Introduction
In the two previous articles of this series, we explored how the abilities of Ethereum's legacy accounts can be extended, whether by adding code to them or enabling them to be autonomous. One point we hope has been outstanding enough is that the mechanisms we've covered are improvements to the status quo of EOAs and contract accounts; they don't necessarily introduce a new account type (except for EIP-7702).
However, full account abstraction cannot be implemented with simple improvements to the status quo. It must be built from the ground up with new mechanisms and models. This is made possible with the introduction of smart accounts, whose abilities far supersede those of EOAs, 7702-type accounts, and contract accounts.
Keeping to Ethereum's infinite garden nature, there is no single path to implementing smart accounts. Multiple mechanisms exist, each with its advantages, disadvantages, and dependencies.
This article covers the four major models that enable smart accounts, whether as an out-of-protocol implementation (Endorsed operations via ERC-5189 and Alternative mempools via ERC-4337), or as a native/enshrined implementation (Native AA for rollups via RIP-7560 and L1 Native AA via EIP-7701).
We provide an overview of these mechanisms, a walk-through of their specifications, and comparisons between them to facilitate a deeper understanding of the topic for a wide range of readers. We hope you enjoy it. Read on…
ERC-5189: Endorsed Operations
ERC-5189 proposes the addition of endorser contracts to act as intermediaries between users of smart contract wallets and bundlers. These endorsers contain flexible validation/execution logic governing transactions sent from specific smart contract wallets. In this way, endorser contracts help bundlers determine valid fee-paying transactions by serving as a proxy for users to access the latter's mempools.
In the ERC-5189 standard, user transactions are packed in structs referred to as operations, which are made up of the following fields:

Users fill these fields with transaction variables and send the objects to a bundler's mempool. Predefined restrictions in the endorser contracts determine the validity of the users’ operation, typically customized to operate with specific smart contract wallet providers.
Through this approach, the standard permits flexibility for endorser contracts; for example, placing the bottleneck for validation on smart contract wallet providers ensures that such providers can easily add features to, or entirely replace their endorser contract, as necessary.
Below are the technical details, beginning with a rundown of the entities involved in the mechanism: the sender
/entrypoint
, the endorser contract, and the bundler.
Entities involved in an ERC-5189 operation
Entrypoints
These entities are the execution target of an ERC-5189 operation, just like the msg.sender
in “normal” Ethereum transactions.
Essentially, the end-user (entrypoint
) defines its desired state change through a callData
field, whose value's function is executed within it. It also specifies an endorser for the operation, which helps the bundler to check that the calldata
's logic is valid. After the bundler runs its checks, it executes the operation as an Ethereum transaction in which “entrypoint
” is called with the calldata
's function.
Endorsers
As we previously mentioned, the endorser is a deployed smart contract with an exposed interface that allows it to be trustlessly integrated with smart contract wallets, so that they can easily perform the validation aspect of operations sent by users.
interface Endorser {
struct Operation {
address entrypoint;
bytes callData;
uint256 fixedGas;
uint256 gasLimit;
address endorser;
bytes endorserCallData;
uint256 endorserGasLimit;
uint256 maxFeePerGas;
uint256 priorityFeePerGas;
address feeToken;
uint256 feeScalingFactor;
uint256 feeNormalizationFactor;
bool hasUntrustedContext;
}
struct GlobalDependency {
bool baseFee;
bool blobBaseFee;
bool chainId;
bool coinBase;
bool difficulty;
bool gasLimit;
bool number;
bool timestamp;
bool txOrigin;
bool txGasPrice;
uint256 maxBlockNumber;
uint256 maxBlockTimestamp;
}
struct Constraint {
bytes32 slot;
bytes32 minValue;
bytes32 maxValue;
}
struct Dependency {
address addr;
bool balance;
bool code;
bool nonce;
bool allSlots;
bytes32[] slots;
Constraint[] constraints;
}
struct Replacement {
address oldAddr;
address newAddr;
SlotReplacement[] slots;
}
struct SlotReplacement {
bytes32 slot;
bytes32 value;
}
function simulationSettings(
Operation calldata _operation
) external view returns (
Replacement[] memory replacements
);
function isOperationReady(
Operation calldata _operation
) external returns (
bool readiness,
GlobalDependency memory globalDependency,
Dependency[] memory dependencies
);
}
Endorsers are intended to be designed by wallet developers, as in-depth knowledge of a wallet's operation and storage space design is necessary to prevent failures. They primarily check that:
- The specified
entrypoint
is a valid contract account. - The
entrypoint
appends a valid signature to its operation. - The operation
calldata
is valid. - The operation repays the bundler after it is executed.
They are registered in an endorser registry, which serves the implied function — a central registry for identifying eligible endorsers. The registry is resource-gated, so addresses are only appended as eligible endorsers when they burn a non-zero amount of ETH. This also provides an avenue for bundlers to limit access to their mempools, as they can choose to provide their execution services to only endorsers who burn up to a specified amount of ETH.
Bundlers
Bundlers in ERC-5189 are responsible for processing account abstraction transactions sent to them as operation objects. They’re expected to:
- Maintain local mempools and wait for user operations.
- Call the appropriate functions on the endorser contract to validate operations.
- Pack validated operations into a block and execute them.
ERC-5189's design relies greatly on endorser contracts to provide spam filtration services and fee payment guarantees for bundlers. This approach effectively shields the latter from adversarial agents, unless the endorser itself is malicious.
Due to their positioning as a proxy between users and bundlers, endorsers are essentially privileged entities with the implied ability to grief bundlers and censor users. To limit this, bundlers can ban endorsers from their mempool when they:
- Mark an under-paying operation as ready for execution and cause losses to the bundler.
- Mark an invalid operation as ready, thus causing reverts/failures during execution.
- Change the readiness value of an operation while none of the operation's listed dependencies have changed.
In any of the scenarios above, the offending endorser is banned from the bundler's mempool, so the bundler will no longer execute their users’ operations. The offending endorser's pending operations are also dropped.
Below is an outline of the behaviours of the bundler and endorser through the three phases of an operation: pre-validation, validation, and execution.
Phases of an ERC-5189 operation
Pre-validation phase
The bundlers handle this phase since operations are streamed directly to them. These checks reduce the probability of operation failure down the line by stipulating that the bundler performs the following steps:
- Ensure the
endorserGasLimit
value of an operation's specified endorser is sufficiently low. This helps prevent endorsers from consuming too much gas in the validation phase and potentially griefing the bundler. - Ensure the endorser is unbanned and present in the endorser registry with a specified minimum burn. This step also protects the bundler from endorser-related sybil attacks.
- Check that the
fixedGas
value is enough to cover the cost associated with transaction submission and that thegasLimit
value is at least up to the cost of a normal [CALL
]. In this way, the bundler can avoid wasting resources on processing operations that may ultimately fail in the execution phase due tocalldata
mispricing. - Ensure the fee payment conditions are valid.
- Ensuring that the values of
maxFeePerGas
andpriorityPerGas
are above their acceptable minimum. This check addresses the problem of unprofitable block building for bundlers by ensuring operations pay enough fees for inclusion in a block. - Ensuring that a “replacement transaction” offers at least a 12% premium over the fees offered by the transaction to be replaced, to disincentivize bundler spamming.
The bundler runs these checks in the pre-validation phase to determine operations to be validated with the endorsers’ help in the second phase of the mechanism.
Validation phase
In this phase, the bundler calls the endorser contract to validate the operations being considered for execution. Endorser contracts validate operations before they are placed in a bundler's mempool. This is made possible through two functions:
simulationSettings()
isOperationReady()
.
These two are responsible for running pre-simulation checks and pre-execution checks, respectively. The bundler calls these functions on operations, and the endorser “does its thing.”
Below is a more technical look at the process to ease our understanding of what the endorser does in the context of each function and why every step is necessary.
simulationSettings()
:
This function returns modifications that must be made to onchain variables before execution is simulated offchain, in the bundler's local environment. The commonly targeted variables are the storage slots of smart contracts, such as token contracts, onchain price feeds, etc. The simulationSettings()
function tracks the token balances and nonces (among other things) of such contracts and returns alterations the bundler must apply to the operation before they simulate its execution offchain.
Thus, the function sets the stage for execution simulation by ensuring the bundler's local environment is consistent with onchain conditions.
To better understand the necessity of this function, it is necessary to remember that one of the primary objectives of any account abstraction mechanism is simplified transaction batching. One of the many applications of transaction batching is to deploy and call a smart contract atomically.
In the context of ERC-5189, since the contract hasn't been deployed onchain, it has no address. However, the simulation can only succeed because the contract already exists. To sidestep this issue, the endorser provides a (replaceable) address value when the simulationSettings()
function is called on a deploy + call operation.
In another scenario, users may wish to pay their fees with an ERC-20 token, another of the numerous objectives for account abstraction mechanisms. However, since bundlers don't access onchain state (due to the costs), there's no trivial way to verify that the user actually holds enough of their chosen ERC-20 token.
In this case, the endorser contract suggests a modification to the token's storage slot, so that the bundler is presented with a sufficient value for the simulation to proceed when the latter calls the simulationSettings()
function.
To bring it all together, the simulationSettings()
function helps bundlers process operations they receive efficiently by:
- Preparing the bundler's local environment for execution simulation.
- Returning a list of storage slots to be modified for a seamless simulation of the execution process.
isOperationReady()
:
This function is used to evaluate the validity of an operation in the bundler's mempool. It evaluates the probability of a pending operation's success and returns a boolean (true/false) value alongside a list of dependencies under which the value remains correct.
The return values of the isOperationReady()
function when called by a bundler are:
- Readiness - which presents a boolean value for an operation's “executionability”. Thus, it provides a true value if an operation is ready to be executed and will pay the bundler a specified minimum fee, and a false value if it isn't ready or doesn't pay up to a minimum fee.
globalDependency
- This data struct provides a list of general blockchain variables that can affect any transaction's validity. The most noteworthy portions of this struct are the fields “maxBlockNumber
” and “maxBlockTimeStamp
”, which can be used to constrain the validity of a submitted operation to a specific duration. Thus providing a “valid until x” functionality.- Dependencies - This second data struct is used to specify a list of more relevant/specific smart contract variables that must remain unchanged (or within certain bounds) for an operation's readiness value to remain valid. Due to the interdependence of smart contracts, certain variables –such as their balance and nonce– must be tracked to minimize failures that arise due to the bundler using an outdated state during operation execution.
Execution phase
This phase is relatively simple, as most of the complex work has been handled in the previous phases through numerous checks. To execute a validated operation in their mempool, the bundler submits a call to the entrypoint
contract's address. This call causes the logic of the function originally specified by the entrypoint
via the “callData
” field to be executed within the entrypoint
.
It is important to note that the bundler repeats this process for numerous operations to build a block, which is then passed to a proposer for attachment to the chain.
Fee-payment in ERC-5189
To enable gas abstraction or currency multiplicity with minimal overhead, the ERC-5189 mechanism is designed so that bundlers pay the network fees for users’ operations during its execution. This is possible through the endorsers, who ensure that operations specify an appropriate fee amount and token paid to the bundler after execution.
Below are the technical details around ERC-5189's fee payment mechanism.
Bundlers are expected to only execute operations endorsed for payment guarantees. The mechanism is designed to offer:
- A strong guarantee of fee payment for bundlers.
- Support for multiple currencies apart from ETH, e.g., ERC-20 tokens.
- Support for gasless transactions through services like Paymasters.
The bundler is expected to run the following checks during the pre-validation phase to ensure that operations are offering an appropriate fee:
- The
feeToken
must be ETH or some other acceptable/verified token contract, to prevent using fake ERC-20 tokens for gas payment. - The
feeScalingFactor
andfeeNormalizationFactor
must have values of “1” when ETH is used for fee payment, or at an acceptable conversion rate when other tokens are used. - The operation must be endorsed if the
sender
(entrypoint
) is paying their gas. - The paymaster in a gasless transaction must possess a collateralized/staked endorser.
From the discussions above, we can highlight that ERC-5189's fee payment mechanism supports three models:
- Self-paying ETH operations - This is the default nature of Ethereum transactions, in which the
entrypoint
settles their gas fees by paying ETH to the bundler for their operation's execution. - Self-paying non-ETH operations - The
entrypoint
settles their gas fees by paying the bundler in a token, which could be ERC-20, ERC-777, or any other niche token standard the latter is willing to accept. In this model, the bundler stipulates an exchange rate for the token's conversion to ETH, and the endorser verifies that theentrypoint
holds enough of the token during the validation phase. After execution, theentrypoint
then transfers the agreed value to the bundler. - Sponsored operations - In this model, a third-party, typically a gas relay service, is responsible for settling the
entrypoint
's gas fees in ETH. However, dApps that wish to subsidize their users can also serve as third parties.
Here, the operation's sponsor is validated by the bundler through its attached endorser, which provides the bundler payment guarantees.
ERC-5189 and the risks of an unlimited validation scope
While ERC-5189 is a great proposal with many benefits, taking the path of great flexibility in the validation phase imposes some security risks on the network. Though its pre-validation phase covers some attack vectors, such as mempool spam risks and gas over-consumption, it isn't all-inclusive.
Some other risks its design poses include:
- State-dependency of validation phase - The lack of explicitly forbidden opcodes means that an entity can submit an operation that depends on mutable state. The discrepancy that arises makes execution success unpredictable, as an operation's validation logic might change when included in a block, causing the block to fail and reducing mempool efficiency.
- Lack of global reputation system - Bundlers in ERC-5189 maintain a local mempool and can only outright ban an endorser from their mempool as punishment for misbehavior. There is no mechanism for a bundler to communicate to its peers that an endorser or
entrypoint
is malicious, as entities’ reputations are localized. Thus, an endorser can grieve multiple bundlers until all the bundlers in the network ban it. - Uncapped gas parameters - Since the proposal lacks a ceiling on the
gasLimit
value, an entity can budget for its validation, and the efficiency of the blocks built by bundlers in ERC-5189 can be greatly reduced. This is because the bundler loses out on the fees offered by other pending operations in its mempool.
Any account abstraction mechanism has to deal with the problem of over-/under-indexing on flexibility. For instance, how do you ensure the network and its operators remain safe without rigidly enforced rules?
ERC-5189 proposes that the bundlers, who execute transactions, should also be responsible for ensuring their safety, after all, they get paid for it. However, this free-market model might not work well in a distributed setting like Ethereum's, especially if the network still wants to maintain its valued decentralization. So what can be done?
As we've explored throughout this series, account abstraction mechanisms come in various forms, with different functionalities and goals. However, a shared property is that the validation of AA transactions occurs in the EVM, rather than at the consensus layer. This means some limitations can be placed on the accessibility of the EVM, to ensure that the entities involved in the scope of any AA model are protected from attacks and prevent the network from being grieved.
The ERC-7562 proposal provides the blueprint for these limitations by defining a suite of rules enforced during the validation phase of any account abstraction mechanism. You may wonder why these rules must be followed during the validation phase. The reason isn't as complex. When two transactions “collide” in their execution phase, both can be included in a block with one reverting, but both pay inclusion fees. However, when two transactions collide in their validation phase, they affect the entire block's validity and prevent the block builder from doing their job.
This approach sounds easy, right? Good. You can move to the end of the next section; it gets worse (or better if you're up to it) from here. We will briefly study these rules and then cover their practical applications in ERC-4337 and RIP-7560.
ERC-7562: Mindful validation of AA transactions
The features enabled by account abstraction are achieved by moving validity rule enforcement from the consensus layer to the EVM. Intuitively, this would require a considerable amount of work on each layer, where most of this work will be the deprecation or enshrinement of invariants as applicable to each layer, so that the changes don't reduce the network's integrity.
Most of these rules are defined in ERC-7562, which serves as an adjunct mechanism to aid account abstraction transaction executors (whether bundlers or any other entities) in correctly validating transactions sent to them. It introduces a suite of rules to prevent malicious behavior from entities in the network, either targeting each other or the network.
Before going into the specifications, it is important to note that ERC-7562 was originally designed for ERC-4337 alone, before being generalized to fit any AA mechanism's context. Consequently, most of its terminologies are derived from ERC-4337's specifications, even though the rules can apply to any other mechanism.
ERC-7562's rules are grouped into two broad groups:
- Network-wide rules - Include strict rules that must be adhered to by the affected entity. The violation of a network rule leads to a reduction of the entity's reputation score. Consequences may be throttling or banning, depending on the severity of the entity's actions.
- Local rules - Include “soft” optional rules that may increase the security guarantees of interactions amongst involved entities. Violating such rules does not put the network at risk or damage the associated entity's reputation.
Below is a dive into what these rules entail.
Network-wide Rules
These apply to each userOp
before they are accepted into a bundler's local mempool for execution and propagation. They define global restrictions on entities that can access the storage of other accounts and network opcodes.
Due to Ethereum's state model, transactions are interdependent but do not specify the states they touch upfront. This feature may lead to the invalidation of transactions that simultaneously wish to update the same state.
Ethereum's vanilla execution mechanism (wrt EOAs) deals with this aspect by limiting the validity conditions of transactions to an EOA's local environment. So that invalid transactions only impact the EOA, rather than the network or a block builder. However, nondeterminism in AA transactions is more problematic because they depend on mutable state by definition, which can be exploited to compromise the network.
The biggest challenge here is that a transaction from a smart account still incurs some validation cost, which the builder bears if the transaction is invalid. If this occurs frequently enough, it becomes too costly for the builder to build a profitable block, and they begin to lose their slots and impact the network's integrity.
The network can counter this challenge by explicitly dividing a transaction into two phases. One where the block builder isn't sure it is valid and the account hasn't committed to paying a fee and another where the block builder has validated the transaction and agreed to pay a minimum fee for block inclusion. This approach allows the network to place certain restrictions on the behavior of an account until they are responsible for the gas incurred.
These network rules are designed to limit the state access of AA transactions to prevent network grieving. The bundler must drop transactions that don't pass these checks during the first check. If the failure occurs during the second check, the offending entity's reputation in the network is degraded, and the entire transaction is excluded from the bundle. If a bundler executes and propagates a faulty transaction, its connection to other bundlers, via the bundlers’ p2p layer, is severed, and the offending bundler is marked as a spammer.
Network-wide rules are grouped into three classes according to what resource they intend to limit:
- Opcode rules: These are used to define which opcodes an entity specified in a [
userOperation
] struct can access (or not) while theuserOp
is being validated.
The rationale behind these limitations is that a validation simulation is performed locally by a bundler before bundle creation, and some opcodes can be used to access information revealed only during block creation.
Thus, an entity with access to such opcodes can cause the transaction to pass offchain simulations but revert onchain, effectively wasting the bundler's computational efforts.
- Storage rules: These define the limitations to an entity's storage access, be it an associated or external storage slot.
The rationale for storage access limitations is to prevent avoidable overlaps of userOp
s during the validation process, which could invalidate otherwise valid transactions.
Thus, limiting storage access for userOp
s to only certain associated accounts permits guaranteed inclusion for one userOp
per account in a single bundle.
- Code rules: A single code rule pertaining to any entity's executable content or its referenced accounts. It states that the code content of an entity involved in an AA transaction must not be changed after it has been validated.
This rule helps ensure that transaction validation is deterministic and can be easily replayed to prevent mempool bloat (due to failed transactions) and bundler griefing.
Entities that violate the rules above have their reputation reassessed.
This discussion brings us to the reputation system, its necessity, and how bundlers are expected to interact with themselves and other entities, based on their reputation scores.
The variables of the reputation system are defined thus:
opsSeen
- a per-entity counter of how often a unique valid [userOperation
] referencing a specific entity was received by a specific bundler.opsIncluded
- a per-entity counter of how often a unique valid [userOperation
] referencing a specific entity was included in an executed bundle.inclusionRate
- which defines the relation ofopsIncluded
toopsSeen
.max_seen
- which is defined as: [opsSeen // MIN_INCLUSION_RATE_DENOMINATOR
].
The first two variables are updated every hour as: [value = value * 23//24], and [MIN_INCLUSION_RATE_DENOMINATOR
] is a network-wide constant value of 100 units for clients and 10 units for bundlers.
The reputation-based rules derived from these values and used to ensure DoS-resistance for the bundler include:
- An entity is banned when: [
max_seen
>opsIncluded
+BAN_SLACK
], whereBAN_SLACK
is a constant value of 50 units. - An entity is throttled when: [
max_seen
>opsIncluded
+THROTTLING_SLACK
], whereTHROTTLING_SLACK
is a constant value of 10 units. - An entity's reputation is marked [OK] in every other case and begins in that state.
The reputation-based guidelines derived from these are as follows:
- A [BANNED] entity must not be allowed into the canonical mempool, and pending transactions that reference it are deemed invalid.
- A [THROTTLED] entity is limited thus:
- A total of four(4) transactions that can stay in the mempool as defined by
[THROTTLED_ENTITY_MEMPOOL_COUNT]
- A total of four (4) AA transactions that can be included in a bundle as defined by
[THROTTLED_ENTITY_BUNDLE_COUNT]
- A duration of ten (10) blocks over which its submitted transactions in the mempool are still deemed valid, and within which they must be included in a bundle or dropped as defined by
[THROTTLED_ENTITY_LIVE_BLOCKS]
- If an [OK] entity causes bundle creation to fail after the second validation cycle, its [
opsSeen
] value is set to[BAN_OPS_SEEN_PENALTY]
with a value of 10,000 units, and its [opsIncluded
] value is set to zero (0), causing it to be banned from the network.
An entity's possession of a stake in the system, verifiable via its [MIN_STAKE_VALUE
] and [MIN_UNSTAKE_DELAY
] fields’ values, allows it to circumvent the limitations of the reputation system to an extent. This statement implies that an [OK] entity can have unlimited transactions in the mempool and/or bundle.
Other entity-specific rules also exist for edge cases, as outlined in the specification.
So why are all these rules necessary? Entities used universally, such as aggregators and paymaster contracts, can be accessed and used by multiple AA transactions simultaneously because they typically facilitate the validation of multiple transactions per bundle and should be reusable by default.
However, an adversarial entity could abuse this privilege by revoking their support for a transaction's execution, causing mass invalidation of transactions that have undergone some processing. This causes wastage of the bundler's computational resources and reduces their efficiency. Furthermore, they can flood a bundler's mempool with seemingly valid transactions, then repeatedly cause them to revert during the bundling process.
To prevent this, locally defined (and enforced) reputation and stake systems are concurrently used to determine when to throttle or ban the use of an offending entity in the network. The reputation system enables bundlers to verify that a global entity is trustworthy, and the stake system makes it more expensive for adversarial entities to conduct serial sybil attacks on bundlers.
Local rules
These reputation-based guidelines protect the bundlers from sybils and DoS attacks while executing AA transactions and block-building processes.
They are considered “soft rules,” and transactions that fail the checks are immediately dropped from the bundler's mempool (i.e., not propagated or included in a block). However, the offending entity is never punished.
The two general local rules are:
- A
userOp
may not use an entity already specified as an associated account in a differentuserOp
in the bundler's mempool. - A
userOp
may not use the storage of an associated account if it is the [sender
] of a differentuserOp
in the bundler's mempool.
That's it (most of it, actually) for ERC-7562. It is now time to dive into ERC-4337 and highlight the reason(s) it “won” the out-of-protocol AA model race against ERC-5189 (spoiler: it was mostly due to its incorporation of ERC-7562).
ERC-4337: Out-of-protocol alternate mempools as a pathway to account abstraction
ERC-4337 was the first step taken to bring Ethereum's goal of account abstraction past the ideation stage, while presenting a roadmap towards the endgame for transactions on Ethereum. The initiative introduced an alternate mempool for new transaction structures called userOperations. These structs are packaged by bundlers –analogous to builders in the PBS vertical for MEV– and validated through an Entrypoint contract.
Like ERC-5189, ERC-4337 removes the need for transaction origination from EOAs, enabling contract accounts to be more autonomous. This allows such accounts to behave as “smart accounts,” without changing Ethereum's foundational mechanisms.
Before exploring the similarities and differences in both models of out-of-protocol AA-enabling mechanisms, let us explore the technical details of ERC-4337.
The ERC-4337 userOp
struct describes the transaction a user wishes to execute alongside other variables, as shown in the table below.

We will begin with an overview of the expected behavior and functionality of the entities in ERC-4337 — senders, the factory contract, the Entrypoint
contract (different from ERC-5189's entrypoint
), paymasters, aggregators, and bundlers.
Entities involved in an ERC-4337 userOp
Factory contract
As EOAs cannot be used in ERC-4337, first-time users may have to deploy a contract account that is “stateful” by convention. Essentially, the deployment and use of a contract account require changes to onchain state. This presents a dilemma for users who may wish to set up a new account without linking it to their EOA, as they have no way of making the necessary alterations and deploying their contract account.
This dilemma is circumvented in ERC-4337 by the factory contract, which efficiently deploys ERC-4337-compatible contract accounts (senders) on demand. The factory contract is called into action when a userOp
's initCode
field contains a non-zero value (this value is the account's desired deployment logic).
Under the hood, account creation through the factory contract is done using the CREATE2
opcode, so that the created account has a “deterministic” address (i.e., its address value can be known by the user beforehand) to which funds can be sent pre-validation. The gas fee for this is handled by a paymaster whose behavior we will cover soon.
Sender
The sender is the entity responsible for initiating a userOp
request; i.e., it sends a userOp
request that will be executed within it to the canonical 4337 mempool or an alt-mempool. Its core interface is set up as shown below:
interface IAccount {
function validateUserOp
(PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
external returns (uint256 validationData);
}
When a bundler calls it via the entrypoint
contract to begin the validation process, it must run the following checks:
- Validate that the call is made from a valid
entrypoint
contract. - Validate that the signature exposed by the
entrypoint
's interface is a valid component of the submitted [userOpHash
]. - If the signature is valid, the sender will pay the
entrypoint
contract a minimum deposit ofmissingAccountsFund
. This deposit is an approximation of the amount necessary to cover the processing of theiruserOp
request and can be overpaid. Excesses can be withdrawn after the execution loop –subject to a 10% penalty– by issuing awithdrawTo
call to theentrypoint
contract. - Alongside the minimum deposit mentioned above, the account has to return a struct containing the following elements:
- [
authorizer
] - which is the address responsible for providing a valid signature for theuserOp
. Otherwise, it returns an address for an aggregator, which will be specified as theauthorizer
when used. - [
validUntil
] - A 6-byte timestamp which is used to define the expiration of auserOp
s execution time frame; i.e., it specifies a time before which theuserOp
must be executed or else be considered invalid. - [
validAfter
] - This timestamp value is used to define the beginning of theuserOp
s validity duration; i.e., at [validAfter
], theuserOp
enters an execution time frame which ends at [validUntil
].
It is important to note that senders are limited to one userOp
per bundle, unless they possess a stake in the system and submit their requests to a bundler willing to accept and process multiple userOp
s from a single sender.
Entrypoint contract
This entity is a sort of “gatekeeper” for 4337 dedicated mempools. It is responsible for:
- Running checks on the pre-validation and validation logic of a [
userOperation
]. - Executing the sender's referenced
calldata
within the latter's account. - Enforcing upfront gas payment to bundlers.
It exposes the following interface, which is called by a bundler to begin the processing of userOps
:
function handleOps(PackedUserOperation[] calldata ops, address payable beneficiary);
function handleAggregatedOps(
UserOpsPerAggregator[] calldata opsPerAggregator,
address payable beneficiary
);
struct UserOpsPerAggregator {
PackedUserOperation[] userOps;
IAggregator aggregator;
bytes signature;
}
As shown in the pseudo-code above, either of the two separate entrypoint
models may be used depending on the sender's signature scheme:
- [
handleOps
] handles validation logic foruserOp
s initiated from accounts that require only a single signature for verification and authorization. - [
handleAggregatedOps
] is the secondentrypoint
model and is primarily responsible for providing the validation logic of batched [userOperation
] structs sourced from multiple aggregator contracts.
Its function is entirely similar to [handleOps
], However, the logic flow, which we will outline later on, is entirely different because it must transfer the correct aggregator to each userOp
, and then call [validateSignatures
] on each aggregator before proceeding with per-account validation checks.
The entrypoint
contract calls any of the functions above on the sender and begins the pre-validation phase.
Aggregators
A signature aggregator is a subsidiary contract that a bundler can trust to provide a single signature to validate multiple userOp
s. It has to be whitelisted by the network to be considered functional.
Their core functionality is to enable multiple [userOperation
] requests’ signatures to be combined into one signature that the bundler can easily check. This feature allows the bundler to validate multiple userOp
s in one process, reducing execution costs.
The userOp
's [sender
] signifies it uses a signature aggregator when validateUserOp()
is initially called on it (during local simulation by the bundler) by returning its aggregator's value as part of an aggregatorInfo
struct.
The bundler then checks that the aggregator is whitelisted, staked, and not throttled or banned. If the aggregator passes these checks, the bundler proceeds by:
- Calling
validateUserOpSignature()
- validates the signature presented by eachuserOp
. - Calling
aggregateSignatures()
- creates a single signature for all theuserOp
s that use the same aggregator in a bundle.
Summarily, signature aggregators enable the bundler to run “aggregateSignatures()
”, which aggregates all the signature schemes used by multiple userOp
s into a single value. The bundler then calls validateSignatures
through the Entrypoint
contract, allowing it to ensure the signature is correctly implemented.
Paymasters
The paymaster
is a second subsidiary contract that enables trustless abstraction of gas fee payments for userOp
structs. They are designed to charge users a premium over the expected fees for executing a userOp
, in a supported asset of the user's choice; the excess is refundable if the user requests it at any point.
The primary application of gas fee abstraction in ERC-4337 is that users can create an account that implements specialized logic (through the factory contract), without needing to fund the charged state rent from a personal EOA. In this way, users can generate accounts locally, just like EOAs, but have the account implement specialized logic, just like contract accounts.
If a userOp
leverages a paymaster
contract, the verification loop is modified so that the handleOps
call also checks that the contract has a sufficient ETH deposit at the Entrypoint
contract to pay for the request's execution. If the paymaster
has a sufficient deposit, validatePaymasterUserOp
is called to verify that the paymaster
is willing to pay for the request's execution.
Like aggregators, paymasters have access to the global state by default. They can signify support for as many userOp
s as possible in a bundle. This grants them a grieving attack vector where the paymaster can signify support for a userOp
's inclusion in a bundle, then retract it midway through execution, causing invalidation of the userOp
and waste of the bundler's compute power.
To prevent such mass invalidation attacks, the system throttles paymasters by default, restricting their storage access and placing an upper bound on the number of userOp
s they can support for each parsed bundle. However, paymasters can access more storage by holding a stake in the system.
Bundlers
These are entities responsible for end-to-end processing of userOp
s; i.e., the bundler:
- maintains a 4337-type mempool and listens for
userOp
s, - validates
userOp
s by running checks and calling other involved entities as necessary, and - packs them into a bundle for top-of-the-block atomic execution.
Below is an overview of the lifecycle of a userOp
across the three phases of the ERC-4337 mechanism from the perspective of the bundler.

Phases of an ERC-4337 userOp
Pre-validation phase
Bundlers are expected to run a local simulation upon receiving a userOp
to verify that its signature is correct and an adequate amount of fees is offered for execution.
The process for each userOp
in a bundler's mempool occurs in the following manner:
- Checking that the
userOp
has a valid [nonce
] field: As ERC4337 lays the foundation for two-dimensional nonces in Ethereum, a bundler who wishes to include multipleuserOp
s from the same sender in one bundle has to track both the [key
] and [sequence
] pair for eachuserOp
from the sender. However, tracking the [key
] value is enough if they only wish to include oneuserOp
per sender in each bundle. - Checking that the [
sender
] is either an extant contract or that theuserOp
has an [initCode
] value: If the sender already exists, the bundler parses its first twenty bytes as a factory address and records whether it has a stake in the system. If it doesn't exist, the bundler’shandleOps
call deploys an account at the sender's address using the details provided in theinitCode
field. If an account doesn't exist and the [initCode
] field is empty, the entire call immediately fails. - Checking that the [
sender
] offers enough gas for each step in theuserOp
: The bundler must calculate the total amount of gas the sender (or paymaster) should pay for the calls made by itsuserOp
, alongside the fee the account must deposit at theentrypoint
. It then checks that the account holds a minimum of the returned value. - Checking that the [
paymasterAndData
] field is either empty or begins with an address for the paymaster contract if the field is populated. In the case that the sender uses a paymaster, the bundler must check that the specified contract:
* has nonempty code onchain
* has a sufficient ether deposit to pay for the userOp
* is not throttled or banned.
- Checking that the
callgas
value is nonzero and that it is at least the cost of a general [CALL
] opcode. - Checking that the configurable minimum values of [
maxFeePerGas
] and [maxPriorityFeePerGas
] offered by a sender are within a value they are willing to accept, which at the minimum should be equivalent to the current base fee of the latest block. - Finally, unless the bundler supports multiplicity, they must check that every single sender has no other
userOp
already in their mempool, or that a newuserOp
is intended to replace the existing entry. In the latter case, the newuserOp
must have the same values for [sender
] and [nonce
], but with increased [maxFeePerGas
] and [maxPriorityFeePerGas
] values.
These checks are implemented to ensure the individual validity of each object in a [userOperation
] struct before the bundler parses them.
The validation phase proceeds as described in ERC-7562, so we'll just move on to the execution phase.
Execution phase
After passing the validation loop, the [userOperation
] is called through an execution loop by [handleOps
]. The execution loop proceeds thus:
- The account with [
userOperation
]’scalldata
is called by thehandleOps
function, allowing the account to specify how thecalldata
will be parsed for execution. Optimally, accounts should have an [execution
] function that can perform this as a series of calls. - The parsing function may also be left to the
entrypoint
. The account enables this by having itscalldata
start with themethodsig
– [IAccountExecute.executeUserOp
], which allows theentrypoint
contract to build acalldata
struct by encoding [executeUserOp (UserOp, UserOpHash)
]. Thecalldata
obtained from this process is then used to call the account. - After the call, the account is refunded the excess of their deposit during the validation loop for the pre-charged gas cost. This refund is subject to a 10% penalty, which disincentivizes blockspace hoarding.
- After execution, the fees collected from all parts of the [
userOperation
] are paid to the bundler's provided address.
During a bundle's creation, the bundler is expected to:
- Exclude
userOp
s that access the [sender
] address of anotheruserOp
in the same batch. This is to ensure that the sender's state remains constant during execution. - Sort
userOp
s by the paymaster contract they use –if any– and keep track of each paymaster's balance. This enables it to check that the paymaster can easily pay for all theuserOp
s that use it in a bundle. - Sort
userOp
s by the aggregator they use –if any– and then run the aggregator-specific code for each one to create the correct aggregated signature for eachuserOp
.
These measures prevent collisions between interdependent userOp
s and their associated contracts.
After building a full bundle and before sending it to a block producer, bundlers are to run a second check in the following manner:
- Run [
debug_traceCall
] to enforce the validation rules on opcode and storage access, and verify the entire batch. - If the previous call is reverted before completion, the bundler is to find the offending entity using the returned results and remove the entity's associated
userOp
from the bundle and its mempool. - If the reversion was due to a [
factory
] or [paymaster
] contract, and the [sender
] has no stake in the system, the bundler issues a ban on the former as applicable. If the [sender
] has a stake in the system, the bundler bans them instead.
The rationale behind these subsequent checks is that staked entities are granted more transient storage access, and this privilege could be abused to communicate data between userOp
s in the same bundle, which effectively grieves the system.
So that's it for ERC-4337. The table below summarizes the differences between ERC-5189 and ERC-4337.

RIP-7560: A synergistic approach to native AA on Ethereum rollups
The biggest drawback ERC-4337 presents to everyday users is the high cost of processing the most basic userOp
s (a whopping 42k gwei compared to the 21k gwei of basic EOA transactions). This high cost intuitively limits its usability and adoption to a select few willing to pay the fees for the features granted by smart accounts.
Furthermore, the inability of ERC-4337 to benefit from protocol upgrades –the most obvious being stricter censorship-resistance guarantees in the form of crLists– leaves its users at the risk of censorship, which can only worsen if the mechanism reaches mass adoption in its current form.
To address these issues and further affirm Ethereum's commitment to the rollup-centric roadmap, RIP-7560 was introduced. The mechanism is a summarized ERC-4337-compatible version of EIP-2938; it adapts the latter to fit into the former mechanism's convention, while addressing the biggest challenges smart accounts currently face.
RIP-7560 introduces the first in-protocol implementation of validation-execution separation into explicit phases using “method selectors”. In Solidity code, these method selectors are simple and cost-effective representations of a function (to be clear, they are the first four bytes of the keccak256 hash of a function's signature). In RIP-7560, these method selectors are used to “point” to specific calls that must be made by/to a smart account when a transaction from the account is being processed.
The logic of these calls is implemented on the network's execution layer; i.e., both the validation and execution of RIP-7560-type transactions occur on the EVM, albeit in distinct phases.
RIP-7560 transactions are initiated by smart accounts as an EIP-2718-compliant object (AA_TX_TYPE
) with two distinct phases: validation and execution. Each consists of multiple call frames depending on the complexity of the account's request. They are sent to the public mempool (or any other “traditional” transaction processing mechanism) through RPCs, from where they are processed by block builders and proposers.
The absence of a third-party responsible for transaction processing (e.g., ERC-5189's endorsers and ERC-4337's bundlers) eliminates the need for a pre-validation phase.

Below is an overview of the phases of an RIP-7560 transaction alongside their respective frames to better understand their mechanisms.
Validation Phase
During this phase, the values of the objects sent to the mempool by a smart account, as part of an AA_TX_TYPE
, are evaluated for correctness. It consists of the following frames:
- [
sender
] deployment - In this frame, theAA_SENDER_CREATOR
(which, intuitively, is responsible for making calls to create smart accounts) invokes a [deployer
] (similar to the factory contract in ERC-4337) with the value of [deployerData
]. This call transforms the [sender
] into a smart account and can only happen once for every account. - [
sender
] validation - This frame consists of two sub-calls:
AA_ENTRY_POINT
calls thevalidateTransaction
function on the sender, causing it to:
i. Authenticate its identity using the appropriate [authorizationData
] value
ii. Run nonce checks
iii. run gas checks (if a paymaster
isn't specified)
- The sender relays a callback to
AA_ENTRY_POINT
, using any of the following functions:
i. acceptAccount
, which shows that the sender has verified the objects of an AA_TX_TYPE
and will pay the gas for its execution.
ii. sigFailAccount
, which shows that the sender cannot authenticate itself (i.e., it used an incorrect [authorizationData
] value).
In the case that a sender passes the validation phase, it returns two values to AA_ENTRY_POINT
alongside the acceptAccount
callback
validAfter
andvalidUntil
(same function as in ERC-4337)
Any other scenario, such as:
- The sender making multiple calls to
AA_ENTRY_POINT
- sender making no calls to
AA_ENTRY_POINT
- sender making any other call apart from
acceptAccount
leads to the transaction being invalidated and dropped.
- [
paymaster
] validation - In this frame, the paymaster (if one is used) is validated and expected to explicitly signal its agreement to settle the gas fees for the sender's transaction. It begins with a call to the specified paymaster fromAA_ENTRY_POINT
with avalidatePaymasterTransaction
function, which causes the paymaster to assess the transaction and return either one of two callbacks:
acceptPaymaster
, which means a paymaster is willing to pay for the specified transaction's inclusion in a block. If a paymaster returns this call, it must also specifyvalidAfter
andvalidUntil
values, alongside a context value. The context field is intended to store any additional data that a paymaster may need for accounting purposes in the post-transaction phase.sigFailPaymaster
, which means a paymaster isn't willing to settle a transaction's execution fee, whether due to validation or accounting errors between it and the sender. If a paymaster returns this call, the transaction is dropped and not included in a block.
Execution phase
Upon completion of the validation phase, the execution phase begins, wherein the execution payload executionData
is passed to the sender, and the paymaster arranges their books.
- In the first frame, the sender executes the payload's embedded function call as follows:
(sender).call(executionData);
After this, the transaction proceeds to the post-transaction frame. - The post-transaction frame caters to paymaster contracts by providing a mechanism to assess the success of transactions executed in the previous frames and calculate the actual gas cost incurred. This allows them to perform accounting and access data that could inform their future optimizations.
Arguably, the biggest feature introduced in RIP-7560 is a departure from EIP-3607— the ability of smart accounts (which implicitly contain code) to pay their gas fees by themselves. Essentially, reinstalling smart accounts in the network as fully autonomous entities, from deployment to management.
While we'll restate the benefits of this development later on, let us first examine how gas settlement occurs in RIP-7560.
Due to the removal of intrinsic ECDSA-based verification for transactions, there is no need for the ecRecover mechanism to be called on AA_TX_TYPE
transactions; rather, their gas is represented as maxPossibleGasCost
, which incorporates:
- An
AA_BASE_GAS_COST
of 15k gas units, representing the minimum amount of gas a smart account must offer for any transaction. - A
validationGasLimit
, whose value is provided by the user with the aid of their wallet provider (as is the case with EOA transactions). This value is the maximum they are willing to pay for their transaction's inclusion. It is based on the complexity of the transaction and an estimate of onchain conditions. ThevalidationGasLimit
depends on four variables:executionData
,paymasterData
,deployerData
, andauthorizationData
. In the validation phase, the block builder computes the values of these four variables and adds them to the transaction's cost ascalldataGasUsed
. The transaction is considered invalid and dropped if the user's estimatedvalidationGasLimit
is less than the block builder's computedcalldataGasUsed
. - A
paymasterValidationGasLimit
, which serves as a ceiling on the gas spent by the paymaster (if one is used) during the paymaster validation frame. It must be greater than or equal to the value ofpaymasterValidationGasUsed
- a
callGasLimit
, a ceiling on the amount of gas that can be spent during the sender execution frame. It must be greater than or equal togasUsedByExecution
. - A
paymasterPostOpGasLimit
, which serves as a ceiling on the amount of gas the paymaster can spend in the post-transaction frame.
The maxPossibleGasCost
may be charged directly from the sender's balance or a paymaster, through either a validateTransaction
or validatePaymasterTransaction
function call. The gas cost for AA_TX_TYPE
transactions is charged in the validation phase to prevent DoS attacks.

Lowering the stakes of RIP-7560 implementation on rollups via RIP-7711
Since RIP-7560 targets rollups, it is important to make it as adaptable as possible to accommodate the wide range of existing and potential rollup designs.
One aspect of RIP-7560 that must remain as general as possible is the separation of the validation and execution windows of a transaction being processed.
Most rollups implement a single-sequencer model where transactions are streamed to a single entity that executes them in the order they are received. However, other rollups may use a public (or even private) mempool that grants their users a higher extent of censorship-resistance.
Block builders find it harder to identify a transaction whose execution phase may invalidate other pending transactions in the builder's mempool in rollups employing private or public mempools. RIP-7711 comes in as a solution to this issue. It provides a mechanism for block builders to specify AA_TX_TYPE
transactions that can be bundled so they don't “collide” with each other in the validation phase.
In RIP-7711, the validation and execution phases of AA_TX_TYPE
transactions (referred to as BUNDLE_TRANSACTION_TYPE
) are granted non-atomicity. This means that, rather than processing an AA_TX_TYPE
transaction included in a set of BUNDLE_TRANSACTION_TYPE
from start to finish, the builder completes the entire set's validation phase before moving to their execution phase. Thus, a block builder can efficiently build blocks of non-colliding AA_TX_TYPE
transactions.
If implemented alongside ERC-7562, using the BUNDLE_TRANSACTION_TYPE
mechanism enables a block producer to avoid execution collisions while detecting validation collisions, so that the appropriate punishments for (potentially) adversarial state access can be applied to entities more easily.
EIP-7701: The Endgame for L1 accounts
As noted in the previous section, the separation of validation and execution in RIP-7560 is achieved using solidity method selectors. While this is a nothingburger for rollups, it cannot be replicated on the mainnet due to the higher stakes involved at such a level.
To be more specific, using solidity method selectors means the language-agnostic property of the execution layer is compromised, leaving the protocol susceptible to attacks at the compiler level (while this has a somewhat low chance of occurring, it is nonzero, as evidenced by the Vyper incident).
Therefore, native AA models on the mainnet must take a much more sophisticated approach. One such approach under consideration is account abstraction via the EVM object format (EOF).
So far, EOF has proven to be a very controversial upgrade due to the complexity it introduces. However, we will avoid an in-depth analysis of the mechanism or even debating its perceived merits here to avoid introducing more complexity to this article. Instead, the following section outlines the properties of EOF and how they enable account abstraction. We shall also evaluate EIP-7701, which employs EOF smart accounts to bring account abstraction to Ethereum L1.
The definitive features of the EVM object format are:
- Logic containerization: Enabling EVM bytecode to execute in a strictly deterministic manner.
- Code versioning: Enables backwards-incompatible changes to the EVM's specifications, with limited risks of network downtime.
The former feature, logic containerization, is our major focus here, as it enables smart accounts to explicitly define their validation and/or execution logic and ensure they don't overlap. The first version of the mechanism (EOFv1) introduces containerization as “code-data separation”, enabling code deployed according to its specification to be initialized onchain with two main types of fields:
- Section headers: Define what a section is or does and its parameters.
- Section kinds: Define a code or data payload.
The explicit separation of code and data through this mechanism enables EVM bytecode to be deployed in an extensible and versioned manner. Changes to bytecode logic can be made in a backwards-compatible manner, and a bytecode's logic is guaranteed to be valid according to the EOF's version rules.
EOFv1's code sectioning can be applied to the RIP-7560 mechanism to explicitly assign code sections to specific entities, so that rather than using the complex call-and-callback method between entities and AA_ENTRY_POINT
, entities are explicitly limited to a specific logic as follows:
- Only the deployer can call the data and code fields assigned to them.
- Only the sender can call their validation and execution code.
- Only the paymaster can call their validation code.
Any other unassigned code section is exposed as call-able by other accounts, and entities cannot call any other function not assigned to them. Thus, enabling granular definition of the context within which some value is to be processed.

Ethereum: Everything is abstraction
Now that we've covered how these models work and have an average understanding (or, maybe more) of how account abstraction works, let us reiterate that this has always been the goal of transacting on Ethereum.
If we are to assume that the Ethereum account dilemma has been ostensibly solved due to the intensive research being carried out across these models, then what can we do now? How do these models differ from legacy accounts, and do these differences even matter?
The short answer is that there are a lot of improvements, and they all matter. The longer answer, however, is in the next section, where we map the developments covered here and going back to the original abstraction article published by Vitalik.
Abstraction in practice
Cryptography
This section outlines Vitalik’s approach to validation-agnosticism in transactions. Simply put, any account abstraction model should be able to move beyond the intrinsic ECDSA-based verification loop that EOA transactions are subjected to.
ERC-4337 provides a means for this, as do RIP-7560 and EIP-7701. Their separation of validation and execution phases enables a “plug and play” model that users can leverage to introduce other signature schemes for their transactions. This enables the use of better optimized schemes while paving the way for quantum-resistant schemes.
Some use cases opened up by this improvement include:
- Common authentication mechanisms such as passkeys, biometrics, etc., mostly cater to the average user.
- Zero-knowledge authentication policies. These will better serve Ethereum and its rollups in its eventual move to statelessness.
- BLS-based authentication policies, which will serve dApps that may seek to optimize their contracts.
- Quantum-resistant authentication policies that will ensure the protocol's safety in a post-quantum world.
An understated part of the improvement in this aspect is the ease of asset recovery in case of key loss, a virtually impossible task in the legacy model. By utilizing a rotating key model, a social recovery mechanism, a multisig-based authentication mechanism, or any other possible mechanism, a user can easily regain access to their assets after losing their primary keys.
Trie/State model
This section discusses the pitfalls of Ethereum's stateful model regarding transactions. The root of the problem, as we have mentioned earlier, is that transactions may “collide” during their validation phase, leaving the network at risk of DoS attacks.
This problem is extensively solved by the rules laid out in ERC-7562 that limit the state that transactions can access while being validated and allow the network to support account abstraction securely.
Currency
The case for this is simple: a permissionless network should be able to support multiple currencies. Otherwise, it still has a lesser resistance to state-capture and other forms of censorship. This type of development is harder in a Proof-of-Stake network where the protocol enshrines the fee mechanism to ensure DoS-resistance. However, Ethereum hardly backs down from challenges.
ERC-4337, RIP-7560, and EIP-7701 all solve the currency multiplicity problem by supporting self-validating paymaster contracts, which users can subscribe to using a gas currency of their choice. This is further extended through the use of the Entrypoint contract in ERC-4337, and the protocol-level AA_ENTRY_POINT
in RIP-7560 and EIP-7701, which collect the gas for transactions upfront, rather than waiting till execution is completed or reverted.
This approach facilitates currency multiplicity without introducing DoS attack vulnerabilities. It allows users to transact even when they do not have ETH because other agents can sponsor them, the dApp they wish to access, or even pay the block builder using a non-ETH currency.
Conclusion
This narration marks the end of our series on account abstraction in Ethereum. We focused on the primary mechanisms that enable adding features to legacy accounts or introduce new account standards. In the future, we might dive into other mechanisms that build on these to provide other functionalities such as cross-chain messaging systems, chain-specific addresses, and modular smart accounts.
Acknowledgements: Special thanks to Daniel Ayuko for review and feedback. We also appreciate SafeDAO for funding work on this report via the OBRA program.