Put idle balances to work. Earn in the same asset.

Give users yield without leaving your app. They deposit USDC into a curated vault straight from their embedded wallet, watch the balance grow in the same asset, and withdraw any time - no DeFi background required, built entirely on Dynamic.

  1. Create the client

    Docs

    One Dynamic client per app, created at module scope. Earn is EVM-only, so the EVM extension is the only one this demo registers.

    lib/dynamic/client.ts
    import { createDynamicClient } from "@dynamic-labs-sdk/client";
    import { addEvmExtension } from "@dynamic-labs-sdk/evm";
    
    export const client = createDynamicClient({
      environmentId: process.env.NEXT_PUBLIC_DYNAMIC_ENVIRONMENT_ID!,
    });
    addEvmExtension(client);
  2. Wrap your app for hooks

    Docs

    The react-hooks package reads the client from context and uses TanStack Query underneath, so mount QueryClientProvider outside DynamicProvider once.

    app/providers.tsx
    import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
    import { DynamicProvider } from "@dynamic-labs-sdk/react-hooks";
    import { client } from "@/lib/dynamic/client";
    
    const queryClient = new QueryClient();
    
    export function Providers({ children }: { children: React.ReactNode }) {
      return (
        <QueryClientProvider client={queryClient}>
          <DynamicProvider client={client}>{children}</DynamicProvider>
        </QueryClientProvider>
      );
    }
  3. Sign in with an email code

    Docs

    Send a one-time passcode and verify it. The embedded wallet that signs every deposit belongs to the user this creates.

    components/screens/auth-screen.tsx
    import { useSendEmailOTP, useVerifyOTP } from "@dynamic-labs-sdk/react-hooks";
    
    const { mutate: sendOtp, data: otpVerification } = useSendEmailOTP();
    const { mutate: verifyOtp } = useVerifyOTP();
    
    sendOtp({ email });
    // User types the 6-digit code from their inbox:
    verifyOtp({ otp: code, otpVerification });
  4. List the vaults

    Docs

    Every vault the environment can see, each with a best-effort live netApy and tvlUsd. This is the first call after sign-in - and the only place a vaultId should ever come from.

    hooks/use-vaults.ts
    import { listYieldVaults } from "@dynamic-labs-sdk/client";
    
    const vaults = await listYieldVaults();
    for (const vault of vaults) {
      console.log(vault.vaultId, vault.curator, vault.assetSymbol, vault.netApy);
    }
Earn - Dynamic Demos