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

# Smart Wallets with ZeroDev (Account Abstraction)

When using account abstraction in your project to sponsor gas, batch transactions, or any other account abstraction features, you will likely want to get a ZeroDev kernel client to perform these operations.

You can use the `@dynamic-labs/zerodev-extension` package to create a ZeroDev kernel client for a wallet.

Here is how you can set up and create a kernel client.

<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/viem)
</Note>

# Setup

## Install ZeroDevExtension

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

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

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

  <Tab title="yarn">
    `bash Shell yarn add @dynamic-labs/zerodev-extension `
  </Tab>
</Tabs>

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

/**
 * 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
  }
}
```

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:

<Tabs>
  <Tab title="expo">`bash Shell npx expo install events `</Tab>
  <Tab title="npm">`bash Shell npm install events `</Tab>
  <Tab title="yarn">`bash Shell yarn add events `</Tab>
</Tabs>

## Integrate with your Dynamic client

To include the ZeroDev module in your Dynamic client, you need to extend the client with the ZeroDev extension:

```typescript
import { createClient } from '@dynamic-labs/client'
import { ViemExtension } from '@dynamic-labs/viem-extension'
import { ZeroDevExtension } from '@dynamic-labs/zerodev-extension'

const dynamicClient = createClient({
  environmentId: '',
})
  .extend(ViemExtension())
  .extend(ZeroDevExtension())
```

Now your setup is complete, and you have the ZeroDev module available in your Dynamic client.

# Usage

Now that you have the ZeroDev module in your Dynamic client, you can get the ZeroDev kernel client by using the `dynamicClient.zeroDev.createKernelClient` method. Here is an example:

```typescript
// dynamicClient.ts
const dynamicClient = createClient({
  environmentId: '',
})
  .extend(ViemExtension())
  .extend(ZeroDevExtension())

// getPrimaryWalletKernelClient.ts
const getPrimaryWalletKernelClient = async () => {
  const primaryWallet = dynamicClient.wallets.primaryWallet

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

  const kernelClient = await dynamicClient.zeroDev.createKernelClient({
    wallet: primaryWallet,
  })

  return kernelClient
}
```

# Examples

## Batch transaction example

This example demonstrates how you can use a ZeroDev kernel client to perform a batched transaction:

```typescript
import { encodeFunctionData } from 'viem'

const contractAddress = '0x123'

const contractABI = [
  {
    inputs: [{ internalType: 'address', name: '_to', type: 'address' }],
    name: 'mint',
    outputs: [],
    stateMutability: 'nonpayable',
    type: 'function',
  },
]

const sendBatchedTransactions = async () => {
  const primaryWallet = dynamicClient.wallets.primaryWallet

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

  const kernelClient = await client.zeroDev.createKernelClient({
    wallet: primaryWallet,
  })

  const { account } = kernelClient

  const hash = await kernelClient.sendUserOperation({
    account,
    callData: await account.encodeCalls([
      {
        data: encodeFunctionData({
          abi: contractABI,
          args: [primaryWallet.address],
          functionName: 'mint',
        }),
        to: contractAddress,
        value: BigInt(0),
      },
      {
        data: encodeFunctionData({
          abi: contractABI,
          args: [primaryWallet.address],
          functionName: 'mint',
        }),
        to: contractAddress,
        value: BigInt(0),
      },
    ]),
  })

  return hash
}
```
