ERC-4337: Account Abstraction via Entry Point Contract specification

@yoavw , @dror
I have a question about this ERC: In a decentralized bundler network, what would be the incentive for bundlers to propagate UserOps to the rest of the bundlers in the UserOp mempool? If a bundler can collect fees for being the first to bundle UserOps and send them to the Ethereum network then I would presume it would become advantageous for a bundler to listen for incoming UserOps but not propagate them further since they can be the first to bundle the UserOps they receive.

In the normal Ethereum mempool this is not an issue because full nodes gossip amongst themselves and with block producers/validators. The full nodes are not in any competition with each other so they have no incentive to censor transactions.

But without a concept of a full-node for the proposed UserOp mempool, with bundlers in competition with each other to be the first to bundle UserOps, and with no consensus mechanism to regulate which bundler gets to create the next bundle, I would imagine that there wouldn’t be any reason or incentive for bundlers to communicate with each other.

Why do you say it is highly recommended? Is this recommendation related to 4337? If yes, I am a bit confused. I thought that 4337 actually eliminates a need for 2771 for AA because gas sponsoring takes place in another layer. 2771 is still needed for EOAs, of course.
I wonder if this statement is valid: with EIP2771 a target smart contract decides on gasless tx service provider (it defines trusted forwarder), with EIP4337 a wallet provider decides on gasless tx service (if enabled, it binds tightly or loosely to a paymaster).

The EIP 4337 spec describes UserOperation as: Like a transaction, it contains “sender”, “to”, “calldata”, “maxFeePerGas”... . However, I don’t see where the to field gets set in any of the examples. ERC-4337: Account Abstraction Using Alt Mempool.

Does this need to be encoded as an attribute within the calldata?


I have a question about the Account Abstraction model. In the context of fully on-chain gaming, players are expected to initiate transactions. However, I’m interested in implementing a system where multiple players sign messages, which are then aggregated by a backend and uploaded to the blockchain. Ideally, users wouldn’t need to see a pop-up window each time they sign, and could set a configuration allowing them to sign messages of a specific format without permission (e.g., {from: 0x0, data: *, value: 0}). Is this possible? Thank you!

The incentive is the same as normal nodes and block-builders.
A “bundler” (a node that collects UserOperations into a transaction to be placed in the next block) has to be a block-builder (or use a direct API such as MEV-boost) to the next block.
Any attempt to put a bundle into the normal mempool would result a frontrun by another bundler.
It is true that a bundler can handle ITS OWN UserOperations, where they pay no extra fee to the bundler. This way there is no risk for someone to front-run (since there is no incentive to) - and even if someone does, it will get the UserOp on chain on the expense of this other bundler, so it doesn’t even serve as a “DoS” vector.

Since a bundler is merely a functionality of a block-builder, it carries almost the same incentive model.
The “almost” is because validation of a UserOperation is slightly more complex than a transaction: it is more expensive (in cpu and gas) and thus requires a different logic to protect the bundler from spam - but you do get paid for it when it gets submitted.

We recommend 2771 because it is good for Smart-Contracts ecosystem, not directly related to erc-4337 (or AA in general)
This is the de-facto standard for off-chain signing of data.

2771 doesn’t need an EOA, of course…
It DOES need the contract to validate the signature in the isValidSignature() method, but there is no requirement for the signature to be ECDSA, or for the signer to be an account: it can be a BLS, shnorr, zkproof, multisig or whatever signature scheme your account supports.

In ERC-4337, the format of the inner transaction is defined by the wallet itself. We expect wallets to have the equivalent of execute(dest,value,data), but they can use different formats.
Notably, accounts are expected to have an executeBatch() method, which may carry multiple destinations and calldata

That’s not a framework issue, but a wallet issue: you want to be able to “pre-approve” the wallet to send specific transactions without a user interaction.
This in general pose a security breach, but there is a concept of “session key”: your account supports a restricted key, which is limited to specific target contracts, specific contract methods and time-span. The user creates such a key once, and let the game “manage” this key (e.g. store it in the browser’s localStorage)
The damage such a key may cause is limited - probably to the same site or game, which is probably accepted.
So even though ERC-4337 doesn’t define such session keys by itself (or any type of key, for that matter), it is possible to create such accounts which support multiple key types. I do believe some wallet implementations already support it, or intend to, as this is a key feature for blockchain gaming.

Hello guys,

Could anyone give me a hint, how the signature in user operation been generated, and how it been validated in the smart contract in details, I am quite confused on this part.

Best regards

Account abstraction in general (and ERC-4337 in particular) delegate the validation of the UserOperation (transaction) to the account contract itself.
That is, ERC-4337 does not verify the signature at all. it calls a method on the account (named validateUserOp), which should validate the struct - including the signature field.
The meaning of this signature is entirely up to the account.
It can be a single or multiple signatures, a zk proof blob, or anything else.

@mudgen add some additional thoughts (not limited to specific plugin eip,hope it’s a useful thought for all): link

How to minimize security issues caused by plugins in a contract wallet


  1. The wallet use delegatecall to implement flexible plugins.
  2. It is not allowed for hacker(stole your private key) to add malicious plugins to destroyed the storage slot before social recovery (social recovery will never be able to run if some storage slot destroyed).

Implementation suggestions:

  1. The wallet owner must have a 48-hour delay confirmation period for adding any new plugins (or can be immediately effective through joint signature by owner and guardian).
    (This prevents the wallet from being stolen by hackers and destroying the storage, causing social recovery to not run as expected.)

  2. The wallet contract needs to add a simulate(calldata) function, where calldata is all the operations that the user will execute (if key storage such as owner, guardian, etc. are modified after executing the user’s operation, the specific information that is modified should be reverted). The wallet UI side should call this function in advance before the user executes any operation, if key storage is not modified as expected, the user should be prompted to avoid the wallet storage being destroyed by contract wallet plugin’s bug.

Was there an answer to this?

Hi, this is Pablo from PlanckerDAO. We are recently organizing a joint reading of eip4337. When we got to the part on bundling, we were confused about the sentences “In practice, restrictions (2) and (3)” and “If any of the three conditions is violated” because we didn’t find the numbered restrictions and conditions above.

I was having trouble understanding this as well, since there are only 2 bullets but it talks about restrictions (2) and (3). I think when referencing restrictions and conditions, it would be nice to reference them by label, which in most cases could be done by changing unordered lists to ordered lists in the ERC.

I understand that the bundled transaction opens up the opportunity for front-running in the normal transaction mempool, and that’s why it is important to have Proposer-Builder separation (through MEV-boost).

The question I have is why would bundlers participate in the UserOp mempool, where they would be sharing the UserOps they received with other bundlers who would frontrun them in bundling the UserOps.

Wouldn’t it make more sense for users to send their UserOps to multiple bundlers, and the bundlers do not need to communicate with each other because they are in direct competition with one another. Why would a bundler share the UserOps they received with other bundlers in the mempool?

UserOperation is a new type of transaction, and it shares the same incentive model as normal transactions.
Bundlers are essentially block-builders that support this new type of transaction.

Any question about a bundler is the same about a block-builder: Users are not expected to send transactions directly to block-builders, and just the same, they are not expected to send transactions directly to bundlers.

This is my advice:

  1. Do not limit add/replacing/remove functions to view/pure functions.
  2. Handle security of facets by having a facet registry which is a list of audited and approved facets for smart contract wallet diamonds. Also upgrades could require the approval of a user. That way a user gets only what he/she approves.

You can make it so that only facets in the facet registry can be added to a diamond. That way a malicious user who somehow gains access to a diamond cannot add malicious facets.

1 Like

I think there is a difference. In the normal transaction mempool there is limited competitive advantage for validators to withhold transactions from other validators:

  • In Proof of Work chains, even if a miner communicates transactions to another miner, the block has to be mined for the transaction to be included in the chain. So PoW mining is the competitive bottleneck.
  • In Proof of Stake chains, validators get chosen probabilistically so there is no competitive advantage to withholding transactions from other validators.

In the UserOp mempool however, if a bundler sends UserOps to another bundler, the other bundler could bundle the UserOps faster and you lose out on the fees you could have collected if you were the first to bundle these UserOps. This is why it seems logical to me that the bundlers would not communicate with each other.

Is the UserOp mempool just a network of normal nodes propagating UserOps in a P2P manner with each other, and certain willing block producers participate in this mempool by listening to a certain set of nodes for UserOps which they can bundle, without propagating these UserOps any further in the mempool?

If a bundler withholds transactions, soon enough users will notice they get included on-chain slower, and will stop using this RPC provider, and switch to another RPC provider.
A bundler (like any other block builder) earns from transaction fees but even more so from MEV opportunities.
As we see it, a logical bundler should look at each UserOperation and decide:

  • No high MEV value, so it is better to send it to the public mempool. The small gas fee will be earned by the bundler attached to the next block-builder, but at least the “quality of service” offered to the user is good.
  • High MEV value: better pay extra through PBS/MEVboost protocols to get this UserOperation included fast, before the opportunity disappears (and again, give the user a good quality of service)

Any other tactic will soon report this bundler is a bad service, and force the users to switch to another.

This discussion thread is about the ERC-4337 core, not about account implementation: the modular accounts architecture is discussed separately here.

Thanks for pointing me to this!

Hey, I was wondering what if the key contract storage (owner, selector mapping, etc.) can change its slot randomly to a new location after a transaction is executed? Imagine we make a copy of storage before executing calldata, and assign it to a new randomly generated location and we update the information about this random location post execution of calldata. This way, the calldata can execute anything, but key storage aspects will not change.

PS: Need to assess the gas implications of this.