Enabling MegaEth
Dynamic supports MegaEth from Day 0, simply enable it in the EVM networks section of the dashboard and you’re good to go! We also support 7702 by default on MegaEth in partnership with Zerodev, learn how to enable that below.
Setup MegaEth for 7702
ZeroDev Account
Sign up for a free account at https://dashboard.zerodev.app/ and create a project, configure your project name and network (please use MegaEth for this example) and copy your new ZeroDev project ID.
Choose who gets a SCW
On the same configuration page as the step above, you’ll see there are two different types of configuration for issuing smart contract wallets (SCWs) in Dynamic - the wallet level and the user level.
Choose whether to issue SCWs to all wallets, only to embedded wallets, or use EIP-7702. Choose 7702 here.
Choose whether to issues SCWs to all your users (existing included next time they log in), or just new users.
Choose if your users see both the signer and smart wallet
On the same configuration page as the 2 steps above, you’ll see there is a setting for how the Dynamic SDK treats the signer and the smart wallet - only the smart wallet or both the smart wallet and signer.
Only allows you to interact with the smart wallet directly.
- Show Smart Wallet & Signer
Treats the smart wallet and signer as separate wallets which you can switch between.
Enable Dynamic-powered embedded wallets + Email
Install the packages in your app
npm i @dynamic-labs/ethereum @dynamic-labs/ethereum-aa @dynamic-labs/sdk-react-core
Initialize the Dynamic Context Provider
Pass ZeroDevSmartWalletConnectors
along with EthereumWalletConnectors to the WalletConnectors Array of your context provider.
import { DynamicContextProvider, DynamicWidget } from '@dynamic-labs/sdk-react-core';
import { EthereumWalletConnectors } from '@dynamic-labs/ethereum';
import { ZeroDevSmartWalletConnectors } from '@dynamic-labs/ethereum-aa';
const App = () => {
return (
<DynamicContextProvider
settings={{
environmentId: 'XXXX',
walletConnectors: [
EthereumWalletConnectors,
ZeroDevSmartWalletConnectors
]
}}
>
<DynamicWidget />
</DynamicContextProvider>
);
};
Kernel Interaction
Currently to interact with the wallet, you will need to interact directly with the kernel, we will do this in a new component:
const Sign7702Transaction = () => {
import { isZeroDevConnector } from '@dynamic-labs/ethereum-aa';
import { primaryWallet } from '@dynamic-labs/sdk-react-core';
if(!primaryWallet) {
console.error('No wallet found');
return null;
}
if(!isZeroDevConnector(primaryWallet.connector)) {
console.error('Not a ZeroDev connector');
return null;
}
const params = {
withSponsorship: true,
}
const kernelClient = primaryWallet.connector?.getAccountAbstractionProvider(params);
if(!kernelClient) {
console.error('No kernel client found');
return null;
}
const userOpHash = await kernelClient.sendUserOperation({
callData: await kernelClient.account.encodeCalls([
{
data: '0x',
to: zeroAddress,
value: BigInt(0),
},
{
data: '0x',
to: zeroAddress,
value: BigInt(0),
},
]),
});
}
Full Example
import { EthereumWalletConnectors, } from '@dynamic-labs/ethereum';
import { DynamicContextProvider, DynamicWidget, useUserWallets} from '@dynamic-labs/sdk-react-core';
import { ZeroDevSmartWalletConnectors, isZeroDevConnector } from '@dynamic-labs/ethereum-aa';
import { zeroAddress } from 'viem';
import { useState } from 'react';
function App() {
return (
<DynamicContextProvider
settings={{
environmentId: '54a5040b-cdd2-47f4-ac72-8e37dd8db1b6',
walletConnectors: [
EthereumWalletConnectors,
ZeroDevSmartWalletConnectors
]
}}
>
<DynamicWidget />
<Sign7702Transaction/>
</DynamicContextProvider>
)
}
function Sign7702Transaction() {
const { primaryWallet } = useDynamicContext();
const [error, setError] = useState(null);
const [txHash, setTxHash] = useState(null);
const [isSendingTransaction, setIsSendingTransaction] = useState(false);
if (!primaryWallet) {
return null;
}
const handleSendTransaction = async () => {
const connector = primaryWallet.connector;
if (!connector) {
setError('No connector found');
return;
}
if (!isZeroDevConnector(connector)) {
setError('Connector is not a ZeroDev connector');
return;
}
const params = {
withSponsorship: true,
};
const kernelClient = connector.getAccountAbstractionProvider(params);
if (!kernelClient) {
setError('No kernel client found');
return;
}
try {
setIsSendingTransaction(true);
const userOpHash = await kernelClient.sendUserOperation({
callData: await kernelClient.account.encodeCalls([
{
data: '0x',
to: zeroAddress,
value: BigInt(0),
},
{
data: '0x',
to: zeroAddress,
value: BigInt(0),
},
]),
});
const { receipt } = await kernelClient.waitForUserOperationReceipt({
hash: userOpHash,
});
setTxHash(receipt.transactionHash);
setError(null);
} catch (err) {
setError((err).message || 'Error sending transaction');
} finally {
setIsSendingTransaction(false);
}
};
return (
<>
<div className='grid gap-12'>
{primaryWallet && (
<div className='grid gap-4'>
<Button
onClick={handleSendTransaction}
disabled={!primaryWallet || isSendingTransaction}
loading={isSendingTransaction}
className='w-full'
>
Send Transaction
</Button>
{txHash && (
<div className='p-6 bg-gray-50 rounded-lg mt-6'>
Transaction Hash:
<a
href={`https://odyssey-explorer.ithaca.xyz/tx/${txHash}`}
target='_blank'
rel='noopener noreferrer'
className='block bg-gray-100 p-3 rounded hover:bg-gray-200 transition-colors text-blue-600 underline flex items-center gap-2'
>
{`${txHash.slice(0, 6)}...${txHash.slice(-4)}`}
<span className='text-gray-500 text-sm'>
(View on Explorer)
</span>
</a>
</div>
)}
</div>
)}
{error && (
<Typography variant='paragraph-3' className='text-red-500 mt-6'>
Error: {error}
</Typography>
)}
</div>
</>
);
}
export default App