Stablecoin yield, embedded in your product. No wallet setup required.

Sign in with email or a social account, create a non-custodial MPC wallet in one call - no seed phrase, no extension - then deposit USDC into curated vaults, track positions, and withdraw anytime. Built entirely on Dynamic.

@dynamic-labs-sdk/client@dynamic-labs-sdk/react-hooks
  1. Create the client

    Docs

    One Dynamic client per app, created at module scope. The EVM extension registers the networks the embedded wallet supports.

    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 under the hood, so mount QueryClientProvider outside DynamicProvider once - every hook below works anywhere inside.

    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

    The login card on the left runs this flow: send a one-time passcode, verify it. No password, no seed phrase - the session lives in the client.

    components/login.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. Sign in with a social account

    Docs

    Kick off the provider's OAuth flow, then complete it when the user lands back - same session, same embedded wallet.

    components/social-login.tsx
    import {
      useCompleteSocialRedirect,
      useSignInWithSocialRedirect,
    } from "@dynamic-labs-sdk/react-hooks";
    
    const { mutate: signIn } = useSignInWithSocialRedirect();
    const { mutate: completeRedirect } = useCompleteSocialRedirect();
    
    signIn({ provider: "google", redirectUrl: window.location.origin });
    
    // ...and when the provider redirects back:
    completeRedirect({ url: new URL(window.location.href) });
  5. Create the embedded wallet

    Docs

    One call mints a non-custodial embedded (WaaS) wallet for the signed-in user - no extension, no seed phrase; keys never leave Dynamic's MPC. The hook lists every account and re-renders as they're created.

    lib/dynamic/wallets.ts
    import { createWaasWalletAccounts } from "@dynamic-labs-sdk/client/waas";
    import { useGetWalletAccounts } from "@dynamic-labs-sdk/react-hooks";
    
    await createWaasWalletAccounts({ chains: ["EVM"] });
    
    const { data: walletAccounts } = useGetWalletAccounts();
    const walletAccount = walletAccounts?.[0];
  6. Deposit USDC into a vault

    Docs

    Wrap the wallet account in a viem-compatible client and write to the vault contract - the user approves in place; keys never leave Dynamic's MPC.

    lib/vaults/deposit.ts
    import { createWalletClientForWalletAccount } from "@dynamic-labs-sdk/evm/viem";
    import { parseUnits } from "viem";
    
    const walletClient = await createWalletClientForWalletAccount({ walletAccount });
    
    const hash = await walletClient.writeContract({
      address: vault.address,
      abi: vaultAbi,
      functionName: "deposit",
      args: [parseUnits(amount, 6), walletAccount.address],
    });
  7. Track balances and positions

    Docs

    Read USDC and vault-share balances with one hook - the portfolio view renders straight from the query and stays fresh.

    components/positions.tsx
    import { useGetTokenBalances } from "@dynamic-labs-sdk/react-hooks";
    
    const { data: balances } = useGetTokenBalances({ walletAccount });
Earn - Dynamic Demos