EIP-7702 After Pectra: A Practical Playbook for Ethereum App Developers
On May 7, 2025, Ethereum’s Pectra upgrade (Prague + Electra) hit mainnet. Among its most developer-visible changes is EIP-7702, which lets an externally owned account (EOA) "mount" smart-contract logic—without migrating funds or changing addresses. If you build wallets, dapps, or relayers, this unlocks a simpler path to smart-account UX.
Below is a concise, implementation-first guide: what actually shipped, how 7702 works, when to choose it over pure ERC-4337, and a cut-and-paste scaffold you can adapt today.
What Actually Shipped
- EIP-7702 is in Pectra’s final scope. The meta-EIP for the Pectra hard fork officially lists 7702 among the included changes.
- Activation details: Pectra activated on mainnet at epoch 364032 on May 7, 2025, following successful activations on all major testnets.
- Toolchain note: Solidity v0.8.30 updated its default EVM target to prague for Pectra compatibility. You'll need to upgrade your compilers and CI pipelines, especially if you pin specific versions.
EIP-7702—How It Works (Nuts & Bolts)
EIP-7702 introduces a new transaction type and a mechanism for an EOA to delegate its execution logic to a smart contract.
- New Transaction Type (0x04): A Type-4 transaction includes a new field called an
authorization_list
. This list contains one or more authorization tuples—(chain_id, address, nonce, y_parity, r, s)
—each signed by the EOA's private key. When this transaction is processed, the protocol writes a delegation indicator to the EOA’s code field:0xef0100 || address
. From that point forward, any calls to the EOA are proxied to the specifiedaddress
(the implementation), but they execute within the EOA’s storage and balance context. This delegation remains active until it's explicitly changed. - Chain Scope: An authorization can be chain-specific by providing a
chain_id
, or it can apply to all chains ifchain_id
is set to0
. This allows you to deploy the same implementation contract across multiple networks without requiring users to sign a new authorization for each one. - Revocation: To revert an EOA back to its original, non-programmable behavior, you simply send another 7702 transaction where the implementation
address
is set to the zero address. This clears the delegation indicator. - Self-Sponsored vs. Relayed: An EOA can submit the Type-4 transaction itself, or a third-party relayer can submit it on the EOA's behalf. The latter is common for creating a gasless user experience. Nonce handling differs slightly depending on the method, so it's important to use libraries that correctly manage this distinction.
Security Model Shift: Because the original EOA private key still exists, it can always override any smart contract rules (like social recovery or spending limits) by submitting a new 7702 transaction to change the delegation. This is a fundamental shift. Contracts that rely on
tx.origin
to verify that a call is from an EOA must be re-audited, as 7702 can break these assumptions. Audit your flows accordingly.
7702 or ERC-4337? (And When to Combine)
Both EIP-7702 and ERC-4337 enable account abstraction, but they serve different needs.
- Choose EIP-7702 when…
- You want to provide instant smart-account UX for existing EOAs without forcing users to migrate funds or change addresses.
- You need consistent addresses across chains that can be progressively upgraded with new features.
- You want to stage your transition to account abstraction, starting with simple features and adding complexity over time.
- Choose pure ERC-4337 when…
- Your product requires full programmability and complex policy engines (e.g., multi-sig, advanced recovery) from day one.
- You are building for new users who don't have existing EOAs, making new smart-account addresses and the associated setup acceptable.
- Combine them: The most powerful pattern is to use both. An EOA can use a 7702 transaction to designate an ERC-4337 wallet implementation as its logic. This makes the EOA behave like a 4337 account, allowing it to be bundled, sponsored by paymasters, and processed by the existing 4337 infrastructure—all without the user needing a new address. This is a forward-compatible path explicitly encouraged by the EIP's authors.
Minimal 7702 Scaffold You Can Adapt
Here’s a practical example of an implementation contract and the client-side code to activate it.
1. A Tiny, Auditable Implementation Contract
This contract code will execute in the EOA’s context once designated. Keep it small, auditable, and consider adding an upgrade mechanism.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @notice Executes calls from the EOA context when designated via EIP-7702.
contract DelegatedAccount {
// Unique storage slot to avoid collisions with other contracts.
bytes32 private constant INIT_SLOT =
0x3fb93b3d3dcd1d1f4b4a1a8db6f4c5d55a1b7f9ac01dfe8e53b1b0f35f0c1a01;
event Initialized(address indexed account);
event Executed(address indexed to, uint256 value, bytes data, bytes result);
modifier onlyEOA() {
// Optional: add checks to restrict who can call certain functions.
_;
}
function initialize() external payable onlyEOA {
// Set a simple one-time init flag in the EOA's storage.
bytes32 slot = INIT_SLOT;
assembly {
if iszero(iszero(sload(slot))) { revert(0, 0) } // Revert if already initialized
sstore(slot, 1)
}
emit Initialized(address(this));
}
function execute(address to, uint256 value, bytes calldata data)
external
payable
onlyEOA
returns (bytes memory result)
{
(bool ok, bytes memory ret) = to.call{value: value}(data);
require(ok, "CALL_FAILED");
emit Executed(to, value, data, ret);
return ret;
}
function executeBatch(address[] calldata to, uint256[] calldata value, bytes[] calldata data)
external
payable
onlyEOA
{
uint256 n = to.length;
require(n == value.length && n == data.length, "LENGTH_MISMATCH");
for (uint256 i = 0; i < n; i++) {
(bool ok, ) = to[i].call{value: value[i]}(data[i]);
require(ok, "CALL_FAILED");
}
}
}
2. Designate the Contract on an EOA (Type-4 tx) with viem
Modern clients like viem
have built-in helpers to sign authorizations and send Type-4 transactions. In this example, a relayer
account pays the gas to upgrade an eoa
.
import { createWalletClient, http, encodeFunctionData } from "viem";
import { sepolia } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";
import { abi, implementationAddress } from "./DelegatedAccountABI";
// 1. Define the relayer (sponsors gas) and the EOA to be upgraded
const relayer = privateKeyToAccount(process.env.RELAYER_PK as `0x${string}`);
const eoa = privateKeyToAccount(process.env.EOA_PK as `0x${string}`);
const client = createWalletClient({
account: relayer,
chain: sepolia,
transport: http(),
});
// 2. The EOA signs the authorization pointing to the implementation contract
const authorization = await client.signAuthorization({
account: eoa,
contractAddress: implementationAddress,
// If the EOA itself were sending this, you would add: executor: 'self'
});
// 3. The relayer sends a Type-4 transaction to set the EOA's code and call initialize()
const hash = await client.sendTransaction({
to: eoa.address, // The destination is the EOA itself
authorizationList: [authorization], // The new EIP-7702 field
data: encodeFunctionData({ abi, functionName: "initialize" }),
});
// 4. Now, the EOA can be controlled via its new logic without further authorizations
// For example, to execute a transaction:
// await client.sendTransaction({
// to: eoa.address,
// data: encodeFunctionData({ abi, functionName: 'execute', args: [...] })
// });
3. Revoke Delegation (Back to Plain EOA)
To undo the upgrade, have the EOA sign an authorization that designates the zero address as the implementation and send another Type-4 transaction. Afterward, a call to eth_getCode(eoa.address)
should return empty bytes.
Integration Patterns That Work in Production
- Upgrade in Place for Existing Users: In your dapp, detect if the user is on a Pectra-compatible network. If so, display an optional "Upgrade Account" button that triggers the one-time authorization signature. Maintain fallback paths (e.g., classic
approve
+swap
) for users with older wallets. - Gasless Onboarding: Use a relayer (either your backend or a service) to sponsor the initial Type-4 transaction. For ongoing gasless transactions, route user operations through an ERC-4337 bundler to leverage existing paymasters and public mempools.
- Cross-Chain Rollouts: Use a
chain_id = 0
authorization to designate the same implementation contract across all chains. You can then enable or disable features on a per-chain basis within your application logic. - Observability: Your backend should index Type-4 transactions and parse the
authorization_list
to track which EOAs have been upgraded. After a transaction, verify the change by callingeth_getCode
and confirming the EOA's code now matches the delegation indicator (0xef0100 || implementationAddress
).
Threat Model & Gotchas (Don’t Skip This)
- Delegation is Persistent: Treat changes to an EOA's implementation contract with the same gravity as a standard smart contract upgrade. This requires audits, clear user communication, and ideally, an opt-in flow. Never push new logic to users silently.
tx.origin
Landmines: Any logic that usedmsg.sender == tx.origin
to ensure a call came directly from an EOA is now potentially vulnerable. This pattern must be replaced with more robust checks, like EIP-712 signatures or explicit allowlists.- Nonce Math: When an EOA sponsors its own 7702 transaction (
executor: 'self'
), its authorization nonce and transaction nonce interact in a specific way. Always use a library that correctly handles this to avoid replay issues. - Wallet UX Responsibility: The EIP-7702 specification warns that dapps should not ask users to sign arbitrary designations. It is the wallet's responsibility to vet proposed implementations and ensure they are safe. Design your UX to align with this principle of wallet-mediated security.
When 7702 is a Clear Win
- DEX Flows: A multi-step
approve
andswap
can be combined into a single click using theexecuteBatch
function. - Games & Sessions: Grant session-key-like privileges for a limited time or scope without requiring the user to create and fund a new wallet.
- Enterprise & Fintech: Enable sponsored transactions and apply custom spending policies while keeping the same corporate address on every chain for accounting and identity.
- L2 Bridges & Intents: Create smoother meta-transaction flows with a consistent EOA identity across different networks.
These use cases represent the same core benefits promised by ERC-4337, but are now available to every existing EOA with just a single authorization.
Ship Checklist
Protocol
- Ensure nodes, SDKs, and infrastructure providers support Type-4 transactions and Pectra's "prague" EVM.
- Update indexers and analytics tools to parse the
authorization_list
field in new transactions.
Contracts
- Develop a minimal, audited implementation contract with essential features (e.g., batching, revocation).
- Thoroughly test revoke and re-designate flows on testnets before deploying to mainnet.
Clients
- Upgrade client-side libraries (
viem
,ethers
, etc.) and test thesignAuthorization
andsendTransaction
functions. - Verify that both self-sponsored and relayed transaction paths handle nonces and replays correctly.
Security
- Remove all assumptions based on
tx.origin
from your contracts and replace them with safer alternatives. - Implement post-deployment monitoring to detect unexpected code changes at user addresses and alert on suspicious activity.
Bottom line: EIP-7702 provides a low-friction on-ramp to smart-account UX for the millions of EOAs already in use. Start with a tiny, audited implementation, use a relayed path for gasless setup, make revocation clear and easy, and you can deliver 90% of the benefits of full account abstraction—without the pain of address churn and asset migration.