Skip to content

Migration Guide

(beta) ERC-4337 UserOps => ERC-7683 Intents

This is a beta feature. Only use this if you are in touch with the ZeroDev team.

import { createIntentClient, installIntentExecutor } from "@zerodev/intent"
 
const main = async () => {
  // Construct a Kernel account
  const account = await createKernelAccount(publicClient, {
    plugins: {
      sudo: ecdsaValidator,
    },
    entryPoint,
    kernelVersion,
    initConfig: [installIntentExecutor], 
  })
 
  // Construct a paymaster client
  const zerodevPaymaster = createZeroDevPaymasterClient({ 
    chain, 
    transport: http(PAYMASTER_RPC), 
  }) 
 
  // Construct a Kernel account client
  const kernelClient = createKernelAccountClient({ 
    account, 
    chain, 
    bundlerTransport: http(BUNDLER_RPC), 
    client: publicClient, 
    paymaster: { 
        getPaymasterData(userOperation) { 
            return zerodevPaymaster.sponsorUserOperation({userOperation}) 
        } 
    }, 
 
    userOperation: { 
      estimateFeesPerGas: async ({bundlerClient}) => { 
          return getUserOperationGasPrice(bundlerClient) 
      } 
    } 
  }) 
 
  // Construct an intent client
  const intentClient = createIntentClient({ 
    account: kernelAccount, 
    chain, 
    bundlerTransport: http(bundlerRpc, { timeout }), 
  }) 
 
  // Send a UserOp
  const userOpHash = await kernelClient.sendUserOperation({ 
      callData: await kernelClient.account.encodeCalls([{ 
        // ... 
      }]), 
  }) 
 
  // Send an intent
  const result = await intentClient.sendUserIntent({ 
    calls: [ 
      // ... 
    ], 
  }) 
 
  // Wait for the userop
  await kernelClient.waitForUserOperationReceipt({ 
    hash: userOpHash, 
    timeout: 1000 * 15, 
  }) 
 
  // Wait for the intent
  const receipt = await intentClient.waitForUserIntentExecutionReceipt({ 
    uiHash: result.uiHash, 
  }) 
}

SDK 5.3.x => 5.4.x

In version 5.4.x of the @zerodev/sdk, we've migrated to using viem@2.18.x with native Account Abstraction (AA) modules instead of the permissionless package. This change brings significant updates to types, imports, function signatures, and overall API usage.

This guide will help you migrate your codebase to be compatible with the new version.

Update dependencies

  1. Remove the permissionless package:

    npm uninstall permissionless
  2. Ensure you have viem@^2.21.40 version

Update permissionless Account Abstractions

Replace any imports from permissionless with the equivalent from viem/account-abstraction or @zerodev/sdk if applicable.

Update Type Definitions

Replace EntryPoint Types

import type { EntryPoint } from 'permissionless/types'; 
import type { EntryPointVersion } from 'viem/account-abstraction'; 

Replace UserOperation Types

import type { UserOperation } from 'permissionless/types'; 
import type { UserOperation } from 'viem/account-abstraction'; 

Replaced entryPoint: Address with entryPoint: { address: Address; version: EntryPointVersion}

For createKernelAccount and signerToEcdsaValidator among other plugins, replace the entryPoint parameter as shown:

import { getEntryPoint } from "@zerodev/sdk/constants"; 
createKernelAccount(publicClient, {
  // ...
  entryPoint: ENTRYPOINT_ADDRESS_V07, 
  entryPoint: getEntryPoint("0.7"), 
})
signerToEcdsaValidator(publicClient, {
  // ...
  entryPoint: ENTRYPOINT_ADDRESS_V07, 
  entryPoint: getEntryPoint("0.7"), 
})

Removed entryPoint from createKernelAccountClient

  const kernelClient = createKernelAccountClient({
    entryPoint, 
    // ...
  });

Replaced middleware.sponsorUserOperation from createKernelAccountClient with paymaster.getPaymasterData

  const kernelClient = createKernelAccountClient({
    middleware: { 
		  sponsorUserOperation: paymasterClient.sponsorUserOperation, 
	  }, 
    paymaster: { 
      getPaymasterData(userOperation) { 
        return paymasterClient.sponsorUserOperation({ userOperation }) 
      } 
    } 
    // ...
  });

Added client to createKernelAccountClient

client is now required in createKernelAccountClient.

  const kernelClient = createKernelAccountClient({
    client: publicClient, 
    // ...
  });

Added estimateFeesPerGas to userOperation in createKernelAccountClient

estimateFeesPerGas is now required in userOperation in createKernelAccountClient to estimate the gas price for the user operation. The default gas prices might be too high, so it's recommended to use this function to estimate the gas price.

  const kernelClient = createKernelAccountClient({
    userOperation: { 
      estimateFeesPerGas: async ({bundlerClient}) => { 
        return getUserOperationGasPrice(bundlerClient) 
      } 
    }, 
    // ...
  });

kernelClient.sendUserOperation and kernelClient.signUserOperation now take userOperation properties directly

await kernelClient.sendUserOperation({
  userOperation: { sender, callData, nonce, ...rest }, 
  sender, 
  callData, 
  nonce, 
  ...rest 
});
await kernelClient.signUserOperation({
  userOperation: { sender, callData, nonce, ...rest }, 
  sender, 
  callData, 
  nonce, 
  ...rest 
});

Replaced account.encodeCallData with account.encodeCalls

    await account.encodeCallData( 
      {  
        to: zeroAddress,  
        value: BigInt(0), 
        data: "0x", 
        callType 
      }, 
    ), 
    await account.encodeCalls([ 
      { 
        to: zeroAddress, 
        value: BigInt(0), 
        data: "0x", 
      }, 
    ], callType), 

Replaced kernelClient.sendTransactions with kernelClient.sendTransaction

await kernelClient.sendTransactions({ 
    transactions: [ 
      // ... 
    ], 
}); 
await kernelClient.sendTransaction({ 
    calls: [ 
      // ... 
    ], 
}); 

KernelAccountClient extends bundlerActions by default

For example:

const bundlerClient = kernelClient.extend(bundlerActions(entryPoint)); 
await bundlerClient.waitForUserOperationReceipt({ 
  hash: userOpHash, 
}); 
await kernelClient.waitForUserOperationReceipt({ hash }) 

Merged bundlerClient.sendUserOperation and kernelClient.sendUserOperation

kernelClient.sendUserOperation now prepares the userOperation if needed and directly calls eth_sendUserOperation.

SDK 5.1.x => 5.2.x

Most functions now take an entryPoint param

EntryPoint 0.7 is the most recent update to ERC-4337, but we will still be supporting EntryPoint 0.6.

The SDK will automatically use Kernel v3 for EntryPoint 0.7, and Kernel v2 for EntryPoint 0.6.

You will need to specify an entryPoint parameter to many functions, including:

  • Functions for creating validators, such as signerToEcdsaValidator
  • Functions for creating Kernel accounts, such as createKernelAccount
  • Function for creating Kernel client: createKernelAccountClient

For example:

import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "permissionless"
 
// If migrating a live app
const entryPoint = ENTRYPOINT_ADDRESS_V06
 
// If launching a new app
const entryPoint = ENTRYPOINT_ADDRESS_V07
 
const account = await createKernelAccount(publicClient, {
  plugins: {
    sudo: ecdsaValidator,
  },
  entryPoint,
})
  • If you are migrating a live app that is using EntryPoint 0.6 (Kernel v2), set entryPoint to ENTRYPOINT_ADDRESS_V06.
  • If you are launching a new app, set entryPoint to ENTRYPOINT_ADDRESS_V07.

Replaced transport with bundlerTransport inside createKernelAccountClient

const kernelClient = createKernelAccountClient({
  transport: http(bundlerUrl), 
  bundlerTransport: http(bundlerUrl), 
  // ...
})

Replaced sponsorUserOperation with middleware.sponsorUserOperation

Instead of accepting just a sponsorUserOperation middleware, createSmartAccountClient now accepts a middleware function that can specify a sponsorUserOperation function internally, as well as a gasPrice function.

const kernelClient = createKernelAccountClient({
  sponsorUserOperation: paymasterClient.sponsorUserOperation, 
  middleware: { 
		sponsorUserOperation: paymasterClient.sponsorUserOperation, 
	}, 
  // ...
})