Quickstart -- EIP-7702
EIP-7702 is an upcoming Ethereum upgrade that will allow for attaching a piece of EVM code to a EOA, effectively turning it into a "dual account" that can function simultaneously as a EOA and a smart account.
In practical terms, this means that EOA users can now enjoy most of the benefits of AA, such as gas sponsorship, transaction batching, session keys, chain abstraction, and more. Note that since the account is both a smart account and a EOA, true "key rotation" is not possible since the EOA key will always maintain root access to the account.
In this example, we will upgrade a EOA into a ZeroDev smart account (Kernel) and send a gasless batched transaction from it.
Complete example
Here's the complete code example for you to reference as you follow along.
Install packages
You will be using the following packages:
npm i @zerodev/sdk @zerodev/ecdsa-validator viem
Create a project for a 7702-compatible network
In this example, we will use the Sepolia testnet, but you can use any 7702-compatible network such as Holesky and Odyssey.
- Go to the ZeroDev dashboard and create a project for
Ethereum Sepolia
. - Create a gas policy so that we can send sponsored transactions later.
- A simple "project policy" for "100 requests per minute" will do.
- Create a
.env
file as follows:
PRIVATE_KEY=
PROJECT_ID=
Use the project ID from the dashboard. The private key can be any test EOA key.
Sign a 7702 authorization
To upgrade a EOA into a smart account, the first step is to produce a "7702 authorization," which is a signed message that specifies the address of a smart contract that should be "copied" into the EOA. In practice, to minimize the cost of copying, this smart contract will be a proxy that points to the actual smart account implementation, which in our case is Kernel.
In this example, we will be upgrading an EOA generated from the private key, but it can be any EOA (such as an existing wallet) so long as the EOA is able to sign 7702 authorizations. If you are the developer of an existing EOA wallet and you don't know how to update your signing logic to support 7702, please reach out.
To produce the authorization, we use Viem:
import { createWalletClient, Hex, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { sepolia } from 'viem/chains'
import { eip7702Actions } from 'viem/experimental'
import { KERNEL_V3_3_BETA, KernelVersionToAddressesMap } from '@zerodev/sdk'
const kernelVersion = KERNEL_V3_3_BETA
const signer = privateKeyToAccount(process.env.PRIVATE_KEY as Hex)
const chain = sepolia
console.log("EOA Address:", signer.address)
const walletClient = createWalletClient({
chain,
account: signer,
transport: http(),
}).extend(eip7702Actions())
const authorization = await walletClient.signAuthorization({
contractAddress: KernelVersionToAddressesMap[kernelVersion].accountImplementationAddress,
delegate: true,
})
Set up the ZeroDev SDK
Now that you have the authorization, you can proceed to set up the ZeroDev SDK.
import { createPublicClient } from 'viem'
import { getEntryPoint, KERNEL_V3_1 } from '@zerodev/sdk/constants'
import { createKernelAccountClient } from '@zerodev/sdk'
import { getUserOperationGasPrice } from '@zerodev/sdk/actions'
import { createKernelAccount } from '@zerodev/sdk/accounts'
import { signerToEcdsaValidator } from '@zerodev/ecdsa-validator'
const entryPoint = getEntryPoint("0.7")
const kernelVersion = KERNEL_V3_1
const publicClient = createPublicClient({
chain,
transport: http(process.env.BUNDLER_RPC),
})
const ecdsaValidator = await signerToEcdsaValidator(publicClient, {
signer,
entryPoint,
kernelVersion,
})
const account = await createKernelAccount(publicClient, {
plugins: {
sudo: ecdsaValidator,
},
entryPoint,
kernelVersion,
// Set the 7702 authorization
eip7702auth: authorization,
// Set the address of the smart account to the EOA address
address: signer.address,
})
const paymasterClient = createZeroDevPaymasterClient({
chain,
transport: http(process.env.PAYMASTER_RPC),
})
const kernelClient = createKernelAccountClient({
account,
chain,
bundlerTransport: http(process.env.BUNDLER_RPC),
paymaster: paymasterClient,
client: publicClient,
userOperation: {
estimateFeesPerGas: async ({ bundlerClient }) => {
return getUserOperationGasPrice(bundlerClient);
},
},
})
Don't worry if the code doesn't make too much sense -- you can read more about the setup process here.
Comparing to the normal setup process, there are two main differences:
-
When you set up the Kernel account, specify
eip7702auth: authorization
so that the SDK can handle the upgrade using your authorization. -
When you set up the Kernel account, you specify
address: signer.address
to explicitly set the address of the smart account to the EOA address. Otherwise, the SDK would compute the smart account address from its init data, which is how smart accounts normally work. With 7702 however, the account address is the EOA address.
Using the ZeroDev SDK
Now you can use the ZeroDev SDK as usual. For example, to send a gasless batched UserOp:
const userOpHash = await kernelClient.sendUserOperation({
callData: await kernelClient.account.encodeCalls([
{
to: zeroAddress,
value: BigInt(0),
data: "0x",
},
{
to: zeroAddress,
value: BigInt(0),
data: "0x",
},
]),
})
await kernelClient.waitForUserOperationReceipt({
hash: userOpHash,
})
console.log("UserOp completed")
Congratulations! You just sent your first gasless, batched transaction using a EOA. You can see it by looking up your account on the Sepolia explorer. Note that you may need to look under "Internal Transactions" because UserOps do not appear as regular transactions.
Easy, right? Now explore the rest of the ZeroDev docs and see what you can do with your "smart EOA."