Skip to main content

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

  1. Gas efficiency – No deployment required.
  2. Seamless UX – Enjoy AA features directly.
  3. Multichain support – Reuse authorizations across chains.
  4. Flexible integration – Simple to integrate for devs.
  5. 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:

  1. Validate chain_id, nonce.
  2. Derive authority = ecrecover(keccak(0x05 || rlp(...))).
  3. Add authority to accessed_addresses.
  4. Ensure code is empty or already delegated.
  5. Ensure nonce matches.
  6. Add gas refund if applicable.
  7. Set code: 0xef0100 || address (delegation designation).
  8. If address == 0x0, clear code.
  9. Bump nonce.

Delegation is permanent unless explicitly revoked.


Resources

  1. Viem Guide
  2. BatchCallAndSponsor.sol
  3. MetaMask Delegator
  4. Awesome EIP-7702
  5. EIP-7702 Portal
  6. EIP-7851
  7. Privy React Recipe
  8. ZeroDev Blog
  9. ERC-5792 Demo
  10. Stats Dashboard
  11. 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:

  1. Prompt user to upgrade with pre-approved contract
  2. 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.