A deep dive into the main components of ERC-4337: Account Abstraction Using Alt Mempool — Part 2

Antonio Viggiano
Oak Security
Published in
5 min readOct 24, 2023

--

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.

Source: ERC-4337: Account Abstraction Using Alt Mempool

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.

EntryPoint.handleOps

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.

EntryPoint.innerHandleOp

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.

EntryPoint.handleAggregatedOps

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 handleOpsand 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.

--

--

Antonio Viggiano
Oak Security

Helping protocols improve their invariant tests with echidna 🦔, foundry ⚒️, and medusa 🪼