Abstract
EIP-8141 defines a new EIP-2718 transaction type and a set of rules such transactions need to follow in the canonical public mempool. These canonical mempool rules are chosen to be relatively simple and universal in a way that enables a number of high priority use cases. Other rulesets can exist to serve use cases made impossible by the canonical mempool rules, however without a public mempool such transactions would require a private submission mechanisms. This document defines a framework for alternative mempools with customized validation rulesets for EIP-8141 Frame Transactions. The rulesets define which transactions a node may admit to the mempool, which it rejects, and how it tracks the entities that form a transaction's validation process.
This document also defines the standard alternative mempool, a default ruleset for a permissionless and decentralized public Frame Transactions mempool that is less restrictive than the canonical one.
Motivation
A frame transaction replaces a hard-coded signature check with EVM code that runs during a validation prefix. Before a mempool node relays such a transaction, it must execute the entire validation prefix code. If the prefix depends on mutable state that anyone can change, a single state change can invalidate many pending transactions at once, and a node that spends resources on those transactions is never paid. This is the mass invalidation attack. Mempools must put in place carefully designed sets of rules to bound this threat.
ERC-4337 relies on rules defined in ERC-7562 to solve the same problem for UserOperations.
Frame Transactions differ from UserOperations in ways that make defining a shared rule set inconvenient.
This document defines the Frame Transaction specific mempool rules in a way that maintains a full backward compatibility with use cases that existed in ERC-4337, like autonomous ERC-20 Token Paymasters, privacy pool withdrawals and more.
Specification
Constants
| Name | Value | Description |
|---|---|---|
MAX_VERIFY_GAS_PER_ENTITY | 100_000 | Maximum execution gas budget for a single unstaked or default-code entity's validation frames. |
MAX_VERIFY_GAS_STAKED_ENTITY | 1_000_000 | Maximum execution gas budget for a single staked entity's validation frames. |
MIN_UNSTAKE_DELAY | 86400 | One day. A withdrawal delay long enough to deter most Sybil attacks. |
MIN_STAKE_VALUE | per-chain | A non-trivial but not excessive amount, roughly the equivalent of USD 1000 in the native token. |
SAME_NONCE_KEY_MEMPOOL_COUNT | 4 | Maximum pending transactions that select the same (sender, nonce key) pair (EIP-8250). |
SAME_SENDER_MEMPOOL_COUNT | 64 | Maximum pending transactions from one unstaked sender, regardless of how many nonce keys they select. |
SAME_UNSTAKED_ENTITY_MEMPOOL_COUNT | 10 | Base number of pending transactions that may reference the same unstaked sponsoring payer. |
THROTTLED_ENTITY_MEMPOOL_COUNT | 4 | Pending transactions allowed for a throttled entity. |
THROTTLED_ENTITY_LIVE_BLOCKS | 10 | Blocks a transaction referencing a throttled entity may stay in the mempool. |
THROTTLED_ENTITY_BLOCK_COUNT | 4 | Transactions referencing a throttled entity that a node may include in one block it builds. |
MIN_INCLUSION_RATE_DENOMINATOR | 10 | Denominator in the reputation formula. |
THROTTLING_SLACK | 10 | Lets an entity legitimately fail some transactions without being throttled. |
BAN_SLACK | 50 | Lets a throttled entity fail some transactions without being banned. |
MAX_TXS_ALLOWED_UNSTAKED_ENTITY | 10000 | Upper bound on included when computing the allowance of an unstaked sponsoring payer. |
STAKING_REGISTRY_ADDRESS | per-chain | Address of the Staking Registry contract (see Staking Registry Contract). |
Mempool Types
This document relates to three distinct types of mempool rulesets for Frame Transaction mempools:
- The canonical public mempool, as defined by EIP-8141 in the Mempool section.
- The standard alternative mempool, as defined by this document.
- The non-standard alternative mempools, which are defined by third party mempool operators as defined in Alternative Mempools section.
A transaction that violates a canonical public mempool rule MUST NOT be propagated over the public mempool, as EIP-8141 requires. It may only be propagated over the appropriate alternative mempool's own transport if it satisfies its rules. One transaction may be propagated over multiple alternative mempools if it satisfies all of their rules.
Alternative Mempools
The standard alternative mempool defined by this document is not the only possible rule set. Node operators may agree on alternative mempools, rule sets that a node opts into in addition to the standard mempool. Each alternative mempool is identified by its own topic, conventionally the IPFS hash of a document that describes its rules. A transaction that violates a standard rule MUST NOT be propagated in the standard mempool, but may be propagated in any alternative mempool whose rules it satisfies. Reputation counters (seen and included) should be kept separately for each mempool, so that an entity that is throttled in one mempool is unaffected in another.
Rule Types
Public transaction mempools are distributed among multiple nodes in a peer-to-peer network, while each node maintains its own view of the mempool and participant reputations at all times. Additionally, certain nodes may choose to act as solo submission channels with custom rules but without a connection to a peer-to-peer network. Therefore, there are two types of validation rules: network-wide rules and local node rules.
A violation of any rule by a frame transaction results in the transaction being rejected from submission or dropped from the mempool if necessary, and therefore prevented from being included in future blocks.
A peer-to-peer mempool networks rely on participant reputations to limit the threat of mass transaction invalidation. A network-wide rule is a rule whose violation by a transaction damages the reputation of the peer that sent that transaction into the standard mempool. A peer with critically low standing is treated as a spammer according to the Propagation Rules.
A local rule depends on a node's own mempool contents and its local tracking of entities' reputations. Different nodes may hold different mempool contents, so no consensus is possible and peers are never penalised for a local rule violation. Local rules are collected in the Local Rules section, and all other rules are network-wide.
Definitions
- Validation prefix: the shortest prefix of a transaction's frames whose successful execution sets
payer, as defined by EIP-8141. All Frames that appear after the validation prefix regardless of their type belong to the execution body of the Frame Transaction and are largely outside this document's scope. - Validation frame: a frame in the validation prefix regardless of its mode, type or scope.
- Frame Subclasses: a heuristic classification of a Validation Frame within a Frame Transaction based on its role and behaviour in the transaction validation process.
The EIP-8141 mode subclassifications defines the following subclasses:
self_verify,only_verify,pay,expiry_verifyanddeploy; thepre_verifysubclass is additionally defined in this document. - Entity: a smart contract that a Validation Frame executes directly. Entities are defined by their role in a transaction, similarly to Frame Subclasses:
- The sender is
tx.sender. It runs theself_verifyoronly_verifyframe. - The payer is the resolved target of the frame that calls
APPROVEwith a payment scope. It runs thepayframe, or theself_verifyframe if sender and payer is the same entity. - The factory is the resolved target of the
deployframe. Every validation frame is attributed to exactly one entity. Anexpiry_verifyframe is attributed to no entity as its code is protocol-defined.
- The sender is
- Default-code entity: an entity whose account has the empty code hash and therefore executes EIP-8141's default code. It has no bytecode to trace, is never staked, and is exempt from the opcode, call and storage rules.
- Staked entity: an entity that has a stake of at least
MIN_STAKE_VALUEand an unstake delay of at leastMIN_UNSTAKE_DELAY, as reported by the Staking Registry smart contract, and whose stake is not being withdrawn. - Associated storage: a storage slot of any contract is associated with a given address according to the Associated Storage Rules.
- Canonical paymaster: a contract whose runtime code exactly matches the canonical paymaster implementation defined by EIP-8141.
- Admission validation: the simulation a node performs before it first accepts a transaction.
- Revalidation: a re-simulation of a pending transaction against a newer head or a candidate block, as described in Replacement, Eviction and Revalidation.
- Spammer: a peer that attempts to exhaust the mempool network by sending a large number of transactions that were never valid.
- Mass invalidation attack: a series of actions by which a large number of transactions, having passed admission validation and propagated through the mempool network, later become invalid and ineligible for inclusion.
Execution Model
VERIFY frames run in static mode.
The non-static DEFAULT mode frames in the validation prefix are allowed for two subclasses:
- The
deployframe as defined in EIP-8141 - The
pre_verifyframe
Rules in this document that mention writes, contract creation or value calls consequently take effect only in those frames.
The pre_verify frame subclass
A pre_verify frame is a DEFAULT-mode frame whose resolved target is the same as the resolved target of the approving VERIFY frame (self_verify, only_verify, pay) that immediately follows it. Each approving frame MAY be preceded by at most one pre_verify frame.
A pre_verify frame is distinguishable from the deploy frame as it does not create code in the tx.sender address.
The code of an approving VERIFY frame that is preceded by a pre_verify frame MUST check the status of that pre_verify frame before it calls APPROVE, using the frame status parameter of FRAMEPARAM, and MUST NOT call APPROVE if that status is not success.
According to EIP-8141, a failed DEFAULT mode frame does not invalidate the transaction even if it is reverted in the validation prefix, so without this check the approving frame would approve after the state writes it depends on had been reverted. Although mempool nodes reject at admission a transaction whose pre_verify frame does not succeed in simulation, smart contracts cannot rely on mempool rules for their security.
Staking Registry Contract
Stake is kept in a specialized designated contract at STAKING_REGISTRY_ADDRESS.
It implements the following interface:
interface IStakingRegistry {
/// Lock `msg.value` as the caller's stake, with the given unstake delay.
function addStake(uint32 unstakeDelaySec) external payable;
/// Begin the withdrawal delay. From this point the caller is not considered to be staked.
function unlockStake() external;
/// Withdraw the stake after the delay has passed.
function withdrawStake(address payable withdrawAddress) external;
/// Return the stake information.
function getDepositInfo(address account)
external
view
returns (uint256 stake, uint32 unstakeDelaySec, uint64 withdrawTime);
}Associated Storage Rules (ASSOC)
Several rules below grant an entity broader access to storage that is associated with it, rather than only to a contract's own account storage. Associated storage identifies the slots a well-behaved contract is expected to use to track state for a specific address, such as an ERC-20 balance mapping keyed by that address, without requiring the contract to declare in advance which slots those are.
- [ASSOC-010] A storage slot of any contract is associated with address
Aif the slot's own value equalsA. - [ASSOC-020] A storage slot of any contract is associated with address
Aif the slot was computed askeccak256(A || x) + n, wherexis abytes32value andnis an integer in the range 0 to 128. This covers the common Solidity mapping and dynamic array layouts keyed or indexed byA, together with a fixed run of slots reachable from them.
A node determines storage association by testing the slots a validation frame has actually accessed using specialized simulation and tracing interfaces.
Validation Prefix and Structure (PREFIX)
-
[PREFIX-010] The validation prefix MUST match one of the following shapes. A transaction whose prefix does not match any of them MUST be rejected.
[self_verify][deploy, self_verify][only_verify, pay][deploy, only_verify, pay]
In every shape, each approving frame (
self_verify,only_verifyorpay) MAY be immediately preceded by onepre_verifyframe, as [PREFIX-110] describes. An optional singleexpiry_verifyframe is always allowed as the first frame of the validation prefix. -
[PREFIX-020] If a
deployframe is present it MUST be the first frame of the prefix, not counting a leadingexpiry_verifyframe. There is at most onedeployframe. Thedeployframe MUST result in a successful deployment of thetx.sendercontract. -
[PREFIX-040] No frame in the validation prefix may carry
ATOMIC_BATCH_FLAG. -
[PREFIX-050] No
VERIFYframe may follow the validation prefix. -
[PREFIX-060] A transaction MUST be rejected if any validation frame reverts, or a
VERIFYframe exits without its requiredAPPROVE. -
[PREFIX-080] A node MUST reject or drop a transaction whose
expiry_verifydeadline is earlier than the node's view of the current block timestamp. -
[PREFIX-100] The following types of frames are exempt from alt-mempool rules: frame whose target is a default code account, a canonical paymaster, or the
EXPIRY_VERIFIERcontract. A node MAY evaluate them directly instead of simulating them. It MUST still apply the same limits it would apply normally. -
[PREFIX-110] The target of a
pre_verifyframe MUST have deployed code. -
[PREFIX-120] The
DEFAULTmode frame in the validation prefix that is neither thedeployframe nor apre_verifyframe MUST cause the transaction to be rejected.
Budgets (BUDGET)
- [BUDGET-010] A node MUST track the sum of
limits.executionseparately per entity, over that entity's own validation frames. Thepre_verifyframe counts toward the entity of the approving frame it immediately precedes. The intrinsic cost of validatingtx.signaturescounts toward thetx.sender. For unstaked entities, that sum MUST NOT exceedMAX_VERIFY_GAS_PER_ENTITY. For staked entities, that sum MUST NOT exceedMAX_VERIFY_GAS_STAKED_ENTITY.
Signatures (SIGNATURE)
- [SIGNATURE-010] Before simulating any frame, a node MUST validate every protocol-validated signature (
SECP256K1,P256(EIP-7951)) against its own signed message: the transaction's signature hash whenmsgis empty, or the explicit digestmsgcarries otherwise. A transaction with any invalid signature MUST be rejected.
Opcode Rules (OPCODES)
Every validation frame is bound by the banned opcodes of EIP-8141's Validation Trace Rules, except for the frames [PREFIX-100] exempts. This section lists only the differences.
- [OPCODES-010]
BALANCE(0x31) andSELFBALANCE(0x47) are allowed for a staked entity. They remain banned for every other entity. - [OPCODES-020]
SSTOREis not banned outright. The Storage and State Access rules decide which frames may write and where. - [OPCODES-030] Any unassigned opcode is blocked.
- [OPCODES-040] A revert on "out of gas" is forbidden, because it can leak the gas limit or the call-stack depth.
Contract Creation (CREATION)
- [CREATION-010]
CREATE,CREATE2andSETDELEGATE(EIP-7819) are allowed only inside thedeployframe, and only to install code attx.sender. Any one of these opcodes may be executed at most once, and it MUST install code fortx.sender.
Calls and Code Access (CALLING)
- [CALLING-010] Using an address that has no deployed or default code is forbidden.
- [CALLING-040] Precompiles that access nothing in the blockchain state or environment are allowed. These include the core precompiles
0x01to0x11and theP256VERIFYprecompile.
Storage and State Access (STORAGE)
Storage access by SLOAD, SSTORE, TLOAD and TSTORE is restricted as follows. Note that storage writes are possible only in deploy and pre_verify frames. Transient storage (EIP-1153) accessed with TLOAD and TSTORE is treated exactly like persistent storage accessed with SLOAD and SSTORE.
- [STORAGE-000] Access to storage is always restricted unless allowed by one of the following rules.
- [STORAGE-010] Access to
tx.sender's own storage is always allowed. - Access to storage associated with
tx.senderin an external contract that is not an entity of the transaction is allowed if either:- [STORAGE-021] the sender's account already exists, meaning the transaction has no
deployframe; or - [STORAGE-022] the transaction has a
deployframe and the factory is a staked entity.
- [STORAGE-021] the sender's account already exists, meaning the transaction has no
- If an entity is staked it is additionally allowed:
- [STORAGE-031] access to its own storage;
- [STORAGE-032] read-only access to any storage in a contract that is not an entity of the transaction.
- [STORAGE-033] write access to slots associated with the entity address in any contract that is not an entity of the transaction;
Local Rules (LOCAL)
These rules depend on the other transactions in a node's own mempool and have no network propagation effects. A node applies them when it admits a transaction. A transaction that violates one is rejected without any reputation change for the peer that sent it.
- [LOCAL-010] A transaction MUST NOT use as its factory or its sponsoring payer an address that is
tx.senderof another pending transaction in the mempool. A factory or paymaster contract can therefore not also serve as an account. - [LOCAL-020] A transaction MUST NOT use storage associated with its sender, or with a staked entity, in a contract that is
tx.senderof another pending transaction in the mempool.
Stake (STAKING)
Note that there are no penalization mechanisms in the alternative mempools protocol and the stake is never slashed. It exists only as a configurable mechanism for sybil attack prevention. The significant lock-up period introduces capital cost of creating new abusive entities.
- [STAKING-010] An entity is staked if the Staking Registry reports for it a stake of at least
MIN_STAKE_VALUEand an unstake delay of at leastMIN_UNSTAKE_DELAY, and withdrawal has not been initiated.
Payer Solvency (SOLVENCY)
- [SOLVENCY-010] For every payer, including the sender when it pays for itself, a node MUST track
reserved_pending_cost(payer), the sum of the maximum costs of every pending transaction in its mempool that names this payer. A node MUST reject a transaction ifavailable_balance(payer)is less than its maximum cost, whereavailable_balance(payer) = balance(payer) - reserved_pending_cost(payer). - [SOLVENCY-020] For a canonical paymaster,
available_balanceadditionally subtractspending_withdrawal_amount(paymaster), the amount of any delayed withdrawal currently pending in that paymaster. - [SOLVENCY-030] On admission a node increases
reserved_pending_costby the transaction's maximum cost. It decreases it on eviction, replacement, inclusion and removal by reorg. When a replacement changes the payer, the node moves the reservation to the new payer atomically with the replacement.
Reputation (REPUTATION)
Definitions
seen: a per-entity counter of how many times this node received a unique valid transaction that references the entity. It counts transactions received over RPC and over the mempool network. Admitting a replacement for an existing pending transaction is not a new occurrence for this purpose; [REPUTATION-040] governs it instead.included: a per-entity counter of how many transactions that were previously counted inseenfor that entity were included in a canonical block. A node determines this from the block's transactions and receipts.- Refresh rate: every hour, both counters are updated as
value = value * 23 // 24. The effect is a practical reputation reset after four days of entity inactivity. inclusionRate: the ratio ofincludedtoseen.
An ACTIVE staked entity faces no additional limit under the reputation rules. There is no cap on its pending transactions, or on its transactions in a block a node builds. An entity whose transactions are frequently not included loses its reputation, until declines below a certain threshold and gets additional limitations.
Calculation
Let max_seen = seen // MIN_INCLUSION_RATE_DENOMINATOR. The following conditions partition every entity into exactly one reputation state:
- BANNED:
max_seen > included + BAN_SLACK - THROTTLED:
included + THROTTLING_SLACK < max_seen <= included + BAN_SLACK - ACTIVE:
max_seen <= included + THROTTLING_SLACK
A new entity starts as ACTIVE. Reputation is tracked per entity address, not per role. The refresh rate limits an entity's organic climb toward BANNED, allowing a relatively small number of invalid transactions per hour without any penalties.
Let opsAllowed = SAME_UNSTAKED_ENTITY_MEMPOOL_COUNT + inclusionRate * min(included, MAX_TXS_ALLOWED_UNSTAKED_ENTITY), the pending-transaction allowance for an unstaked sponsoring payer ([REPUTATION-220]). For a new entity, with included = 0, this is SAME_UNSTAKED_ENTITY_MEMPOOL_COUNT.
General rules
The following rules apply to all staked entities and to unstaked sponsoring payers.
- [REPUTATION-010] A
BANNEDaddress is not allowed into the mempool. Every pending transaction that references it is removed. - [REPUTATION-020] A
THROTTLEDaddress is limited toTHROTTLED_ENTITY_MEMPOOL_COUNTentries in the mempool, toTHROTTLED_ENTITY_BLOCK_COUNTtransactions in a block the node builds, and toTHROTTLED_ENTITY_LIVE_BLOCKSblocks of residency in the mempool. - [REPUTATION-040] Admitting a replacement is not a new occurrence of
seenfor any unchanged entity. If the replacement changes thepayer, thefactory, or both, the node decrements each changed role's old address'sseenby 1 and increments its new address'sseenby 1, atomically with the replacement.
Unstaked entities
- [REPUTATION-210] A
THROTTLEDsender is limited toTHROTTLED_ENTITY_MEMPOOL_COUNTpending transactions in total, regardless of how many nonce keys it uses. - [REPUTATION-220] An unstaked sponsoring payer that is neither
THROTTLEDnorBANNEDmay have at mostopsAllowedpending transactions in the mempool.
Blame attribution
The alternative mempool system tracks which entity was the one responsible for a transaction that has been previously admitted to the mempool to become invalid. This is done by detecting the exact VERIFY frame in the validation prefix that changes its behaviour and no longer executes the expected APPROVE opcode call.
- [REPUTATION-310] If a transaction fails revalidation because of the
factoryor thesenderentities, the sponsoringpayer'sseenis decremented by 1. Apayermust not lose reputation because of another entity's failure. - [REPUTATION-320] If a staked
factoryis used and thesender's validation frame fails, thefactory'sseenis not decremented under [REPUTATION-310]: it absorbs the failure in its owninclusionRate, exactly as if its own frame had failed. - [REPUTATION-330] If a staked
senderis used, its reputation is affected by failures of all other entities of the transaction, even if those entities are staked.
Replacement, Eviction and Revalidation (LIFECYCLE)
-
[LIFECYCLE-010] A pending transaction is identified by
(sender, nonce_keys, nonce_seq), as defined by EIP-8250. A node MAY admit a transaction only if itsnonce_seqis the next contiguous sequence value for each key in itsnonce_keys: either the key's on-chain sequence,current_nonce_seq(sender, key), or one more than thenonce_seqof a pending transaction of the same sender that selects that key. Forming a nonce gap on any key is not allowed. -
[LIFECYCLE-020] Two transactions of the same sender conflict if they have the same
nonce_seqand theirnonce_keysshare at least one key, as at most one of them can ever be included. The mempool MUST NOT hold two conflicting transactions. A transaction that conflicts with one or more pending transactions is a replacement for all of them. A replacement MUST be valid under every rule in this document. A node SHOULD accept and propagate it only if it increases bothmax_fee_per_gasandmax_priority_fee_per_gasby at least 10% over each transaction it replaces. A replacement MAY name a different factory or payer contract. On accepting a replacement, a node removes every transaction it replaces, and evicts every pending transaction of the sender that no longer satisfies [LIFECYCLE-010]. -
[LIFECYCLE-030] A node MUST keep at most
SAME_NONCE_KEY_MEMPOOL_COUNTpending transactions that select any one(sender, key)pair. A transaction with severalnonce_keyscounts once against each of its keys. A node MUST keep at mostSAME_SENDER_MEMPOOL_COUNTpending transactions of an unstaked sender, regardless of how many nonce keys they select. A staked sender has no sender-wide limit whileACTIVE; [REPUTATION-020] limits it once it isTHROTTLED.These limits count only the keys selected by pending transactions. Because the mempool never holds conflicting transactions, a replacement releases every key that a replaced transaction selected and the replacement does not. For example, replacing a pending transaction with
nonce_keys = [1, 3, 5]by one withnonce_keys = [1, 5]at the samenonce_seqreleases key3: a new transaction may select key3at its on-chain sequence, and a pending transaction that selected key3at the next sequence is evicted under [LIFECYCLE-020]. -
[LIFECYCLE-040] When a new block is accepted, a node MUST remove the transactions the block includes and update payer reservations. It MUST revalidate every pending transaction that depends on state the block changed.
This includes at least:
- transactions for the same sender
- transactions whose recorded storage dependencies changed
- transactions whose payer's balance or code changed
- transactions that reference an entity whose stake status changed
A transaction that no longer satisfies the rules MUST be evicted. To optimize the revalidation flow, a node should record, for each admitted transaction, the set of state it depended on: the storage slots read, the code, balance and nonce of every address whose value the validation used. It should use this set to select the transactions that require revalidation, without the need to re-validate the others.
Propagation (PROPAGATION)
The wire protocol is out of scope for this document. The following rules apply to any transport that carries transactions between nodes of the standard mempool.
- [PROPAGATION-010] A transaction is broadcast with two items: the transaction itself, and the block hash against which it was last validated.
- [PROPAGATION-020] A node that receives a transaction from a peer MUST validate it locally before it propagates it.
- [PROPAGATION-030] If a received transaction fails a static check, such as an invalid encoding, a value below a minimum, or an outdated block hash, the node drops it and keeps the connection.
- [PROPAGATION-040] A node silently drops a transaction that conflicts ([LIFECYCLE-020]) with a transaction recently included in a block. This is almost certainly a network race. It causes no reputation change.
- [PROPAGATION-050] If a received transaction fails against the current block, the node should retry validation against the block named in the transaction's message. If it succeeds, the node silently drops the transaction and keeps the connection. If it fails this is an indicator of a peer propagating a known invalid or incompatible transaction payload. The node should mark the sending peer as a spammer, disconnect from it, or block it permanently.
Acceptance Algorithm
A node applies the rules in this order:
- Validate the signatures.
- Determine the validation prefix and check its structure.
- Resolve each entity's role, address and stake ([STAKING-010]) and check reputation.
- Simulate the prefix and trace it, applying [OPCODES], [CREATION], [CALLING] and [STORAGE] rules to every validation frame.
- Check payer solvency and reserve the cost.
- Check the local rules, the per-sender limitations
- If the transaction is a replacement, apply the replacement rules.
- If every check passes, record the dependency set, admit the transaction and propagate it.
Rationale
Relationship to the public mempool
EIP-8141's public mempool is deliberately narrow, which is the correct choice for a protocol consensus affecting rules in a decentralized network. However, such a narrow ruleset cannot host a wide range of useful applications of the core Frame Transaction architecture: a shielded pools with Merkle roots as paymasters, registries of authorised signers, or an ERC-20 token paymaster with budgeting code and its own storage. Stake and reputation give a node what the public mempool lacks by design: an economic cost for creating an abusive entity, and a mechanism that throttles an entity once it causes invalidations.
Because the standard mempool extends the public mempool rather than replacing it, the two stay consistent. A wallet author who targets the public mempool needs no knowledge of this document.
Rationale for per-entity verification gas budgets
A single combined gas budget for the whole validation prefix, as EIP-8141 uses, cannot be raised for a staked entity without also raising it for every unstaked entity in the same transaction, since the rule only sees one sum. The alternative mempool tracks the sum separately per entity instead, so a staked payer, sender or factory can be given MAX_VERIFY_GAS_STAKED_ENTITY, a materially higher allowance for more expensive validation logic such as signature aggregation or a Merkle proof check, while every unstaked entity of the transaction remains bound by MAX_VERIFY_GAS_PER_ENTITY, exactly as it would be in a transaction with no staked entity at all.
No cap on state gas
EIP-8141 caps limits.state (EIP-8037) at MAX_VERIFY_STATE_GAS across the validation prefix. This document places no cap on state gas. A payer's solvency check already reserves the cost of every frame's declared limits.state, so a large budget is paid for, and the prefix structure already limits where state can be written. A deploy frame that needs a large state gas budget for a code deposit can declare it without hitting a mempool-specific limit.
Keyed nonces and per-sender limits
EIP-8250 keyed nonces let one shared sender serve many independent users, typically a privacy protocol in which every user selects a fresh nonce key at sequence 0. Every such transaction selects its own key, so SAME_NONCE_KEY_MEMPOOL_COUNT never binds, and only the sender-wide limit bounds the sender. That limit applies to unstaked senders only. A staked sender is already accountable for every failure of its transactions ([REPUTATION-330]), so a mass invalidation of its pending transactions throttles it, and [REPUTATION-020] then bounds it as it bounds any other staked entity.
Treating any two transactions that cannot both be included as a replacement keeps the pending transactions of a sender free of conflicts, so a node can track each key's pending sequences independently, and a limit on a key counts only the transactions that actually select it.
State modifying pre_verify frames
ERC-4337 validation functions may write storage, under the same associated-storage and stake rules that govern reads. One common use is a paymaster that pulls ERC-20 tokens from the sender during validation, so that it is reimbursed before it commits to pay. VERIFY frames are static, so the same guarantee needs a non-static frame that runs first.
The pre_verify subclass marks such a frame, binds it to one approving frame so that each write is attributed to an entity, and allows only one per approving frame. Attribution lets the storage and reputation rules apply to writes exactly as they apply to reads.
Mitigating the mass invalidation attack
The mass invalidation attack can be carried out in any of the three ways listed in its definition. To prevent them, validation code runs in a sandbox. It is isolated from other transactions, from external storage changes, and from environment information such as the block timestamp.
A transaction that fails admission validation and never enters the mempool is not an attack. Nodes are expected to apply ordinary measures against spam, such as throttling by API key, IP address, or peer score. An attack is also not considered economically viable if invalidating N transactions costs the attacker N * X for a sufficiently large X.
Backwards Compatibility
The rules in this document preserve the ERC-4337 use cases that ERC-7562 made possible, even though neither the EntryPoint contract nor a UserOperation structures or handleOps bundles exist. Each of those use cases depended on a specific relaxation of the mempool's validation rules, and this document keeps the equivalency of restrictions and relaxations with ERC-7562.
A contract written against ERC-7562's rules therefore needs no change in its core validation architecture to adopt Frame Transactions.
The differences are concentrated in the exposed interfaces, where for example validateUserOp and validatePaymasterUserOp calls are replaced by self_verify/only_verify and pay frames respectively, and initCode execution is replaced by the deploy frame.
This document introduces no consensus change and requires no change to EIP-8141 or the FOCIL rules of EIP-7805 and similar. It does not modify ERC-4337 or ERC-7562.
Security Considerations
Staking Registry. The stake provisions depend on a registry contract outside the EIP-8141 protocol. Correctness of the deployed Staking Registry contract is critical for the security of the entire alternative mempool system.
Staked entities can misbehave temporarily. A staked entity can cause a bounded amount of invalidation before its reputation drops. The bound is BAN_SLACK * MIN_INCLUSION_RATE_DENOMINATOR / 24 invalid transactions per hour, plus whatever throttling then allows. It is a rate limit, not a guarantee.
pre_verify frames run before approval. A pre_verify frame is called by ENTRY_POINT, before any APPROVE has happened, so nobody has been authorised yet. The target of a pre_verify frame SHOULD check that the transaction's sender, as reported by TXPARAM, is the party whose state it is about to change.
A failed DEFAULT frame in the validation prefix does not invalidate the transaction automatically. Only VERIFY failures do, so a pre_verify frame that reverts on-chain lets the transaction continue. The approving frame MUST check the pre_verify frame's status. A node cannot check the requirement, so a payer that ignores it bears the loss.
Approval covers all following SENDER frames. sender_approved is a single transaction-scoped flag. Once it is set, every SENDER frame in the transaction executes as tx.sender, not only the frame the approving code inspected. Wallet code that approves execution SHOULD bind its approval to the whole frame list, for example by verifying a signature over the canonical signature hash, which commits to every frame. A signature over an explicit digest that does not commit to the frame list authorises an open-ended set of SENDER frames.
ARBITRARY signatures. The protocol does not validate them, so a transaction that carries one is only as trustworthy as the frame that inspects it.
Canonical paymaster. A canonical paymaster is exempt from the trace rules and admitted by code match. This puts a lot of responsibility on the canonicalized code's correctness.
Default-code payers. A payer with no code is bounded only by the solvency rules. A sponsor that moves its balance elsewhere between admission and inclusion invalidates every pending transaction it sponsors, up to the balance it appeared to hold. Reservation limits the exposure to the payer's balance at admission time and does not remove it.
Revalidation load. A new head can force many revalidations. The lifecycle rules allow a node to select only the affected transactions. A node that ignores the filtering of affected transactions would expose itself to a load attack proportional to the size of its mempool.
Copyright
Copyright and related rights waived via CC0.
