Add an interest-bearing savings feature to your fintech app. Users deposit funds, earn yield automatically, and withdraw at any time, with no crypto knowledge required.
This guide shows how to build a yield account feature for a neobank or fintech app. Your users deposit funds, which are allocated to a Morpho lending vault via Trails. The blockchain layer is fully abstracted: your users see a savings balance and an interest rate, nothing else.
User taps "Move to Savings" → Your backend quotes the deposit route via Trails → User authorizes with a single tap (gasless, no fees to manage) → Trails routes funds into the yield vault → Yield accrues; user withdraws any time
Users never interact with a blockchain directly. Wallet creation, gas, and transaction signing all happen in the background via an embedded wallet tied to their account.
A wagmi-compatible embedded wallet provider (Polygon Wallet, Privy, Dynamic, or similar), which powers the invisible signing layer your users never see
Each user gets an embedded wallet created automatically at sign-up, with no crypto onboarding and no seed phrases. This wallet is the signing key for their yield account; users never see or interact with it directly.
import { PrivyProvider } from "@privy-io/react-auth";import { WagmiProvider } from "wagmi";import { QueryClient, QueryClientProvider } from "@tanstack/react-query";import { polygon } from "viem/chains";const queryClient = new QueryClient();export const App = () => ( <PrivyProvider appId={process.env.NEXT_PUBLIC_PRIVY_APP_ID} config={{ defaultChain: polygon, supportedChains: [polygon], embeddedWallets: { createOnLogin: "users-without-wallets", // automatic, no user action required }, }} > <QueryClientProvider client={queryClient}> <WagmiProvider config={wagmiConfig}> <YourApp /> </WagmiProvider> </QueryClientProvider> </PrivyProvider>);
Users log in with email, phone, or SSO via your standard auth flow. Privy silently provisions the wallet in the background:
The yield vault implements ERC-4626, a standard interface for yield-bearing vaults. Use TRAILS_ROUTER_PLACEHOLDER_AMOUNT so Trails fills in the exact routed amount at execution time:
Before moving funds, fetch a quote. This returns the intent object that drives the deposit, including fee breakdowns you can surface in your UI if needed:
The user authorizes the transfer with a single tap. Internally this is a gasless EIP-2612 permit signature, with no approval transaction and no gas fee the user needs to manage. From the user’s perspective it’s indistinguishable from confirming any other in-app action: