ERC-4337: Account Abstraction via Entry Point Contract specification

Multi-Entrypoint Support for Account Abstraction

I have an idea to enhance its functionality by introducing multi-entrypoint support. This enhancement would allow an account to accept multiple entrypoints, enabling seamless integration with various wallet platforms.

The current EIP-4337 proposal focuses on providing a standardized approach for composing Ethereum accounts and abstracting their underlying signatures and key management. However, it assumes a single entrypoint for interacting with the account. By expanding the proposal to support multiple entrypoints, we can significantly enhance its flexibility and usability across different wallet implementations.

My proposal suggests introducing a mechanism within EIP-4337 that allows an account to register and manage multiple entrypoints. This way, users can interact with the account using different wallet platforms, each utilizing its own entrypoint, while still benefiting from the underlying features provided by account abstraction.

The benefits of this enhancement include:

  1. Improved interoperability: Supporting multiple entrypoints would foster interoperability between different wallet platforms, empowering users to choose their preferred method of interacting with the account while maintaining a consistent user experience.
  2. Enhanced user choice: Users could access and manage the account using a wide range of wallet implementations, including hardware wallets, mobile wallets, browser extensions, and more, without needing to modify or switch their account setup.
  3. Developer-friendly integration: Wallet developers would have the flexibility to integrate their platforms with accounts utilizing EIP-4337 more easily, expanding the adoption and support for account abstraction in the Ethereum ecosystem

I think (EIP-725X)[EIPs/ at master · ethereum/EIPs · GitHub] can help

Hi authors, I have a question about the “forbidden” opcodes.

On the EIP body it says

They should only be forbidden during verification, not execution.

But that’s not very obvious to me. Can you help me understand better by providing some examples about the intended enforcement approach?

I don’t understand what you achieve with multiple EntryPoint contracts.
An account trusts the EntryPoint that its execute method is only called if validateUserOp is called first (and doesn’t fail).
While it is possible for an account to support multiple EntryPoint (e.g. using require(validEntryPoints[msg.sender])), I don’t see the merit of it: There should be a single EntryPoint on the network, and the only reason to replace is the unlikely case we find a security breach , in which case wallets would like to replace it.

When an application submits a UserOperation (by calling the eth_sendUserOperation rpc call), the bundler first validate this UserOp is valid.
It does so by calling the simulateValidation() helper function, to make sure that creation, account validation and paymaster validation all succeed.
In order to protect itself (the bundler, not account), from denial of service attacks, it has to make sure this UserOp can’t interfere (invalidate) any other UserOp already in the mempool.
To do so, it performs a set of checks by tracing the above validation simulation - e.g. to make sure that opcodes that can be used for such denial of service (block number, timestamp,etc) are not used, and also that it only uses its own storage.
It will only accept UserOps that pass these validations.
If a UserOp is validated, the bundler knows it will pay, so there is no longer a possible of denial of service attack.
The executed code of the UserOp can do whatever it pleases - the UserOp is already guaranteed to pay. Just like normal transaction, the user pays even if the UserOp (or transaction) reverts.

I don’t understand what you’re trying to do: during execution, you can do whatever you like. Moving storage to another randomly-allocated location is possible - but you still need to keep (in storage) this randomly allocated storage address.

The problem I am trying to tackle is what if user adds a plugin to their AA wallet, that has a malicious code that can change the diamond storage layout causing users to lose access to wallet.

1 Like

ERC20 Gas Payment Implementation in Bundler:

Should we include logic to validate ERC20 gas payments in the bundler, such as checking prices to optimize gas usage?

The paymaster contract will solely validate gasPrice and return the ERC20 token to tx.origin. Users have the option to set maxPriorityFeePerGas and maxFeePerGas in the userOperation to zero.

When implementing ERC20 gas payments in the bundler, it is worth considering the inclusion of additional logic to validate these payments and optimize gas usage. One approach could involve performing price checks to ensure efficient gas consumption.

Furthermore, users are provided with the flexibility to set maxPriorityFeePerGas and maxFeePerGas to zero within the userOperation section.

The idea is leave the core entities (EntryPoint and bundlers) as un-opinionated as possible. Tokens involve exposure to price volatility, which the core network shouldn’t deal with.

Payment with token is done using a TokenPaymaster, which pays the gas price in native token (eth), and receive tokens from the user’s account.


Hi ERC-4337 contributors:

Just FYI, there is a pending Pull Request to move ERCs out from the current EIP repo, which may mean a new place for future ERC-4337 updates.

We will be grateful to hear your opinion on this

I’m interested in learning whether Account Abstraction will be implemented in the consensus layer in the future. I observed that EIP-4337 was favored over EIP-2938 because it avoids AA on the consensus layer. The reason for my inquiry is that I am an early solo staker who lost my mnemonic and now can’t create a withdrawal address. I’m curious if there are any upcoming EIPs that might introduce social recovery options for ETH2 addresses.

Does this mean session key will have access to all functions of AA wallet by default. Or there would be some control needs to be in place which cross checks data from userOperation while validating transaction coming to smart contract via session key

erc-4337 doesn’t define session key - a specific account implementation can define it, and it also has to define what it can do.
erc4337 only let the validation methods (of account and paymaster) declare the time-range they are valid, which is required in order to have session keys.
Note that this mechanism can be used for other purposes too. e.g. someone can create a paymaster that accepts a “coupon”, which is only valid on a specific time-range.

Why was nonce management moved to the EntryPoint contract itself? I would think that’s something accounts would want complete control over. For example, creating a userOp that an account wants to give nonce incrementing control to another account (in a gas efficient way). Or using an entire storage slot as a 256 bit wide bit field to invalidate one-off userOps (more gas efficient than using whole storage slots just to invalidate one userOp in current key-value implementation).

For this purpose, a UserOperation is not allowed to access any information that might change between simulation and execution, such as current block time, number, hash etc. In addition, a UserOperation is only allowed to access data related to this sender address: Multiple UserOperations should not access the same storage, so that it is impossible to invalidate a large number of UserOperations with a single state change.

From this statement it isn’t clear that this applies only to validation and that execution is unrestricted.

Thanks, your right. Will be fixed

The make reason was too force uniqueness of UserOps. While accounts can work security on-chain, it makes offchain tools, such as block explorers and some paymasters more complex.
UserOps should behave as much as possible as transactions, and unique id is a major feature.

The adopted solution still allow unique out-of-order UserOps, with 192 bit unique id.
This seems to be sufficient (after all, addresses are considered unique and are only 160 bit)
Can you give an example where you think this is not enough?

The 192 bit ID plus 64 bit nonce is great, but I would tweak it to make one-off userOps more efficient. I’d suggest we make values starting at 2^64 - 256 and up be recognized as accessing a bit field all on the same storage slot. So a value of (2^64 - 256) + n would be explicitly pointing to bit n on the slot at [192bit ID]. This would eliminate having to set non zero storage on every userOp that is just an out-of-order one-off and save 17,100 gas ($0.43 on mainnet at time of writing).

I don’t understand how you suggest to use a single storage slot for arbitrary number of one-off userops.

I guess I should have more accurately said one slot for every 256 on-off user ops.