This article is for developers who are working with environments that have both v1 and v2 embedded wallets. You can check the version of the wallet by checking the version parameter in the verified credential of the wallet.

Overview

Key difference between V1 and v2 embedded wallets

v1 embedded wallets require transaction MFA. This means that before a transaction can be signed by the end user, they must perform an additional MFA step. Currently we support Passkeys and One Time Codes for transaction MFA.

v2 embedded wallets allow transaction MFA to be configured as optional. This means that after an end user logs in/ signs up and obtains a valid JWT, they will be able to perform actions with their embedded wallet without any additional MFA steps.

Currently adding transaction MFA is disabled for v2 embedded wallets. Configuring this will be possible in a future update.

Example of signing a transaction using v1 embedded wallets

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

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


const oneTimeCodeSent = useRef(false);

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

    startSession();
}, []);

const onSendOneTimeCodeHandler = async () => {
    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);
    }
};

const handleTransaction = async () => {
    if(!isEthereumWallet(primaryWallet)) return;

    const provider = await primaryWallet.getWalletClient();

    const transaction = {
      account: primaryWallet.address as Hex,
      chain: getChain(await provider.getChainId()),
      to: address as Hex,
      value: amount ? parseEther(amount) : undefined,
    };

    const hash = await provider.sendTransaction(transaction);

    const client =
      await primaryWallet.getPublicClient();

    const { transactionHash } = await client.getTransactionReceipt({
      hash,
    });
    console.log('Transaction: ' + transactionHash);
}

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>
    )}
    {isSessionActive && (
        <div>
            <button type='submit' onClick={handleTransaction}>Send transaction</button>
        <div>
    )}
</>
)

Example of signing a transaction using v2 embedded wallets

    import { useEmbeddedWallet, useDynamicContext } from “@dynamic-labs/sdk-react-core”

    // component declaration and all other logic you might need
    const { primaryWallet } = useDynamicContext();

    const handleTransaction = async () => {
        if (!isEthereumWallet(primaryWallet)) return;

        const provider = await primaryWallet.getWalletClient();

        const transaction = {
          account: primaryWallet.address as Hex,
          chain: getChain(await provider.getChainId()),
          to: address as Hex,
          value: amount ? parseEther(amount) : undefined,
        };

        const hash = await provider.sendTransaction(transaction);

        const client =
          await primaryWallet.getPublicClient();

        const { transactionHash } = await client.getTransactionReceipt({
          hash,
        });
        console.log('Transaction: ' + transactionHash);
    }

    return (
        <>
            <button type='submit' onClick={handleTransaction}>Send transaction</button>
        </>
    );

Example of signing a transaction if your environment has both v1 and v2 embedded wallets

Note: getWalletVersion is only available in 3.0.0-alpha.30 and above

 import { useEmbeddedWallet, useDynamicContext } from “@dynamic-labs/sdk-react-core”

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


    const oneTimeCodeSent = useRef(false);

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

            startSession();
        }
    }, [version]);

    const onSendOneTimeCodeHandler = async () => {
        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);
        }
    };

    const handleTransaction = async () => {
        if (!isEthereumWallet(primaryWallet)) return;

        const provider = await primaryWallet.getWalletClient();

        const transaction = {
          account: primaryWallet.address as Hex,
          chain: getChain(await provider.getChainId()),
          to: address as Hex,
          value: amount ? parseEther(amount) : undefined,
        };

        const hash = await provider.sendTransaction(transaction);

        const client =
          await primaryWallet.getPublicClient();

        const { transactionHash } = await client.getTransactionReceipt({
          hash,
        });
        console.log('Transaction: ' + transactionHash);
    }
    return (
        <>
            {!isSessionActive && version === EmbeddedWalletVersion.V1 && (
                <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>
            )}
            {isSessionActive || version === EmbeddedWalletVersion.V2  (
                <div>
                    <button type='submit' onClick={handleTransaction}>Send transaction</button>
                <div>
            )}
        </>
    );