> ## 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] Recommended: JavaScript SDK for React Native
>
> While this SDK is still supported, we recommend using newer [JavaScript SDK](https://docs.dynamic.xyz/docs/javascript/reference/react-native-quickstart.md), which is optimized for React Native, but also comes with a host of other benefits.

> [card] 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.

## 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 console](https://console.zerodev.app/create-legacy-project) to configure your project.
* Visit the [Sponsor Gas section of the Dynamic Console](https://console.dynamic.xyz/dashboard/smart-wallets), toggle on Zerodev and add your project IDs.

### Configure Your SDK

> [!NOTE]
>
> The `@dynamic-labs/legacy-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](https://docs.dynamic.xyz/docs/react-native/reference/wallets/viem.md)

# Setup

## Install ZeroDevExtension

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

> [tab] expo
>
> ```bash Shell theme={"system"}
> npx expo install @dynamic-labs/legacy-zerodev-extension
> ```

> [tab] npm
>
> ```bash Shell theme={"system"}
> npm install @dynamic-labs/legacy-zerodev-extension
> ```

> [tab] yarn
>
> ```bash Shell theme={"system"}
> yarn add @dynamic-labs/legacy-zerodev-extension
> ```

> [tab] bun
>
> ```bash Shell theme={"system"}
> bun add @dynamic-labs/legacy-zerodev-extension
> ```

> [tab] pnpm
>
> ```bash Shell theme={"system"}
> pnpm add @dynamic-labs/legacy-zerodev-extension
> ```

> [accordion] 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.

## 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:

> [tab] expo
>
> ```bash Shell theme={"system"}
> npx expo install events
> ```

> [tab] npm
>
> ```bash Shell theme={"system"}
> npm install events
> ```

> [tab] yarn
>
> ```bash Shell theme={"system"}
> yarn add events
> ```

> [tab] bun
>
> ```bash Shell theme={"system"}
> bun add events
> ```

> [tab] pnpm
>
> ```bash Shell theme={"system"}
> pnpm add events
> ```

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

```typescript dynamicClient.ts theme={"system"}
import { createClient } from '@dynamic-labs/legacy-client'
import { ReactNativeExtension } from '@dynamic-labs/legacy-react-native-extension'
import { ViemExtension } from '@dynamic-labs/legacy-viem-extension'
import { ZeroDevExtension } from '@dynamic-labs/legacy-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
}
}
```

> [!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.

> [!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 Console configuration the way the Web SDK does. Pass `bundlerProvider: ZerodevBundlerProvider.Pimlico` (or `Alchemy` / `Gelato`) to `createKernelClient` — otherwise the default may not match your console and sponsorship will fail.

## 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 Console 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)](https://docs.dynamic.xyz/docs/react-native/reference/wallets/account-abstraction.md).

> [!TIP]
>
> Using server wallets? See [Sponsor Gas for Server Wallets (EVM)](https://docs.dynamic.xyz/docs/node/wallets/server-wallets/gas-sponsorship.md). Using Solana embedded wallets? See [SVM Gas Sponsorship](https://docs.dynamic.xyz/docs/react-native/smart-wallets/svm-gas-sponsorship.md).

## 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 Dynamic Console 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 Console](https://console.dynamic.xyz/dashboard)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.