EIP-7702 Developer Guide
Introduction
EIP-7702, part of Ethereum's account abstraction roadmap, was introduced in the Pectra hard fork. It allows existing EOAs to adopt smart contract features by delegating control to a designated contract.
This upgrade allows users to:
- Batch transactions
- Use session keys
- Sponsor gas
- Pay with ERC20s
- Enjoy chain abstraction
- Use passkeys
All while retaining their familiar EOA address and without migrating funds.
Key Benefits
- Gas efficiency – No deployment required.
- Seamless UX – Enjoy AA features directly.
- Multichain support – Reuse authorizations across chains.
- Flexible integration – Simple to integrate for devs.
- Custom logic – Not limited to a fixed wallet type.
Technical Deep Dive
EIP-7702 complements ERC-4337, introducing a new transaction type 0x04
(SET_CODE_TX_TYPE) that lets EOAs delegate execution.
Delegation and Authorization
- Delegation: EOA chooses a smart contract for execution.
- Authorization: Signed message with chain ID, contract address, nonce, and signature.
New Transaction Type
rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, value, data, access_list, authorization_list, signature_y_parity, signature_r, signature_s])
// authorization_list = [[chain_id, address, nonce, y_parity, r, s], ...]
authorization_list
address
is the delegated implementation.- Signer (the EOA) is derived from signature + payload.
Type 4 Behavior
For each tuple:
- Validate
chain_id
,nonce
. - Derive
authority = ecrecover(keccak(0x05 || rlp(...)))
. - Add authority to
accessed_addresses
. - Ensure code is empty or already delegated.
- Ensure nonce matches.
- Add gas refund if applicable.
- Set code:
0xef0100 || address
(delegation designation). - If
address == 0x0
, clear code. - Bump nonce.
Delegation is permanent unless explicitly revoked.
Resources
- Viem Guide
- BatchCallAndSponsor.sol
- MetaMask Delegator
- Awesome EIP-7702
- EIP-7702 Portal
- EIP-7851
- Privy React Recipe
- ZeroDev Blog
- ERC-5792 Demo
- Stats Dashboard
- Fusion Module Alt
For Devs: Using EIP-7702
Prerequisites
npm i @startale-scs/aa-sdk viem
Generate credentials on SCS Portal. Retrieve:
bundlerUrl
paymasterUrl
paymasterId
implementationAddress
Setup
import { http, createPublicClient, createWalletClient, privateKeyToAccount, generatePrivateKey } from "viem";
import { createSCSPaymasterClient, createSmartAccountClient, toStartaleSmartAccount } from "@startale-scs/aa-sdk";
const signer = privateKeyToAccount(generatePrivateKey());
const chain = soneiumMinato;
const publicClient = createPublicClient({ transport: http(), chain });
const walletClient = createWalletClient({ account: signer, chain, transport: http() });
const paymaster = createSCSPaymasterClient({ transport: http(paymasterUrl) });
const scsContext = { calculateGasLimits: true, paymasterId };
Manual Authorization
const authorization = await walletClient.signAuthorization({ contractAddress: implementationAddress });
const smartAccountClient = createSmartAccountClient({
account: await toStartaleSmartAccount({
signer,
chain,
transport: http(),
accountAddress: eoaAddress,
eip7702Auth: authorization,
}),
transport: http(bundlerUrl),
client: publicClient,
paymaster,
paymasterContext: scsContext,
});
Automatic Authorization
const smartAccountClient = createSmartAccountClient({
account: await toStartaleSmartAccount({
signer,
chain,
transport: http(),
accountAddress: eoaAddress,
eip7702Account: signer,
}),
transport: http(bundlerUrl),
client: publicClient,
paymaster,
paymasterContext: scsContext,
});
Sending Transactions
const callData = encodeFunctionData({ abi: CounterAbi, functionName: "count" });
const hash = await smartAccountClient.sendUserOperation({
calls: [{ to: counterContract, value: 0n, data: callData }],
});
const receipt = await smartAccountClient.waitForUserOperationReceipt({ hash });
console.log("receipt", receipt);
const isDelegated = await smartAccountClient.account.isDelegated();
console.log("isDelegated", isDelegated);
Helpers
const isDelegated = await smartAccountClient.account.isDelegated();
const tx = await smartAccountClient.account.unDelegate();
const unDelegateReceipt = await publicClient.waitForTransactionReceipt({ hash: tx });
External Wallets
Expect restrictions on which smart account implementations are supported. Likely flows:
- Prompt user to upgrade with pre-approved contract
- Limited to wallet provider’s implementation
Embedded Wallets
Dapps integrate against their own embedded wallets with full feature support. No dependency on external wallet compatibility.
Tutorial
Coming soon: How to upgrade an EOA to a Startale smart account and batch-mint NFTs gaslessly.