Migration Guide
API v2 => API v3
With API v3, the notable changes are:
- A ZeroDev project can now support multiple networks.
- The same RPC can be used for both bundler and paymaster.
Here's what a v3 RPC looks like:
https://rpc.zerodev.app/api/v3/55569f2d-5bbf-43e5-90cc-75d43c26e007/chain/42161
Note that the last part 42161
is the chain ID. Therefore, if you'd like to programmatically use the RPC for different chains, you can do something like:
// replace the prefix with your own RPC prefix
const rpcPrefix = `https://rpc.zerodev.app/api/v3/55569f2d-5bbf-43e5-90cc-75d43c26e007/chain/`
const rpc = rpcPrefix + chain.id
Of course, you can also simply copy the RPC for different chains from the dashboard.
The same RPC can then be used as both the bundler RPC and the paymaster RPC. See the tutorial for an example.
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
-
Remove the
permissionless
package:npm uninstall permissionless
-
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
toENTRYPOINT_ADDRESS_V06
. - If you are launching a new app, set
entryPoint
toENTRYPOINT_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,
},
// ...
})