ERC-7562 Account abstraction validation scope rules

Review · Accounts & wallets · created 2023-09-01

Defines the restrictions that UserOperation validation code must follow in ERC-4337 account abstraction, to prevent denial of service (DoS) attacks in which a flood of fee-free requests overwhelms bundlers and the public mempool.

Why it is needed

A regular account (EOA) transaction only needs its balance, nonce, and signature checked, and once a transaction is confirmed valid, it cannot become invalid without that account paying a fee. This makes mass-submission attacks economically infeasible, since costs spiral. Account abstraction, by contrast, performs validation using arbitrary EVM code that can depend on storage or block information. This makes it possible to craft a UserOperation that passes in the mempool but fails when included in a block, and a single storage change could invalidate huge numbers of unrelated UserOperations at once. An attacker can pay almost no fees while dumping free computation on bundlers, making it computationally infeasible to maintain a mempool containing only valid UserOperations. Also, if spam criteria differ from node to node, nodes may end up treating each other as spammers, splitting the network, so a shared validation rule across all nodes is needed.

In depth

Separation of the validation phase and the execution phase

The validation phase consists of up to 3 on-chain frames: the sender deployment frame (once per account), the sender validation frame (required), and the paymaster validation frame (optional). The execution phase consists of the sender execution frame and the paymaster's postOp frame. The rules in this document apply only to the validation phase. Because a UserOperation that passes validation is guaranteed payment, there are no restrictions on execution code such as the account's callData or the paymaster's postOp. Each validation frame is attributed to a single entity, such as a factory, paymaster, aggregator, or staked account, and the entity's contract must have code already deployed on-chain.

Opcode restrictions

Because validation happens off-chain before a block is produced, opcodes that read information that varies by block are blocked. ORIGIN, GASPRICE, BLOCKHASH, COINBASE, TIMESTAMP, NUMBER, PREVRANDAO, GASLIMIT, BASEFEE, BLOBHASH, BLOBBASEFEE, INVALID, and SELFDESTRUCT are on the forbidden list (OP-011). The GAS opcode is only allowed when immediately followed by *CALL (OP-012), and out of gas reverts that could reveal the gas limit are also forbidden (OP-020). CREATE2 is only allowed exactly once, in the deployment frame, when deploying the sender address's code (OP-031). Accessing an address with no code is forbidden, except for the sender address itself (OP-041, OP-042). A CALL that sends value is forbidden except when sent to the EntryPoint (OP-061), and only the core precompiles 0x1 through 0x11 and P256VERIFY are allowed (OP-062). EIP-1153 transient storage (TLOAD/TSTORE) is treated the same as persistent storage (OP-070), and BALANCE and SELFBALANCE can only be used by staked entities (OP-080).

Storage access rules

Storage that can be accessed during validation via SLOAD, SSTORE, TLOAD, and TSTORE is restricted. An account's own storage is always allowed (STO-010). If a slot's value equals an address A, or the slot location is computed as keccak(A||x)+n (n from 0 to 128), that slot is treated as A's associated storage. Associated storage of an account located in an external contract may be accessed if the account already exists (STO-021), or if it has initCode and the factory is staked (STO-022). If the paymaster or factory is staked, additional access is allowed: access to its own storage (STO-031), reads and writes to its own associated slots in non-entity contracts (STO-032), and read-only access to all storage in non-entity contracts (STO-033). Scoping access to the account's associated range in this way prevents a single storage change from invalidating many UserOperations.

Staking and Reputation Calculation

An entity used in common across many operations needs staking to write to storage outside its account-associated range. A staked entity is one that has locked at least MIN_STAKE_VALUE (chain-specific, roughly $1000 recommended) with an unstake delay of at least MIN_UNSTAKE_DELAY (86400 seconds, 1 day). Bundlers count opsSeen (number of times a valid UserOperation was received) and opsIncluded (number of times it was actually included) per entity, and decay both values hourly by value * 23 // 24 so that after 4 days they fall to about 1%. max_seen is computed as opsSeen // 10; if max_seen exceeds opsIncluded + 50 (BAN_SLACK) the entity is BANNED, and if it exceeds opsIncluded + 10 (THROTTLING_SLACK) the entity is THROTTLED. THROTTLED entities are limited to 4 operations in the mempool, 4 per bundle, and 10 blocks of mempool residency, and all UserOperations from a BANNED address are removed from the mempool. Stake is not slashed and is used only for off-chain detection, but locking funds significantly raises the capital cost of a Sybil attack.

Two Rounds of Validation and Blocking Spammers

A bundler must run full validation once before accepting a UserOperation into the mempool, again before placing it in a bundle, and must also run a third simulation tracing the entire bundle before submission. This is because rules ensure unstaked entities cannot change behavior between simulation and execution, while a malicious staked entity could detect that bundle validation is underway and cause a revert. If a UserOperation received over P2P fails in the current block, it is retried against the block hash under which it was originally validated; if it succeeds there, it is silently dropped while the connection is kept, but if it still fails, the sending peer is permanently banned as a spammer. There are two kinds of rules. Violations of network-wide rules lower the sending peer's reputation, while violations of local rules (STO-040, STO-041), whose state differs per bundler, do not affect reputation.

Entity-specific Detailed Rules

An unstaked sender may have at most 4 UserOperations (SAME_SENDER_MEMPOOL_COUNT) in the mempool at a time (UREP-010). The allowance for an unstaked paymaster is opsAllowed = SAME_UNSTAKED_ENTITY_MEMPOOL_COUNT (10) + inclusionRate * min(opsIncluded, 10000), which grows as its inclusion track record accumulates (UREP-020). An unstaked paymaster cannot return a context (EREP-050), and an aggregator must always be staked regardless of its storage usage (EREP-040). A bundler must track the total of the maximum gas costs of all UserOperations in the mempool that use a given paymaster, ensuring it does not exceed that paymaster's deposit (EREP-010). There are also rules (EREP-015, EREP-016) that prevent a factory's or account's failure from unfairly raising a paymaster's or aggregator's opsSeen, and a rule (EREP-020) that attributes validation failures of a UserOperation with initCode to the staked factory responsible.

EIP-7702 Delegation and Alt-mempools

A UserOperation may contain at most one EIP-7702 authorization tuple (AUTH-010). An account delegated via EIP-7702 may only be used as the sender of a UserOperation and not as any other kind of entity (AUTH-020), and access to it via *CALL or EXTCODE* opcodes is allowed only when that account is the sender of the current UserOperation (AUTH-030). If the mempool contains multiple authorization tuples for the same sender, they must all point to the same delegate address (AUTH-040). Separately, bundlers may participate in alt-mempools that carry separate consensus rules in addition to the canonical mempool. An alt-mempool's topic is identified by the IPFS hash of its rules document, and only UserOperations that violate the canonical rules are checked against alt-mempool rules (ALT-020). An entity's opsSeen and opsIncluded are tracked separately per alt-mempool, so an entity banned in one mempool can still be active in another (ALT-040).

Size and Gas Limits, and the Standard's Current Status

There are size limits so that bundle construction does not hit the EVM's memory expansion limits. A single UserOperation, after packing and ABI encoding, must not exceed 8192 bytes (MAX_USEROP_SIZE); the context a paymaster returns is capped at 2048 bytes per operation (MAX_CONTEXT_SIZE) and 65536 bytes across the whole bundle (MAX_BUNDLE_CONTEXT_SIZE). A handleOps bundle call must not exceed 262144 bytes (MAX_BUNDLE_SIZE). verificationGasLimit and paymasterVerificationGasLimit must each be below MAX_VERIFICATION_GAS (500000) and must leave a margin of VALIDATION_GAS_SLACK (4000) over actual validation gas usage. preVerificationGas must be high enough to cover the UserOperation's serialized calldata gas plus PRE_VERIFICATION_OVERHEAD_GAS (50000). This standard is currently in Review status, so its contents may still change.

Things to watch out for

Original ERC · ← ERCs