EIP-7702 Quickstart — Send a user operation from an EOA | Pimlico Docs
Skip to content

EIP-7702 Quickstart — Send a user operation from an EOA

This guide showcases a simple demo that uses ERC-4337 and EIP-7702 to send a sponsored user operation from a EOA. We will use SimpleSmartAccount as our smart account implementation of choice, other ERC-7702 compatible smart accounts will work as well.

For a high level overview of EIP-7702, checkout our EIP-7702 conceptual guide and for a more technical overview, please refer to the EIP-7702 proposal.

Installation

Make sure you have viem^2.28.0 and permissionless^0.2.24 installed.

npm
npm install permissionless viem

Steps

Setup the smart account

The setup process follows the typical flow of sending a userOperation. The only difference is that when creating the Simple smart account instance, we set the sender address as our EOA's address.

import { createPublicClient, Hex, http } from "viem";
import { toSimple7702SmartAccount } from "viem/account-abstraction";
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
import { sepolia } from "viem/chains";
 
// This is your EOA's private key
const privateKey = generatePrivateKey();
 
const eoa7702 = privateKeyToAccount(privateKey);
 
const client = createPublicClient({
	chain: sepolia,
	transport: http("https://sepolia.drpc.org"),
});
 
const simple7702Account = await toSimple7702SmartAccount({
	client,
	owner: eoa7702,
});
 

Setup paymaster (optional)

The paymaster client will be responsible for interacting with Pimlico's verifying paymaster endpoint and requesting sponsorship. Make sure to replace YOUR_PIMLICO_API_KEY in the code below with your actual Pimlico API key.

import { createPimlicoClient } from "permissionless/clients/pimlico";
 
const pimlicoAPIKey = "<YOUR_PIMLICO_API_KEY>";
 
const pimlicoClient = createPimlicoClient({
	chain: sepolia,
	transport: http(
		`https://api.pimlico.io/v2/11155111/rpc?apikey=${pimlicoAPIKey}`,
	),
});

Create Smart Account Client

A Smart Account Client is an almost drop-in replacement for a standard viem walletClient but for managing smart accounts instead of EOA accounts. In addition, a Smart Account Client also contains, depending on the underlying smart account implementation used, a few extra actions that are specific to smart accounts.

To create a Smart Account Client, use the createSmartAccountClient function.

 
import { createSmartAccountClient } from "permissionless";
import { zeroAddress } from "viem";
 
const smartAccountClient = createSmartAccountClient({
	client,
	chain: sepolia,
	account: simple7702Account,
	paymaster: pimlicoClient,
	bundlerTransport: http(
		`https://api.pimlico.io/v2/11155111/rpc?apikey=${pimlicoAPIKey}`,
	),
});

Sending the transaction

Make sure you set the signed authorization for the first time when the EOA does not have the authorization code set.

 
const isSmartAccountDeployed = await smartAccountClient.account.isDeployed();
 
let transactionHash: Hex;
 
// We only have to add the authorization field if the EOA does not have the authorization code set
if (!isSmartAccountDeployed) {
	transactionHash = await smartAccountClient.sendTransaction({
		to: zeroAddress,
		value: 0n,
		data: "0x",
		authorization: await eoa7702.signAuthorization({
			address: "0xe6Cae83BdE06E4c305530e199D7217f42808555B",
			chainId: sepolia.id,
			nonce: await client.getTransactionCount({
				address: eoa7702.address,
			}),
		}),
	});
} else {
	transactionHash = await smartAccountClient.sendTransaction({
		to: zeroAddress,
		value: 0n,
		data: "0x",
	});
}
 

Batch multiple transactions

The process is the same as sending a single transaction, the only difference is that we pass an array of calls to the sendTransaction function.

 
let transactionHash_2: Hex;
 
// We only have to add the authorization field if the EOA does not have the authorization code set
if (!isSmartAccountDeployed) {
	transactionHash_2 = await smartAccountClient.sendTransaction({
		calls: [
			{
				to: zeroAddress,
				value: 0n,
				data: "0x",
			},
			{
				to: zeroAddress,
				value: 0n,
				data: "0x",
			},
		],
		authorization: await eoa7702.signAuthorization({
			address: "0xe6Cae83BdE06E4c305530e199D7217f42808555B",
			chainId: sepolia.id,
			nonce: await client.getTransactionCount({
				address: eoa7702.address,
			}),
		}),
	});
} else {
	transactionHash_2 = await smartAccountClient.sendTransaction({
		calls: [
			{
				to: zeroAddress,
				value: 0n,
				data: "0x",
			},
			{
				to: zeroAddress,
				value: 0n,
				data: "0x",
			},
		],
	});
}
 

Review

Congratulations! You have successfully sent a sponsored userOperation from your EOA, if you review the transaction on the blockchain explorer, you will see that the userOperation's sender address is equal to your EOA's address.