ERC 4337: account abstraction without Ethereum protocol changes

Account abstraction has for a long time been a dream of the Ethereum developer community. Instead of EVM code just being used to implement the logic of applications, it would also be used to implement the verification logic (nonces, signatures…) of individual users’ wallets. This would open the door for creativity in wallet designs that could provide some important features:

  • Multisigs and social recovery

  • More efficient and simpler signature algorithms (eg. Schnorr, BLS)

  • Post-quantum safe signature algorithms (eg. Lamport, Winternitz)

  • Upgradeability

It is possible to do all of these things with smart contract wallets today, but the fact that the Ethereum protocol itself requires everything to be packaged in a transaction originating from an ECDSA-secured externally-owned account (EOA) makes this very difficult. Every user operation needs to be wrapped by a transaction from an EOA, adding 21000 gas of overhead. The user needs to either have ETH in a separate EOA to pay for gas, and manage balances in two accounts, or rely on a relay system, which are typically centralized.

EIP 2938 is one path toward fixing this, by introducing some Ethereum protocol changes that allow top-level Ethereum transactions to start from a contract instead of an EOA. The contract itself would have verification and fee payment logic that miners would check for. However, this requires significant protocol changes at a time when protocol developers are focusing heavily on the merge and scalability. In our new proposal (ERC 4337), we provide a way to achieve the same gains without consensus-layer protocol changes.

How does this proposal work?

Instead of modifying the logic of the consensus layer itself, we replicate the functionality of the transaction mempool in a higher-level system. Users send UserOperation objects that package up the user’s intent along with signatures and other data for verification. Either miners or bundlers using services such as Flashbots can package up a set of UserOperation objects into a single “bundle transaction”, which then gets included into an Ethereum block.

The bundler pays the fee for the bundle transaction in ETH, and gets compensated though fees paid as part of all the individual UserOperation executions. Bundlers would choose which UserOperation objects to include based on similar fee-prioritization logic to how miners operate in the existing transaction mempool. A UserOperation looks like a transaction; it’s an ABI-encoded struct that includes fields such as:

  • sender: the wallet making the operation

  • nonce and signature: parameters passed into the wallet’s verification function so the wallet can verify an operation

  • initCode: the init code to create the wallet with if the wallet does not exist yet

  • callData: what data to call the wallet with for the actual execution step

The remaining fields have to do with gas and fee management; a complete list of fields can be found in the ERC 4337 spec.

A wallet is a smart contract, and is required to