Summary

This guide will show you how to create an embedded wallet for a user, then help them secure it once they are ready to make their first transaction using One Time Codes, and optionally adding a passkey.

When using one time codes, we’ll also create a session for that user so they can transact for a further period of time without any extra steps. for more information on the differences between passkeys and one codes, please see this guide.

We will assume that the user has already signed up. If you need to handle the signup part headlessly, we recommend reading the headless email guide.

Here are the steps we need to follow:

  1. Check for active session
  2. Create the embedded wallet
  3. Secure the wallet pre-transaction
  4. Create a session for the user

For all of these steps we will need just one hook - useEmbeddedWallet.

Pre-requisites

  • You have already set up the Dynamic SDK and wrapped your app with the DynamicContextProvider.
  • You have enabled Dynamic embedded wallets and toggled “Manual Mode” on in the configuration.
  • You do not have the DynamicWidget component in your application code.

Session Notes

For security reasons, sessions are held in an iframe which gets deleted after page refresh and user log out.

To overcome sending users one-time codes each time they don’t have an active session, we’re able to restore it and developers should always try to do it before starting the one-time codes flow.

You’ll see this in the code examples below, where we check for an active session before sending the one-time code i.e.

useEffect(() => {
    const startSession = () => {
        try {
            if (isSessionActive) return;
            createOrRestoreSession();
        } catch (err) {
        return;
        };
    };
    startSession();
}, []);

Full code examples

You must add the following to your root CSS file to hide the iframe

iframe[id*="dyn-secure-enclave-element-id"] {
  display: none;
}
import { useEmbeddedWallet, useDynamicContext } from “@dynamic-labs/sdk-react-core”

// component declaration and all other logic you might need
const { createEmbeddedWallet,
    createOrRestoreSession,
    isSessionActive,
    sendOneTimeCode,
    userHasEmbeddedWallet } = useEmbeddedWallet();

const oneTimeCodeSent = useRef(false);

useEffect(() => {
   const startSession = () => {
    try {
        if (isSessionActive) return;
        createOrRestoreSession();
    } catch (err) {
    return;
    }
};

    startSession();
}, []);

const onSendOneTimeCodeHandler = async () => {

    if(!userHasEmbeddedWallet()) await createEmbeddedWallet();

    if(!isSessionActive) {
    try {
        await sendOneTimeCode();
        oneTimeCodeSent.current = true;
        return;
    } catch(e) {
        console.error(e)
    }
    } else return;
}

const onCreateSessionHandler: FormEventHandler<HTMLFormElement> = async (event) => {
    try {
    event.stopPropagation();
    event.preventDefault();

    if (!primaryWallet || !userHasEmbeddedWallet()) return;

    const otc = event.currentTarget.otc.value;

    await createOrRestoreSession({oneTimeCode: otc})
        .then((result) => setResult(result))
        .catch((error) => setResult(JSON.stringify(error, null, 2)));
    } catch (err) {
    logger.error(err);
    }
};

return (
<>
    {!isSessionActive && (
        <div>
            {!oneTimeCodeSent.current && <button onClick={onSendOneTimeCodeHandler}>Start session</button>}
            {oneTimeCodeSent.current && (
            <form onSubmit={onCreateSessionHandler} className='create-session-method'>
            <p>
                Enter one-time code sent to email to create a session
            </p>

            <input required name='otc' type='text' placeholder='One-time code' />
            <br />
            <button type='submit'>Create session</button>

            </form>
            )}
        <div>
    )}
</>
)