A deep dive into the main components of ERC-4337: Account Abstraction Using Alt Mempool — Part 2
Welcome back to our exploration of ERC-4337: Account Abstraction Using Alt Mempool. In our previous post, we analyzed the Bundler, highlighting its role in receiving and executing UserOperations as bundled transactions, introducing the concept of the “Alt Mempool”.
This part will focus on another integral component of ERC-4337: the EntryPoint. For newcomers, we recommend starting with Part 1 for a comprehensive understanding.
The EntryPoint
The EntryPoint contract is one of the main components of ERC-4337, serving as a trusted singleton by bundlers, wallets, and paymasters, being responsible for validating and handling UserOperations.
One of EntryPoint’s main responsibilities is ensuring that once validation is successful, the operation will be executed, the wallet or the paymaster will be charged, and the Bundler will be reimbursed regardless of the operation’s outcome.
The structure also includes a reputation system that holds paymasters accountable for post-reversion failures, subject to throttling or banning.
Handling User Operations
The EntryPoint
implements many functionalities defined in the ERC draft. Two main functions, handleOps
and handleAggregatedOps
, are responsible for executing batches of user operations. The first function is used when no signature aggregation is required, while the second is used when a signature aggregator is needed for the operations.
handleOps
This function handles a batch of user operations and compensates for the beneficiary
account with the collected gas fees.
Inside the first loop, it calls _validatePrepayment
, which validates the account and paymaster (if defined) and makes sure the total validation doesn’t exceed the UserOperation's verificationGasLimit
. This function internally calls _validateAccountPrepayment
, which is responsible for creating the wallet contract through _createSenderIfNeeded
. Interestingly, this allows for ERC-4337 wallets to receive assets at a pre-determined counterfactual address even before they are deployed.
A second verification function is called, _validateAccountAndPaymasterValidationData
, which reverts if either the account or paymaster validationData
is expired.
In the second loop, _executeUserOp
is called for each operation, which calls this.innerHandleOps
, which executes the UserOperation calldata
on the wallet contract.
The post-operation is called just after the calldata
is executed. If a paymaster is defined and its validation returns a non-empty context, its postOp
is called. The excess amount is refunded to the account (or paymaster — if it was used in the request).
handleAggregatedOps
The handleAggregatedOps
function is used to handle a batch of aggregated UserOperations, and compensates the beneficiary
with the collected gas fees.
This function is very similar to handleOps
, with the main difference being that it attempts to validate the signatures using the aggregator’s validateSignatures
function before proceeding with _validatePrepayment
, _validateAccountAndPaymasterValidationData
, and _executeUserOp
.
Managing Deposits and Stakes
In order to guarantee that the beneficiary
of handleOps
and handleAggregatedOps
will be reimbursed, the EntryPoint
needs to manage entities' deposits and stakes. For such, it extends from the StakeManager
contract.
Deposits are just a balance used to pay for UserOperations (either by a paymaster or an account), and Stakes are values that are locked for at least unstakeDelay
by a paymaster, which is necessary for the reputation system.
This can be counter-intuitive at first since one of the main ideas of ERC-4337 was to abstract away the requirement of accounts having ether in order to pay for transactions. In fact, all UserOperations must have an ETH deposit on the EntryPoint for them to be executed. The gotcha is that this can either be done through depositTo
on behalf of the counterfactual wallet, or by a paymaster. One can imagine an improved user experience where the user pays for the deposit with fiat in order to have their smart contract wallet deployed, for example.
Validating Nonces
The initial release v0.4 of ERC-4337 left the nonce to be calculated and checked by the wallet, as it would give the most flexibility to the smart contract account, allowing it to include different nonce schemes. It was encouraged to use a nonce for replay checking, but this was not enforced anywhere. An account could ignore the nonce field, send multiple UserOperations with the same value, and use a different mechanism to protect itself from replay attacks, which would make the userOpHash
a non-unique value.
This could create a side effect for block explorers, as they would no longer have a unique identifier to look for and mark specific operations. It might also confuse applications waiting for a transaction response, which could adversely affect the manner in which applications and wallets operate, as discussed in this GitHub issue.
As a result, the new version v0.6 of the EntryPoint
inherits from NonceManager
to handle accounts’ nonces, while still making it flexible enough to enable different replay protection schemes.
This also highlights an important aspect of ERC-4337: the EntryPoint is expected to be updated over time. Bundlers are already equipped with this expectation by supporting the eth_supportedEntryPoints
RPC method, which lists the supported EntryPoint versions.
Security Considerations
Being a central trust point of all ERC-4337, the EntryPoint
contract needs to be very heavily audited and formally verified. Nevertheless, it is expected that this architecture reduces auditing and formal verification load for the rest of the ecosystem.
The amount of work that individual accounts have to do becomes much smaller, as they only need to verify the validateUserOp
function and its “check signature, increment nonce, and pay fees” logic, and check that other functions are msg.sender == ENTRY_POINT
gated.
Finally, the EntryPoint must also ensure that it only calls an account if validateUserOp
has passed, and that if it calls validateUserOp
and passes, it also must make the generic call with calldata
equal to op.calldata
. This is to ensure safety against arbitrary hijacking and safety against fee draining.
Final Thoughts
In the second part of our series into ERC-4337: Account Abstraction Using Alt Mempool, we delved deeper into the intricacies of the EntryPoint contract — a cornerstone of the entire system. Serving as the central point for handling UserOperations, the EntryPoint ensures the effective execution of bundled transactions. Additionally, with the ongoing evolution of the EntryPoint, evident from the shift from version v0.4 to v0.6, it now emphasizes a more rigid validation system, while still retaining flexibility for custom account implementations.
Stay tuned for Part 3 of this series where we’ll dive deeper into the remaining components of ERC-4337 and their workflows. If you have any questions regarding secure use of the account abstraction, don’t hesitate to contact us.