Skip to main content
Dynamic sponsors EVM gas natively for embedded wallets. If you previously enabled gasless transactions through the ZeroDev integration (EIP-7702), this guide moves you to native sponsorship and removes ZeroDev.
This guide covers migrating from ZeroDev EIP-7702 gasless to native sponsorship. Both keep the user on their embedded EOA at the same address — what changes is the connector/extension, the send API, and the on-chain 7702 delegation target. Migrating from ERC-4337 smart-contract accounts is not covered here.

What changes

ZeroDev (EIP-7702)Native gas sponsorship
In codeZeroDevSmartWalletConnectors (React) / ZeroDevExtension (React Native)removed
Sponsored sendvia ZeroDevReact: sendSponsoredTransaction (@dynamic-labs-sdk/evm)
React Native: client.ethereumGasless.send
7702 delegate (on-chain)ZeroDev Kernel implementationDynamic/Fireblocks: 0x0000Fb7702036ff9f76044a501ac1aA74cbab16b
The user’s address does not change — both paths delegate the same embedded EOA via EIP-7702. The delegation target changes, which is how you verify the migration on-chain.
Migrations can touch users, addresses, and assets. When in doubt, talk to us.

Before you start (dashboard)

These apply to both React and React Native and can’t be done in code.
1

Enable native EVM gas sponsorship

In your environment, go to Sponsor Gas → Dynamic Native Sponsorship and turn on Sponsor Network Fees (EVM). After changing the dashboard, reload so the SDK picks it up. From the SDK you can gate your UI on the enabled check — React: isEvmGasSponsorshipEnabled() from @dynamic-labs-sdk/evm; React Native: await client.ethereumGasless.isEnabled().
2

If your app is headless, disable the transaction confirmation UI

If you render Dynamic’s UI components, skip this. If your app is headless (you don’t render DynamicWidget / the Dynamic views), turn off the embedded-wallet transaction confirmation UI for the environment.
With the confirmation UI enabled but no Dynamic UI rendered, sends wait on a confirmation modal that never appears and hang indefinitely.

Migrate your code

Keep ZeroDev wired up until native sponsored sends work — remove it last.
Using @dynamic-labs/sdk-react-core. Today you have ZeroDevSmartWalletConnectors from @dynamic-labs/ethereum-aa in your walletConnectors, and send via primaryWallet.connector.getAccountAbstractionProvider({ withSponsorship: true }).Install @dynamic-labs-sdk/evm and @dynamic-labs-sdk/client, pinned to the exact @dynamic-labs-sdk/client version your @dynamic-labs/sdk-react-core already resolves (check node_modules/@dynamic-labs/sdk-react-core/node_modules/@dynamic-labs-sdk/client/package.json, or your lockfile) so the package manager keeps a single client instance.
1

Register the EVM wallet provider

@dynamic-labs/sdk-react-core builds the underlying @dynamic-labs-sdk/client but drives embedded wallets through the legacy connector system — it never registers a new-SDK wallet provider. Register the EVM WaaS provider yourself, once, after the SDK loads, by calling addEvmExtension() from @dynamic-labs-sdk/evm. It binds to the client DynamicContextProvider already created.
import { useEffect } from 'react';
import { useDynamicContext } from '@dynamic-labs/sdk-react-core';
import { addEvmExtension } from '@dynamic-labs-sdk/evm';

export const RegisterEvmGasless = () => {
  const { sdkHasLoaded } = useDynamicContext();

  useEffect(() => {
    // Registers the EVM WaaS wallet provider on the provider's default client.
    if (sdkHasLoaded) addEvmExtension();
  }, [sdkHasLoaded]);

  return null;
};
Without this, sponsored sends throw No wallet provider found with key: dynamicwaasevm:embeddedWallet — the wallet account exists, but the provider that signs for it was never registered.
2

Send sponsored transactions

Use sendSponsoredTransaction from @dynamic-labs-sdk/evm with the EVM wallet account. Read the account imperatively with getWalletAccounts() from @dynamic-labs-sdk/client — it resolves the same client the provider registered.
import { getWalletAccounts } from '@dynamic-labs-sdk/client';
import {
  sendSponsoredTransaction,
  type EvmWalletAccount,
} from '@dynamic-labs-sdk/evm';

export const sendSponsored = async ({
  to,
  value = 0n,
  data = '0x',
}: {
  to: `0x${string}`;
  value?: bigint;
  data?: `0x${string}`;
}) => {
  const walletAccount = getWalletAccounts().find(
    (account): account is EvmWalletAccount => account.chain === 'EVM',
  );
  if (!walletAccount) throw new Error('No EVM wallet account');

  const { transactionHash } = await sendSponsoredTransaction({
    walletAccount,
    calls: [{ target: to, value, data }],
  });

  return transactionHash;
};
EIP-7702 delegation is activated automatically on the first sponsored send.
Don’t reach for useWalletAccounts() from @dynamic-labs-sdk/react-hooks in a sdk-react-core app: those hooks read the client from the new-SDK <DynamicProvider> context, which <DynamicContextProvider> never mounts, so they throw MissingProviderError. Use the imperative functions above.
3

Remove the ZeroDev connector

Once your sends go through native sponsorship, remove ZeroDevSmartWalletConnectors from your walletConnectors, and disable ZeroDev in the dashboard.
- import { ZeroDevSmartWalletConnectors } from '@dynamic-labs/ethereum-aa';

  <DynamicContextProvider
    settings={{
      environmentId,
-     walletConnectors: [EthereumWalletConnectors, ZeroDevSmartWalletConnectors],
+     walletConnectors: [EthereumWalletConnectors],
    }}
  >
Order matters. Ship the SDK version that tolerates connector removal and disable ZeroDev in the dashboard before deleting the connector from code — otherwise clients can hit a ConnectorSetupError (connector removed while still enabled) or a missing-project-id error (disabled in dashboard while connector still in code) during the rollout window.
4

Verify on-chain

Confirm a sponsored transaction succeeds from the embedded EOA with no funds, then check the account’s EIP-7702 delegation now points at Dynamic’s implementation rather than the ZeroDev Kernel:
import { is7702DelegationActive } from '@dynamic-labs-sdk/evm';

// walletAccount from getWalletAccounts() — see the send step.
const delegated = await is7702DelegationActive({ walletAccount });
// Resolves true once delegated to the Dynamic/Fireblocks implementation:
// 0x0000Fb7702036ff9f76044a501ac1aA74cbab16b

Gotchas

  • The user’s address doesn’t change. Both ZeroDev and native sponsorship delegate the same embedded EOA via EIP-7702 — only the delegation target moves. Once a wallet has re-delegated to Dynamic on its first native send, don’t route that user back through a ZeroDev send.
  • Headless apps must disable the confirmation UI, or sends hang on an unrendered modal.
  • React: register the EVM provider with addEvmExtension() once after the SDK loads, or sends throw No wallet provider found with key: dynamicwaasevm:embeddedWallet. Don’t use the @dynamic-labs-sdk/react-hooks hooks in a sdk-react-core app — they need the new-SDK <DynamicProvider> and throw MissingProviderError. Read the account with getWalletAccounts().
Prefer to automate the code changes? Use the ZeroDev → native gasless migration skill with your AI coding assistant.