Summary

This guide will show you how to create an embedded wallet for a user, and use it to sign a transaction.

Pre-requisites

  • You have already set up the Dynamic SDK and wrapped your app with the DynamicContextProvider.
  • You have enabled Dynamic-powered embedded wallets and toggled off “Create on Sign up” on in the configuration. If you have “Create on Sign up” turned on, the embedded wallet will be created for the user automatically on sign up. You can skip steps 1 and 2 in the section below.
  • You do not have the DynamicWidget component in your application code.

Create embdded wallet

  1. Import useEmbeddedWallet and access the variable to check if user has an embedded wallet already, as well as the method to create our new wallet and a variable to hold our new wallet ID.
import { useState } from 'react';
import { useEmbeddedWallet } from '@dynamic-labs/sdk-react-core';


const { userHasEmbeddedWallet, createEmbeddedWallet } = useEmbeddedWallet();
const [walletId, setWalletId] = useState(null);
  1. As long as the user doesn’t have one already, create one for them.
async function handleEmbeddedWalletCreation() {
    if(!userHasEmbeddedWallet) {
        const walletId = await createEmbeddedWallet();
        setWalletId(walletId);
    }
    return;
}

Note that you can still generate a wallet if the user has one already, please read about embedded wallet accounts if that’s something you’d like to do. For this guide we’ll assume we want to generate an initial wallet.

Access the wallet

This can take two forms, if it’s the only wallet a user has, then we can access primaryWallet from useDynamicContext and that is guaranteed to be the embedded wallet:

import { useDynamicContext } from '@dynamic-labs/sdk-react-core';

const { primaryWallet } = useDynamicContext();

If however the user signed up with a branded wallet, then they will have multiple. In this case we can check via the useUserWallets hook and use the walletId returned by the create wallet call:

import { useUserWallets } from '@dynamic-labs/sdk-react-core';

const userWallets = useUserWallets();

On the connector interface for each wallet, you’ll find an isEmbeddedWallet boolean which we can use:

const embeddedWallet = userWallets.find(wallet => wallet.id === walletId);

An alternative to blend both approaches would be to make embedded wallet the primary one using useSwitchWallet:

import { useSwitchWallet } from '@dynamic-labs/sdk-react-core';

const switchWallet = useSwitchWallet();

switchWallet(walletId);

Build & Send Transaction

Creating a transaction for the embedded wallet to sign follows exactly the same steps as our other examples here. We’ll assume you accessed the wallet via primaryWallet.

Once the sendTransaction call is triggered, there can be an optional transaction confirmation UI step. You can either keep the confirmation screen or disable it entirely - read morehere.

import { FormEventHandler, useState } from "react";

import { parseEther } from "viem";

import { useDynamicContext } from "@dynamic-labs/sdk-react-core";
import { isEthereumWallet } from "@dynamic-labs/ethereum";

const SendTransaction = () => {
  const { primaryWallet } = useDynamicContext();

  const [txnHash, setTxnHash] = useState("");

  if (!primaryWallet || !isEthereumWallet(primaryWallet)) return null;

  const onSubmit: FormEventHandler<HTMLFormElement> = async (event) => {
    event.preventDefault();

    const formData = new FormData(event.currentTarget);

    const address = formData.get("address") as string;
    const amount = formData.get("amount") as string;

    const publicClient = await primaryWallet.getPublicClient();
    const walletClient = await primaryWallet.getWalletClient();

    const transaction = {
      to: address,
      value: amount ? parseEther(amount) : undefined,
    };

    const hash = await walletClient.sendTransaction(transaction);
    setTxnHash(hash);

    const receipt = await publicClient.getTransactionReceipt({
      hash,
    });

    console.log(receipt);
  };

  return (
    <form onSubmit={onSubmit}>
      <p>Send to ETH address</p>
      <input name="address" type="text" required placeholder="Address" />
      <input name="amount" type="text" required placeholder="0.05" />
      <button type="submit">Send</button>
      <span data-testid="transaction-section-result-hash">{txnHash}</span>
    </form>
  );
};