ByAUJay
Summary: EIP-7702 (shipped in Ethereum’s May 7, 2025 Pectra upgrade) lets EOAs delegate execution to audited smart-contract code. In this post we show how to add temporary, narrowly-scoped validation to EOAs—think one-shot approvals, time-boxed session keys, and target-scoped spending—without migrating users to new wallet addresses. (blog.ethereum.org)
Programmable EOAs: Patterns for Temporary Validation Logic with EIP-7702
Decision-makers don’t need another overview of “account abstraction.” You need actionable patterns your teams can ship in Q1/Q2 2026 product roadmaps. Below are precise, field-tested ways to make EOAs programmable for the duration you choose—one call, one hour, one campaign—using EIP-7702’s delegate mechanism, without forcing users to abandon their familiar addresses.
What actually changed (and why it matters)
- EIP-7702 introduced a new transaction type (Type 0x04) that allows an EOA to set “delegated code” for itself. That code isn’t the EOA’s own bytecode; it’s a pointer to a contract whose code will execute in the EOA’s context. Practically, the user’s EOA behaves like a smart account while delegated. (eips.ethereum.org)
- The upgrade went live on May 7, 2025 (epoch 364032). If you postponed AA until it was “native,” your integration window is now open. (blog.ethereum.org)
Key 7702 mechanics your architects should know:
- Type-4 transactions carry an authorization_list of tuples: (chain_id, address, nonce, y_parity, r, s). For each tuple, clients set the EOA’s code to a “delegation indicator” 0xef0100 || address, which instructs the EVM to load code from address when the EOA is called. (eips.ethereum.org)
- Intrinsic costs: base costs follow EIP-2930 rules plus 25,000 gas per authorization tuple; the spec’s impact analysis estimates ~12,016 gas of “work” per tuple (rounded to 12,500) that informs refunds. Use this to rough-order gas budgets for delegated flows. (eips.ethereum.org)
- Persistence: the delegation persists across transactions until explicitly cleared by another Type-4 auth that points to address(0). That means “temporary” must be enforced in logic, not by automatic code reversion. (eips.ethereum.org)
- Security footnote: allowing tx.origin to set code means legacy patterns that used require(msg.sender == tx.origin) as a reentrancy or sandwich guard may break. Review any such checks in contracts you integrate with. (eips.ethereum.org)
Tooling status (the practical bits):
- viem exposes helpers like signAuthorization for Type‑4 tuples; target this first for SDK support. (viem.sh)
- ethers v6 added Type‑4 support (tracking issue closed). If your stack is on ethers, upgrade and verify provider- and wallet-side support for authorization_list. (github.com)
- Etherscan added Pectra visualizations; you can track Type‑4 transactions and delegated code on mainnet. Handy for CS and on-call runbooks. (info.etherscan.com)
“Temporary validation logic” with 7702: the mental model
Because delegation persists until you clear it, the right way to build temporary behavior is to make the delegated contract enforce time, scope, and usage limits using the EOA’s storage. You’re installing a policy engine (delegate) that:
- Validates a constrainted signature or session capability.
- Executes the allowed call(s) in the EOA’s context.
- Updates the EOA’s storage to prevent re-use (for one-shot flows) or to expire sessions.
To prevent storage collisions across different delegates or versions, namespacing storage via ERC‑7201 is now a best practice. Treat each policy as its own namespace keyed by a unique identifier. (eips.ethereum.org)
Use transient storage (EIP‑1153) for intra-transaction reentrancy locks and ephemeral flags; it’s cheaper than SSTORE/SLOAD and cleared automatically at tx end. (eips.ethereum.org)
Pattern 1 — One‑shot Intent: “exactly one call, exactly once”
When you want a user to approve a single downstream action (e.g., approve + swap) with zero lingering power:
- The user signs a typed “OneShot” intent with:
- validUntil (timestamp or block)
- target contract
- function selector + calldata digest
- maxValue (ETH) and optional token spend cap
- gas ceiling
- authNonce (delegate-scoped)
- Your 7702 delegate verifies and executes, then marks the auth hash as consumed in the EOA’s storage namespace.
Implementation sketch (delegate contract):
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; // ERC-7201 namespacing to avoid collisions across delegates library OneShotStorage { // @custom:storage-location erc7201:7block.oneshot.v1 struct Layout { mapping(bytes32 => bool) used; } bytes32 internal constant SLOT = 0x64e2c8c6e7b2f6a14f6e...; // keccak per ERC-7201 function layout() internal pure returns (Layout storage l) { assembly { l.slot := SLOT } } } contract EOAOneShotDelegate { using OneShotStorage for OneShotStorage.Layout; // EIP-712 domain separator cached or computed bytes32 public constant TYPEHASH = keccak256( "OneShot(uint256 chainId,address target,bytes4 selector,bytes32 calldataHash,uint256 maxValue,uint256 validUntil,uint64 authNonce,uint64 gasCeil)" ); error Expired(); error Used(); error WrongTarget(); error ValueTooHigh(); function executeOneShot( bytes calldata callData, bytes calldata sig, address target, bytes4 selector, uint256 maxValue, uint256 validUntil, uint64 authNonce, uint64 gasCeil ) external payable { // Reentrancy lock via EIP-1153 assembly { tstore(0x7b10, 1) } // set transient flag require(block.timestamp <= validUntil, Expired()); // Compute intent hash bytes32 h = keccak256(abi.encode( TYPEHASH, block.chainid, target, selector, keccak256(callData), maxValue, validUntil, authNonce, gasCeil )); // Ensure not replayed OneShotStorage.Layout storage L = OneShotStorage.layout(); if (L.used[h]) revert Used(); // Recover signer = current EOA (msg.sender is the delegated EOA context) // Verify EIP-712 sig against msg.sender (ERC-1271 not applicable here) _verify712(msg.sender, h, sig); // Enforce policy if (msg.value > maxValue) revert ValueTooHigh(); if (gasCeil > 0) require(gasleft() <= gasCeil, "gasCeil exceeded"); if (selector != bytes4(callData[0:4])) revert WrongTarget(); // Mark consumed before external call to prevent reentrancy replay L.used[h] = true; // Execute in EOA context: balances and storage are the EOA's (bool ok, bytes memory ret) = target.call{value: msg.value}(callData); if (!ok) assembly { revert(add(ret, 32), mload(ret)) } // Clear transient reentrancy flag assembly { tstore(0x7b10, 0) } } function _verify712(address expected, bytes32 structHash, bytes calldata sig) internal view { // Omitted: typical EIP-712 digest build and ecrecover; ensure low-s } }
Notes:
- One-shot validity lives entirely in EOA storage, so even though the delegation pointer persists, the permission does not.
- Use low-s signature checks and set chain_id ≠ 0 in intents to prevent cross-chain reuse. The 7702 authorization tuples themselves allow chain_id==0, but for your app-level intents do not mirror that flexibility. (eips.ethereum.org)
- Reentrancy: prefer transient storage locks (TSTORE/TLOAD) over SSTORE to keep gas tight. (eips.ethereum.org)
Pattern 2 — Time‑boxed Session Keys with Spend Limits
For games, social dapps, or L2 commerce: give a device key limited powers for N minutes/hours.
Mechanics:
- The delegate holds a registry mapping session pubkeys to policies:
- validAfter/validUntil
- spend ceilings (per token, per block/day)
- allowlisted target selectors
- Validation accepts either EOA main key signatures or session-key signatures (checked via ecrecover on the session pubkey), then enforces policy and increments counters in the EOA’s namespaced storage. When time expires, validations fail automatically.
Tips:
- Keep session counters namespaced per token and per target to minimize accidental clashes if you upgrade delegates later. ERC‑7201 consistently solves this. (eips.ethereum.org)
- Pair with a “clear delegation” UX, but don’t rely on it. Treat expiry in logic as the true kill switch.
Pattern 3 — Target‑scoped Approvals (“only this app, only these methods”)
When a partner integration needs recurring access for a bounded surface area:
- The delegate maintains a Merkle root of allowed (target, selector) pairs and optionally max per-call value.
- The user signs a single “AppScope” grant referencing that root; your partner sends call proofs with each interaction.
Advantages:
- Rotating the allowlist (e.g., to add a new method) is just a storage update and doesn’t change the EOA’s address or require reinstalling the delegate.
- You can force “view function only” calls by requiring no state change on end-of-call checksum (compare pre/post storage commitments in your namespace).
Pattern 4 — Multi‑party Escalation Windows (social recovery and high‑risk actions)
Use 7702 to bootstrap recovery and “high-risk action” delays without a full smart-account migration:
- The “Guardian” delegate enforces a two‑stage process:
- Initiate: main key (or session) proposes an action (e.g., rotate delegation to a new wallet code, transfer > X ETH) with a timelock.
- Confirm: guardians co-sign during the window; execution succeeds only if threshold signatures are present.
This gives you the value of smart-account guardianship while retaining a user’s EOA address and the ability to interact with legacy contracts that still depend on EOAs.
Pattern 5 — Sponsored flows with receipts (safe for relayers)
Sponsored transactions are now much simpler—no separate 4337 mempool needed if you prefer pure L1 flows. But relayers must be protected:
- Require a paymaster-like receipt: the delegated contract verifies a signed “sponsor commitment” that includes:
- nonce scoped to the sponsor
- max gas and fee caps
- “refund token” and rate (for ERC‑20 refunds)
- If the call succeeds, it issues an on-chain receipt event the relayer can trust in settlement. Relayers should also price-in the risk that an authority invalidates the authorization mid-flight by bumping its nonce; require pre-funded bonds or reputation for your sponsors. (eips.ethereum.org)
Example end-to-end: batch “approve + swap” in one user click
-
User signs Type‑4 authorization tuple delegating to your audited “BatchDelegate” contract (address D).
-
In the same transaction, destination is your batch router; it calls the EOA (now delegated) to:
- run ERC‑20 approve(token, router)
- execute exactOutput swap on target DEX
- enforce “slippage <= X” and “value == 0” policy in the delegate
- mark intent consumed
-
Gas accounting: budget baseline Type‑4 intrinsic + 25k per authorization + normal call gas; use warm vs cold account costs (100 vs 2600) for target calls in your estimates. Production systems should record per-route execution gas to tune tips. (eips.ethereum.org)
Operational guidance and emerging best practices
Security and correctness:
- Avoid chain_id==0 in application-level signatures. 7702 permits it for authorizations, but your intents should be chain-bound to avoid cross-chain replay risk if the same delegate address exists on multiple networks. (eips.ethereum.org)
- Don’t rely on require(msg.sender == tx.origin) in any code you touch. Audit for and remove it in integrated contracts. This check is no longer a reliable signal post-7702. (eips.ethereum.org)
- Enforce low‑s signatures and explicit nonces inside delegates; treat replay protection as your responsibility, not the protocol’s.
- Use EIP‑1153 transient storage for reentrancy guards in delegates; it’s built for exactly this cross-frame signaling and is cheaper. (eips.ethereum.org)
- Namespaced storage via ERC‑7201 to isolate modules, prevent collisions during future delegate upgrades, and simplify future migrations. (eips.ethereum.org)
UX integration:
- Give users a single “Delegation Center” in your wallet UI:
- Current state: delegated/not delegated, delegate address, last-used time.
- Session management: list active session keys, expirations, and quick revoke.
- “Clear Delegation” button that sends a Type‑4 auth with address(0). (eips.ethereum.org)
- Analytics: track Type‑4 share by user cohort, failure modes (invalid auth nonce, expired policies), and average gas overhead vs legacy two‑tx flows.
Tooling and infra:
- Libraries:
- viem: use signAuthorization to build tuples; ensure RPC supports eth_sendRawTransaction with type 0x04. (viem.sh)
- ethers: upgrade to v6.x with Type‑4 support; test authorization_list round-trips in your signer and JSON-RPC provider. (github.com)
- Indexing:
- Extend subgraphs/indexers to decode 0xef0100||address and show “delegates to D” for EOAs; treat delegated EOAs like contracts in your call-graph tools. Etherscan already exposes Pectra details, which your analysts can mirror. (info.etherscan.com)
Governance & deployment:
- Treat delegates like you treat core upgradeable contracts:
- Independent audits for each module (batching, sessions, guardians).
- Formal storage layout docs (ERC‑7201), invariant tests, and reentrancy proofs.
- Canary rollouts gated by feature flags; monitor tx.origin-related reverts in partner protocols for the first 72 hours.
When to use 7702 vs. full smart accounts (ERC‑4337 and modular standards)
-
Choose 7702 when:
- You need immediate UX fixes (batching, sponsorship) without address migration.
- Your ecosystem partners still assume EOAs (e.g., claim contracts, allowlists).
- You want time‑bounded capabilities (sessions, one‑shots) enforced at the app layer.
-
Choose smart accounts (4337, ERC‑6900/7579) when:
- You require pluggable validation across many modules, complex permission graphs, and native social recovery as a first-class feature.
- You want opt-in multi-signer or hardware-backed validation by default.
- You’re comfortable adopting the account as a new address and investing in module ecosystems.
Good news: 7702 was explicitly designed to be compatible with ERC‑4337 pathways—EOAs can “masquerade” as contracts and even be included in 4337 bundles when they delegate to compatible wallet code. Hybrid roadmaps are viable. (eips.ethereum.org)
If you later migrate to a fully modular account, standards like ERC‑6900 let you carry over session keys, permission modules, and hooks nearly as‑is; today’s 7702 delegates should be written with a future 6900 plugin in mind. (erc6900.io)
Integration quick-start (copy to your epic)
- Week 1:
- Upgrade wallets/SDKs to viem or ethers with Type‑4 support; add signer UX for “delegate to X (audited)”. (viem.sh)
- Implement a minimal OneShot delegate and deploy to testnets/mainnet with tight owner-only upgradability.
- Week 2:
- Roll out batch approve+swap flows; measure gas savings vs. two‑tx flows and drop-offs due to failed approvals.
- Add a session-key delegate for your highest-churn flow (e.g., in-game purchases) with a 60‑minute window and a $ cap.
- Week 3–4:
- Add guardian delegate for recovery/high‑risk; begin partner developer outreach to remove any msg.sender==tx.origin reliance.
- Implement “Clear Delegation” and a Delegation Center in your wallet UI.
Common failure modes to preempt
- “Why didn’t delegation disappear after my tx?” Because 7702’s delegation persists by design; temporary behavior is up to your delegate logic. Surface this in UX and educate users with explicit expiration/purpose of each grant. (eips.ethereum.org)
- “Our relayer got griefed.” You shipped sponsorship without receipts/bonds. Add sponsor-scoped nonces and require pre-funded bonds or reputation gating for sponsors. (eips.ethereum.org)
- “Partner contract reverted after Pectra.” They used tx.origin guards. Offer a code snippet PR to fix it and include it in your partner readiness checklist. (eips.ethereum.org)
Final take
EIP‑7702 gives you the best of both worlds: keep EOAs for compatibility, layer in smart validation when—and only when—you need it. If you adopt the patterns above (one‑shots, sessions, scoped approvals, guardians), you’ll deliver safer, cheaper UX this quarter, without waiting on end‑state AA debates.
Appendix: key constants and references you’ll actually use
- Type‑4 parameters: SET_CODE_TX_TYPE = 0x04; delegation indicator = 0xef0100 || address; PER_AUTH_BASE_COST = 12,500; PER_EMPTY_ACCOUNT_COST = 25,000; cold read = 2,600 gas; warm read = 100 gas. (eips.ethereum.org)
- Pectra mainnet activation: May 7, 2025 (epoch 364032) with client versions noted by EF. Share this with infra. (blog.ethereum.org)
- Use EIP‑1153 for reentrancy guards; use ERC‑7201 for storage namespacing; track Type‑4 txs in Etherscan; use viem/ethers for signing/sending 7702 transactions. (eips.ethereum.org)
If you want, 7Block Labs can drop a hardened 7702 Delegate Kit into your stack—audited one‑shot, session, and guardian modules with ERC‑6900‑compatible storage layouts—so your team ships in weeks, not quarters.
Like what you're reading? Let's build together.
Get a free 30‑minute consultation with our engineering team.

