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

1

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.

2

Enable in Dynamic

In the EVM section of your Dynamic Dashboard, toggle on MegaEth and click Save.

Now, go to the Account Abstraction section, enable ZeroDev and paste in your ZeroDev project id.

3

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.

  • Wallet level

Choose whether to issue SCWs to all wallets, only to embedded wallets, or use EIP-7702. Choose 7702 here.

  • User level

Choose whether to issues SCWs to all your users (existing included next time they log in), or just new users.

4

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.

  • Show Smart Wallet Only

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.

5

Enable Dynamic-powered embedded wallets + Email

Back in your Dynamic Dashboard, go to the Embedded Wallets section and enable Dynamic-powered embedded wallets.

Lastly, in the Log in & User Profile section, enable Email sign up (optionally, enable social sign up and configure oauth)

6

Install the packages in your app

npm i @dynamic-labs/ethereum @dynamic-labs/ethereum-aa @dynamic-labs/sdk-react-core
7

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>
  );
};
8

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