Migration Guide
0.2.0
Using viem 2.20.0
Viem released their own version of account abstraction primitives since version 2.18.0
.
Since permissionless.js has viem as a peer dependency and are heavily inspired by viem, we will be updating to use the native account abstraction primitives provided by viem.
For full documentation on viem's account abstraction primitives, please refer to the viem documentation.
Deprecated createBundlerClient
Viem has default createBundlerClient so we have deprecated the permissionless.js bundler client. This means we have also deprecated the following bundler actions:
chainId
estimateUserOperationGas
getUserOperationByHash
getUserOperationReceipt
sendUserOperation
supportedEntryPoints
waitForUserOperationReceipt
Deprecated getEntryPointVersion
This is no more needed as all the permissionless versions now accepts entryPoint version explicitly.
Deprecated getUserOperationHash
This is part of viem/account-abstraction
and now can be directly imported from viem
.
Deprecated signUserOperationHashWithECDSA
Deprecated experimental 7677
Changed signerToBiconomySmartAccount
to toBiconomySmartAccount
import { toBiconomySmartAccount } from "permissionless/accounts"
import { publicClient } from "./publicClient"
import { entryPoint06Address } from "viem/account-abstraction"
import { privateKeyToAccount, generatePrivateKey } from "viem/accounts"
const biconomyAccount = await signerToBiconomySmartAccount(client {
signer: privateKeyToAccount(generatePrivateKey()),
entryPoint: ENTRYPOINT_ADDRESS_V06,
...rest
})
const biconomyAccount = await toBiconomySmartAccount({
client: publicClient,
owners: [privateKeyToAccount(generatePrivateKey())],
entryPoint: {
address: entryPoint06Address,
version: "0.6",
}
...rest
})
Changed signerToEcdsaKernelSmartAccount
to toEcdsaKernelSmartAccount
import { toEcdsaKernelSmartAccount } from "permissionless/accounts"
import { publicClient } from "./publicClient"
import { entryPoint07Address } from "viem/account-abstraction"
import { privateKeyToAccount, generatePrivateKey } from "viem/accounts"
const kernelAccount = await signerToEcdsaKernelSmartAccount(client {
signer: privateKeyToAccount(generatePrivateKey()),
entryPoint: ENTRYPOINT_ADDRESS_V06,
...rest
})
const kernelAccount = await toEcdsaKernelSmartAccount({
client: publicClient,
owners: [privateKeyToAccount(generatePrivateKey())],
entryPoint: { // optional, defaults to 0.7
address: entryPoint07Address,
version: "0.7",
},
...rest
})
Changed signerToLightSmartAccount
to toLightSmartAccount
import { toLightSmartAccount } from "permissionless/accounts"
import { publicClient } from "./publicClient"
import { entryPoint06Address } from "viem/account-abstraction"
import { privateKeyToAccount, generatePrivateKey } from "viem/accounts"
const kernelAccount = await signerToLightSmartAccount(client {
signer: privateKeyToAccount(generatePrivateKey()),
entryPoint: ENTRYPOINT_ADDRESS_V06,
lightAccountVersion: "1.1.0"
...rest
})
const kernelAccount = await toLightSmartAccount({
client: publicClient,
owners: [privateKeyToAccount(generatePrivateKey())],
entryPoint: { // optional, defaults to 0.7
address: entryPoint06Address,
version: "0.6",
},
version: "1.1.0" // optional, defaults to "2.0.0"
...rest
})
Changed signerToSafeSmartAccount
to toSafeSmartAccount
import { toSafeSmartAccount } from "permissionless/accounts"
import { publicClient } from "./publicClient"
import { entryPoint07Address } from "viem/account-abstraction"
import { privateKeyToAccount, generatePrivateKey } from "viem/accounts"
const safeAccount = await signerToSafeSmartAccount(client {
signer: privateKeyToAccount(generatePrivateKey()),
entryPoint: ENTRYPOINT_ADDRESS_V07,
safeVersion: "1.4.1"
...rest
})
const safeAccount = await toSafeSmartAccount({
client: publicClient,
owners: [privateKeyToAccount(generatePrivateKey())],
entryPoint: { // optional, defaults to 0.7
address: entryPoint07Address,
version: "0.7",
},
version: "1.4.1"
...rest
})
Changed signerToSimpleSmartAccount
to toSimpleSmartAccount
import { toSimpleSmartAccount } from "permissionless/accounts"
import { publicClient } from "./publicClient"
import { entryPoint07Address } from "viem/account-abstraction"
import { privateKeyToAccount, generatePrivateKey } from "viem/accounts"
const simpleAccount = await signerToSimpleSmartAccount(client {
signer: privateKeyToAccount(generatePrivateKey()),
entryPoint: ENTRYPOINT_ADDRESS_V06,
...rest
})
const simpleAccount = await toSimpleSmartAccount({
client: publicClient,
owner: privateKeyToAccount(generatePrivateKey()),
entryPoint: { // optional, defaults to 0.7
address: entryPoint07Address,
version: "0.7",
},
...rest
})
Changed signerToTrustSmartAccount
to toTrustSmartAccount
import { toTrustSmartAccount } from "permissionless/accounts"
import { publicClient } from "./publicClient"
import { entryPoint06Address } from "viem/account-abstraction"
import { privateKeyToAccount, generatePrivateKey } from "viem/accounts"
const trustAccount = await signerToTrustSmartAccount(client {
signer: privateKeyToAccount(generatePrivateKey()),
entryPoint: ENTRYPOINT_ADDRESS_V06,
...rest
})
const trustAccount = await toTrustSmartAccount({
client: publicClient,
owner: privateKeyToAccount(generatePrivateKey()),
entryPoint: {
address: entryPoint06Address,
version: "0.6",
},
...rest
})
Deprecated `privateKeyTo<account-name>SmartAccount
All the private key to account conversion functions are now deprecated. You can use to<account-name>SmartAccount
to create a smart account instead.
Example:
import { toSafeSmartAccount } from "permissionless/accounts"
import { publicClient } from "./publicClient"
import { entryPoint07Address } from "viem/account-abstraction"
import { privateKeyToAccount } from "viem/accounts"
const safeAccount = await toSafeSmartAccount({
client: publicClient,
owners: [privateKeyToAccount(privateKey)],
entryPoint: {
address: entryPoint07Address,
version: "0.7"
}, // global entrypoint
version: "1.4.1",
})
Merged createPimlicoPaymasterClient
and createPimlicoBundlerClient
to createPimlicoClient
import { http } from "viem";
import { entryPoint07Address } from "viem/account-abstraction"
import { createPimlicoClient } from "permissionless/clients/pimlico"
const pimlicoUrl = `https://api.pimlico.io/v2/sepolia/rpc?apikey=<PIMLICO_API_KEY>`
const pimlicoPaymasterClient = createPimlicoPaymasterClient({
chain: foundry,
transport: http(paymasterRpc),
entryPoint: ENTRYPOINT_ADDRESS_V07
})
const pimlicoPaymasterClient = createPimlicoPaymasterClient({
chain: foundry,
transport: http(paymasterRpc),
entryPoint: ENTRYPOINT_ADDRESS_V07
})
const pimlicoClient = createPimlicoClient({
transport: http(pimlicoUrl),
entryPoint: { // Optional, defaults to 0.7
address: entryPoint07Address,
version: "0.7",
}
})
All the previous actions that were part of createPimlicoBundlerClient
and createPimlicoPaymasterClient
are now part of createPimlicoClient
and can also be acccessed individually.
Pimlico client also extends actions of Paymaster client by viem. It uses ERC-7677 as the default standard to communicate with Pimlico paymasters.
Deprecated smartAccountClient.deployContract
Changed smartAccountClient.prepareUserOperationRequest
to smartAccountClient.prepareUserOperation
import { smartAccountClient } from './config'
const userOperation = await smartAccountClient.prepareUserOperationRequest({
userOperation: {
callData: await smartAccountClient.account.encodeCallData({
to: CONTRACT_ADDRESS,
data: "0x",
value: parseEther('1')
}),
}
})
const userOperation = await smartAccountClient.prepareUserOperation({
calls: [{
to: CONTRACT_ADDRESS,
data: "0x",
value: parseEther('1')
}]
})
Changed smartAccountClient.sendUserOperation
import { smartAccountClient } from './config'
const userOperationHash = await smartAccountClient.sendUserOperation({
userOperation: {
sender: "0x6152348912fb1e78c9037D83f9d4524D4a2988Ed",
nonce: "0x8104e3ad430ea6d354d013a6789fdfc71e671c4300000000000000000000",
factory: "0xd703aaE79538628d27099B8c4f621bE4CCd142d5",
factoryData: "0xc5265d5d0000000000000000000000006723b44abeec4e71ebe3232bd5b455805badd22f0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e412af322c018104e3ad430ea6d354d013a6789fdfc71e671c4300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000014ec787ae5c34157ce61e751e54dff3612d4117663000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
callData: "0xe9ae5c530100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000594bc666500faed35dc741f45a35c571399560d80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e4e688a440000000000000000000000000c67e4838d4e6682e3a5f9ec27f133e76cb3855f30000000000000000000000006152348912fb1e78c9037d83f9d4524d4a2988ed00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000041aebdfb90adba067d9304980a300636506c3c9081b01f64b04f108407a890602377625ef9096946cc028743123646881c7e31a1c8d6698132c188cb4c33a3f9151b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
maxFeePerGas: 99985502n,
maxPriorityFeePerGas: 1221000n,
preVerificationGas: 66875n,
verificationGasLimit: 373705n,
callGasLimit: 170447n,
paymaster: "0x9d0021A869f1Ed3a661Ffe8C9B41Ec6244261d98",
paymasterData: "0x000000000000000000000000000000000000000000000000000000006638ab470000000000000000000000000000000000000000000000000000000000000000e9311d1945317dc6a1c750e8e6d0641a598beb59edc5652ed3807ca57338a7a107123e1a479386b2c91f242d2dff367c18e0ad9d1021acfe47afc890e252644e1c",
paymasterVerificationGasLimit: 20274n,
paymasterPostOpGasLimit: 1n,
signature: "0xa58d445f26b126fcd644975f0c66bd45f3e6e5b9c1acec2eeee490aa9341cfc312988231c228f84e12eac2d90ed9cd8825546d70d73b2e0fabdd6c8089ab29581b",
}
})
It also allows you to submit user operations with using calls
object like with sendTransaction
. You can read more about it here.
Deprecated smartAccountClient.sendTransactions
Use smartAccountClient.sendTransaction
instead. It now accepts an array of transactions. Read more about it here.
Example:
import { account, smartAccountClient } from './config'
import { parseEther } from 'viem'
const hash = await smartAccountClient.sendTransaction({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}, {
abi: wagmiAbi,
functionName: 'mint',
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
}]
})
Error handling
We have deprecated permissionless.js error handling and now use viem's error handling.