Skip to main content

Simple 7702 Account (EntryPoint v0.8)

The Simple7702Account targets EntryPoint v0.8 and supports the full feature set including gas sponsorship and ERC-20 gas payments through the Candide paymaster.

Moving to EntryPoint v0.9?

See the Simple 7702 Account (EntryPoint v0.9) reference and the 07-migrate-v08-to-v09.ts example for a complete v0.8 to v0.9 migration.

Smart Contracts and Audits​

The contracts were developed by the Ethereum Foundation Account Abstraction Team and audited by Spearbit.

How to Use​

Prerequisites​

Before using Simple7702Account, you must have:

  • Node.js: Version 18.0 or higher.
  • EIP-7702 Compatible Network: Ethereum mainnet, Sepolia, Optimism, Base, or other EIP-7702 enabled chains.
  • Private Key Access: Required for signing authorizations and user operations.

Installation​

npm install abstractionkit

Usage​

import { Simple7702Account } from "abstractionkit";

const delegatorPublicAddress = "0xBdbc5FBC9cA8C3F514D073eC3de840Ac84FC6D31"; // EOA public key
const smartAccount = new Simple7702Account(delegatorPublicAddress);

Constructor defaults:

  • entrypointAddress: 0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108 (EntryPoint v0.8)
  • delegateeAddress: 0xe6Cae83BdE06E4c305530e199D7217f42808555B

Both can be overridden by passing an overrides object as the second constructor argument.

const simple7702Account = new Simple7702Account(eoaAddress, {
entrypointAddress: "0x...", // optional
delegateeAddress: "0x...", // optional
});

Essential Methods​

createUserOperation​

Creates a UserOperation for EIP-7702 accounts that can be sent to bundlers for execution.

example.ts
import { Simple7702Account } from "abstractionkit";

const delegatorPublicAddress = "0xBdbc5FBC9cA8C3F514D073eC3de840Ac84FC6D31";
const smartAccount = new Simple7702Account(delegatorPublicAddress);

const chainId = 11155111n; // Sepolia

const transactions = [
{
to: "0x...",
value: 0n,
data: "0x...",
},
];

const userOperation = await smartAccount.createUserOperation(
transactions,
"https://ethereum-sepolia-rpc.publicnode.com", // provider RPC
"https://api.candide.dev/public/v3/11155111", // bundler RPC
{
eip7702Auth: {
chainId, // chainId at which the account will be authorized
},
// Optional overrides
maxFeePerGas: 20000000000n,
maxPriorityFeePerGas: 2000000000n,
}
);

signUserOperation​

Signs a UserOperation with the provided private key for the EIP-7702 account.

example.ts
const signature = smartAccount.signUserOperation(
userOperation,
"0x...private-key",
11155111n // chain ID
);

userOperation.signature = signature;

signUserOperationWithSigner​

Signs a UserOperation using an ExternalSigner instead of a raw private key. Integrates viem, ethers, browser wallets, hardware wallets, HSMs, and MPC services through the same API.

Since AbstractionKit v0.3.5, Simple7702Account accepts signers that implement either signTypedData or signHash. The SDK prefers signTypedData when available, so JSON-RPC wallets and viem WalletClient instances can sign EntryPoint v0.8 UserOperations without raw-hash signing support. Raw-hash signers continue to work.

example.ts
import { fromViemWalletClient } from "abstractionkit";
import { createWalletClient, custom } from "viem";

const walletClient = createWalletClient({
account: delegatorPublicAddress,
chain,
transport: custom(window.ethereum),
});

userOperation.signature = await smartAccount.signUserOperationWithSigner(
userOperation,
fromViemWalletClient(walletClient),
11155111n, // chain ID
);

See External Signers for the full list of adapters and custom-signer integrations.

getUserOperationEip712Data​

Builds the EIP-712 typed data payload for a UserOperation under the EntryPoint v0.8 domain. Use this static helper when you need to inspect the wallet prompt payload or drive a custom signTypedData primitive directly.

example.ts
import { Simple7702Account } from "abstractionkit";

const typedData = Simple7702Account.getUserOperationEip712Data(
userOperation,
11155111n,
);

const signature = await walletClient.signTypedData(typedData);
userOperation.signature = signature;

getUserOperationEip712TypedData was renamed in v0.3.8 and moved from an instance method to a static helper. Use getUserOperationEip712Hash(userOperation, chainId, overrides?) when you only need the digest.

sendUserOperation​

Sends a signed UserOperation to the bundler for execution on-chain.

example.ts
const response = await smartAccount.sendUserOperation(
userOperation,
"https://api.candide.dev/public/v3/11155111" // bundler URL
);

console.log("UserOperation hash:", response.userOperationHash);

// Wait for the transaction to be included
const receipt = await response.included();
console.log("Transaction receipt:", receipt);

Advanced Methods​

createAccountCallData​

Creates call data for a basic transaction with specified target, value, and data.

example.ts
const callData = Simple7702Account.createAccountCallData(
"0x...", // to address
1000000000000000000n, // value in wei
"0x..." // transaction data
);

createAccountCallDataSingleTransaction​

Creates call data for a single SimpleMetaTransaction.

example.ts
const metaTransaction = {
to: "0x...",
value: 0n,
data: "0x...",
};

const callData = Simple7702Account.createAccountCallDataSingleTransaction(metaTransaction);

createAccountCallDataBatchTransactions​

Creates call data for batching multiple SimpleMetaTransactions together.

example.ts
const transactions = [
{ to: "0x...", value: 0n, data: "0x..." },
{ to: "0x...", value: 0n, data: "0x..." },
];

const callData = Simple7702Account.createAccountCallDataBatchTransactions(transactions);

prependTokenPaymasterApproveToCallDataStatic​

Prepends a token approval transaction to existing call data for use with token paymasters.

example.ts
const callDataWithApproval = Simple7702Account.prependTokenPaymasterApproveToCallDataStatic(
"0x...", // existing call data
"0xa0b86a33e6b3e96bb24b8e4b28e80e0fb3a4f4b6", // USDC token address
"0x...", // paymaster address
1000000n // approve amount (1 USDC)
);

prependTokenPaymasterApproveToCallData​

Instance method to prepend token approval to call data for paymaster usage.

example.ts
const callDataWithApproval = smartAccount.prependTokenPaymasterApproveToCallData(
"0x...", // existing call data
"0xa0b86a33e6b3e96bb24b8e4b28e80e0fb3a4f4b6", // USDC token address
"0x...", // paymaster address
1000000n // approve amount
);

estimateUserOperationGas​

Estimates gas limits for a UserOperation using the bundler.

example.ts
const [preVerificationGas, verificationGasLimit, callGasLimit] =
await smartAccount.estimateUserOperationGas(
userOperation,
"https://api.candide.dev/public/v3/11155111",
{
// Optional overrides
stateOverrideSet: {...},
dummySignature: "0x...",
}
);

Delegation Methods​

isDelegatedToThisAccount​

Checks if the EOA is currently delegated to the expected smart account address via EIP-7702. Returns true only when delegated to the account's delegateeAddress.

example.ts
const isDelegated = await smartAccount.isDelegatedToThisAccount(
"https://ethereum-sepolia-rpc.publicnode.com"
);

if (isDelegated) {
console.log("EOA is delegated to this smart account");
} else {
console.log("EOA is not delegated");
}

createRevokeDelegationTransaction​

Creates a signed EIP-7702 transaction that revokes the delegation, restoring the EOA to a regular account. The transaction delegates to address(0), removing the smart account code from the EOA.

This is a regular Ethereum transaction (type 0x04), not a UserOperation. The EOA needs native tokens to pay for gas.

note

Revocation cannot be done via a UserOperation because the authorization list is processed before execution, which would remove the account's code mid-transaction.

example.ts
const signedTransaction = await smartAccount.createRevokeDelegationTransaction(
"0x...private-key",
"https://ethereum-sepolia-rpc.publicnode.com",
);

// Send using your preferred method (e.g., viem, ethers)
// const txHash = await client.request({
// method: 'eth_sendRawTransaction',
// params: [signedTransaction],
// });

Error Handling & Common Issues​

Common Errors​

// Missing eip7702Auth on the first UserOperation authorization
const userOperation = await smartAccount.createUserOperation(
transactions,
providerRpc,
bundlerRpc
// Missing eip7702Auth causes delegation failure
);

// Correct usage
const userOperation = await smartAccount.createUserOperation(
transactions,
providerRpc,
bundlerRpc,
{
eip7702Auth: { chainId: 11155111n }, // Required for EIP-7702
}
);

Error Recovery​

async function robustTransactionExecution() {
try {
const response = await smartAccount.sendUserOperation(userOperation, bundlerRpc);
const receipt = await response.included();

if (!receipt.success) {
console.error("Transaction failed:", receipt.logs);
// Handle transaction failure
}

return receipt;
} catch (error) {
if (error.code === -32500) {
// Transaction rejected by entrypoint simulation
console.error("Simulation failed, check transaction data");
} else if (error.code === -32501) {
// Paymaster rejection
console.error("Paymaster rejected transaction");
}
throw error;
}
}