> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Gas Sponsorship Setup

> Let your users forget about gas fees and focus on your app.

<Card title="Dynamic Gasless Starter">
  Want to see smart wallets in action? Check out our [Dynamic Gasless Starter](https://github.com/dynamic-labs/examples/tree/main/starters/nextjs-evm-gasless-zerodev) - a Next.js demo that showcases gasless transactions with email-based wallet creation and token minting, all without users paying gas fees.
</Card>

## Quickstart

### Prerequisites

* Create a Zerodev account and projects for each network you want to support, as well as a gas policy for each one. Make sure you use [the V1 dashboard](https://dashboard.zerodev.app/create-legacy-project) to configure your project.
* Visit the [Sponsor Gas section of the dashboard](https://app.dynamic.xyz/dashboard/smart-wallets), toggle on Zerodev and add your project IDs.

### Configure Your SDK

<Note>
  The `@dynamic-labs/zerodev-extension` depends on the Viem Extension, so before
  going through this setup, make sure to have the Viem Extension set up and
  working. [Viem Extension Setup](/react-native/reference/wallets/viem)
</Note>

# Setup

## Install ZeroDevExtension

Install the @dynamic-labs/zerodev-extension package:

<Tabs>
  <Tab title="expo">
    ```bash Shell theme={"system"}
    npx expo install @dynamic-labs/zerodev-extension
    ```
  </Tab>

  <Tab title="npm">
    ```bash Shell theme={"system"}
    npm install @dynamic-labs/zerodev-extension
    ```
  </Tab>

  <Tab title="yarn">
    ```bash Shell theme={"system"}
    yarn add @dynamic-labs/zerodev-extension
    ```
  </Tab>

  <Tab title="bun">
    ```bash Shell theme={"system"}
    bun add @dynamic-labs/zerodev-extension
    ```
  </Tab>

  <Tab title="pnpm">
    ```bash Shell theme={"system"}
    pnpm add @dynamic-labs/zerodev-extension
    ```
  </Tab>
</Tabs>

<Accordion title="Resolve File Resolution Error (Optional)">
  When running the ZeroDevExtension in your React Native application, you might encounter an error where Metro cannot resolve the `paymasterClient.js` file. This issue occurs because Metro tries to load `paymasterClient.js`, but the actual file is named `paymasterClient.ts`.

  To fix this, you need to customize Metro's resolver in your `metro.config.js` file to handle TypeScript file extensions properly.

  ### Generate metro.config.js for Expo Projects

  If you don't have a `metro.config.js` file in your project, you can generate one using the following command:

  ```bash Shell theme={"system"}
  npx expo customize metro.config.js
  ```

  ### Customize Metro Resolver

  Add the following code to your `metro.config.js` file to instruct Metro to resolve `.ts` files when it cannot find the corresponding `.js` files:

  ```js metro.config.js theme={"system"}
  const { getDefaultConfig } = require('expo/metro-config')

  const config = getDefaultConfig(__dirname)

  /**
  * Custom resolver to handle ZeroDev imports
  */
  config.resolver.resolveRequest = (context, moduleName, platform) => {
      try {
          return context.resolveRequest(context, moduleName, platform)
      } catch (error) {
          if (moduleName.endsWith('.js')) {
              const tsModuleName = moduleName.replace(/\.js$/, '.ts')
              return context.resolveRequest(context, tsModuleName, platform)
          }
          throw error
      }
  }

  module.exports = config
  ```

  This modification allows Metro to attempt to resolve `.ts` files when it fails to find `.js` files, which fixes the resolution error for the `paymasterClient` file.
</Accordion>

## Events Polyfill

ZeroDevExtension requires a polyfill for the Node.js events module. You can install the [events](https://www.npmjs.com/package/events) polyfill using one of the following commands:

<Tabs>
  <Tab title="expo">
    ```bash Shell theme={"system"}
    npx expo install events
    ```
  </Tab>

  <Tab title="npm">
    ```bash Shell theme={"system"}
    npm install events
    ```
  </Tab>

  <Tab title="yarn">
    ```bash Shell theme={"system"}
    yarn add events
    ```
  </Tab>

  <Tab title="bun">
    ```bash Shell theme={"system"}
    bun add events
    ```
  </Tab>

  <Tab title="pnpm">
    ```bash Shell theme={"system"}
    pnpm add events
    ```
  </Tab>
</Tabs>

Extend the client with the extension, get the kernel client, and then use it to send sponsored transactions. Here is an example:

<CodeGroup>
  ```typescript dynamicClient.ts theme={"system"}
  import { createClient } from '@dynamic-labs/client'
  import { ReactNativeExtension } from '@dynamic-labs/react-native-extension'
  import { ViemExtension } from '@dynamic-labs/viem-extension'
  import { ZeroDevExtension } from '@dynamic-labs/zerodev-extension'
  import 'fast-text-encoding'

  const environmentId = process.env.EXPO_PUBLIC_ENVIRONMENT_ID as string

  if (!environmentId) {
      throw new Error('EXPO_PUBLIC_ENVIRONMENT_ID is required')
  }

  export const client = createClient({
      environmentId,
      appLogoUrl: 'https://demo.dynamic.xyz/favicon-32x32.png',
      appName: 'React Native Stablecoin App',
  })
  .extend(ReactNativeExtension())
  .extend(ViemExtension())
  .extend(ZeroDevExtension())
  ```

  ```typescript getPrimaryWalletKernelClient.ts theme={"system"}
  import { PaymasterTypeEnum } from '@dynamic-labs/ethereum-aa'
  import { ZerodevBundlerProvider } from '@dynamic-labs/sdk-api-core'
  import { mainnet } from 'viem/chains'
  import { client } from './dynamicClient'

  export const getPrimaryWalletKernelClient = async () => {
      const primaryWallet = client.wallets.primary

      if (!primaryWallet) {
          throw new Error('No primary wallet')
      }

      try {
          const kernelClient = await client.zeroDev.createKernelClient({
              wallet: primaryWallet,
              chainId: mainnet.id,
              paymaster: PaymasterTypeEnum.SPONSOR,
              bundlerProvider: ZerodevBundlerProvider.Pimlico,
          })

          return kernelClient
      } catch (error) {
          console.error('Failed to create kernel client:', error)
          throw new Error(
              `Failed to create kernel client: ${error instanceof Error ? error.message : 'Unknown error'}`
          )
      }
  }
  ```

  ```typescript sendSponsoredTransaction.ts theme={"system"}
  import { encodeFunctionData, parseUnits } from 'viem'
  import { getPrimaryWalletKernelClient } from './dynamicClient'

  const sendSponsoredTransaction = async () => {
  const kernelClient = await getPrimaryWalletKernelClient()

  // Example: Transfer USDC tokens
  const USDC_CONTRACT = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' // ETH Mainnet USDC
  const ERC20_ABI = [
      {
      inputs: [
          { internalType: 'address', name: 'to', type: 'address' },
          { internalType: 'uint256', name: 'amount', type: 'uint256' }
      ],
      name: 'transfer',
      outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
      stateMutability: 'nonpayable',
      type: 'function'
      }
  ]

  const recipientAddress = '0x1234567890123456789012345678901234567890'
  const amount = '10' // 10 USDC

  try {
      const usdcAmount = parseUnits(amount, 6)
      const transferData = encodeFunctionData({
      abi: ERC20_ABI,
      functionName: 'transfer',
      args: [recipientAddress as `0x${string}`, usdcAmount],
      })

      const userOpHash = await kernelClient.sendUserOperation({
      callData: await kernelClient.account.encodeCalls([
          {
          to: USDC_CONTRACT as `0x${string}`,
          value: BigInt(0),
          data: transferData,
          },
      ]),
      })

      console.log('User operation sent, hash:', userOpHash)
      console.log('Waiting for transaction confirmation...')

      const { receipt } = await kernelClient.waitForUserOperationReceipt({
      hash: userOpHash,
      })

      const transactionHash = receipt.transactionHash
      console.log('Transaction completed:', transactionHash)

      return transactionHash
  } catch (error) {
      console.error('Failed to send sponsored transaction:', error)
      throw error
  }
  }
  ```
</CodeGroup>

<Note>
  You can also use the `ZerodevBundlerProvider.Alchemy` or `ZerodevBundlerProvider.Gelato` provider to use the Alchemy or Gelato bundler services.

  You can either use `PaymasterTypeEnum.SPONSOR` to sponsor all transactions or `PaymasterTypeEnum.NONE` to send a non-sponsored transaction.
</Note>

<Warning>
  **Two React Native-specific gotchas compared to the Web/React SDK:**

  * **Use `paymaster`, not `withSponsorship`.** Pass `paymaster: PaymasterTypeEnum.SPONSOR` when creating the kernel client. The `withSponsorship: true` option used by the Web/React SDK does not apply here — sponsorship is configured at kernel-client creation time, not per user operation.
  * **Set `bundlerProvider` explicitly.** React Native does not automatically pick up the bundler/paymaster provider from your Dynamic dashboard configuration the way the Web SDK does. Pass `bundlerProvider: ZerodevBundlerProvider.Pimlico` (or `Alchemy` / `Gelato`) to `createKernelClient` — otherwise the default may not match your dashboard and sponsorship will fail.
</Warning>

## Troubleshooting

### `AA20 account not deployed`

If a sponsored user operation fails with an error like:

```
validation reverted: [reason]: AA20 account not deployed
```

the bundler handling the request doesn't support EIP-7702, which is the default mechanism Dynamic uses to enable smart-account features on existing EOAs. React Native does not automatically select a 7702-compatible bundler based on your Dynamic dashboard configuration, so the fix is to set it explicitly when creating the kernel client:

```typescript theme={"system"}
const kernelClient = await client.zeroDev.createKernelClient({
  wallet,
  paymaster: PaymasterTypeEnum.SPONSOR,
  bundlerProvider: ZerodevBundlerProvider.Pimlico,
})
```

Pimlico is the recommended default for EIP-7702 sponsorship on React Native.

## Advanced Usage

For advanced usage (kernel client, batch transactions, sponsored transactions), see [Smart Wallets with ZeroDev (Account Abstraction)](/react-native/reference/wallets/account-abstraction).

<Tip>
  Using server wallets? See [Sponsor Gas for Server Wallets (EVM)](/node/wallets/server-wallets/gas-sponsorship). Using Solana embedded wallets? See [SVM Gas Sponsorship](/react-native/smart-wallets/svm-gas-sponsorship).
</Tip>

## Note on 7702

EIP-7702 is the default for enabling gas sponsorship using Dynamic & Zerodev, but you can switch back to 4337 if you want using the dashboard settings.

### Why use 7702?

EIP-7702 introduces a new transaction type that allows a wallet to delegate execution to an address with a deployed smart account. This means:

* No need to switch or manage multiple accounts and wallets.
* Users retain their existing EOA and gain smart account functionality.
* The transition is smooth and invisible to the end user.

### Common questions

* Do all chains/networks support 7702?
  No, not all chains/networks support 7702. You can see a list of chains/networks that support 7702 [here](https://swiss-knife.xyz/7702beat).

* When does the delegation (authorization) signing happen?
  The delegation authorization is signed automatically behind the scenes on the first transaction. If a paymaster is used, the paymaster will pay for the transaction.

* How long does the delegation remain active?
  The delegation stays active until the user delegates to a new address.

* How does this work for existing EOAs (e.g. MetaMask)?
  At the moment, delegation is a feature exclusive to embedded wallets. That's because we need to sign the authorization in a very specific way that requires access to the private key. From what we've heard, external wallets like MetaMask are unlikely to expose the `signAuthorization` method, making it unclear how (or if) this flow will work with them.

### Resources

* [EIP-7702 Specification](https://eips.ethereum.org/EIPS/eip-7702)
* [ZeroDev Documentation](https://docs.zerodev.app/)
* [Ithaca Odyssey Testnet](https://www.ithaca.xyz/updates/odyssey)
* [Dynamic Dashboard](https://app.dynamic.xyz/dashboard)
