The Basics
- Add Login / Signup
- Chains / Networks
- Wallets
- Users / VC's
- Design
- Onramps
Beyond The Basics
- Headless
- Global Wallets
- Bridge Widget
- Rate Limits
Developer Dashboard
- SDK and API Keys
- Sandbox vs Live
- Analytics
- User Management
- Test Accounts
- Settings
- Admin
- Webhooks
- Configuring Social Providers
Tutorials
- Farcaster
- Telegram
- Features
- Frameworks
- Integrations
- Webhooks
Migrating to Dynamic
- Migrating to Dynamic
- Migration Tutorials
For Wallets & Chains
Legacy: V1 Embedded Wallets
- V1 Embedded Wallets Overview
- Working with environments that have both v1 and v2 embedded wallets
- Transactional MFA
- Headless
Working with environments that have both v1 and v2 embedded wallets
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, or by using the dashboard.
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>
)}
</>
);
Was this page helpful?