A special thank you to the authors of EIP-2938 and EIP-4337, whose years of research has made this proposal possible.
EVM code is used to implement the logic of applications, but what if it could also be used to implement the verification logic (nonces, signatures…) of individual users’ wallets? For simplicity, Ethereum currently hardcodes the verification logic to a nonce and ECDSA signature, but this means transactions can only “start from” an externally owned account (EOA).
Account abstraction (AA) allows a contract to be a top-level account that pays fees and starts transaction execution.
These 6 are only the beginning of use cases for account abstraction! As programmable transaction validity makes its way into production systems, we'll see even more use cases emerge.
Our first version of AA described below supports use cases 1, 2, and 3, but does not solve 4, 5, and 6. If you deeply care for 4-6, please reach out!
All accounts are smart contracts and have some code
attached to them. Default smart contract code will simulate EOA behavior.
validateTransaction
method on the from
smart contract and passes all the transaction data to it. During the call, the from
account contract should validate the transaction’s information and return whether or not the transaction is valid.This step will have the following limitations to prevent DoS attacks:
ergs
(our equivalent to gas).to
contract with the provided transaction’s data
.from
account for the amount of ergs left after the execution.With AA, transactions can be in 3 possible states:
Success
: executed, made state changes in both the verification and execution step of the txFailed
: executed, paid the fee, and made changes only within the verification step, but didn’t make any state changes in the execution stepFailedVerify
: failed AA verification step, no fee is paid and no state changes were madeWe will support 0-type Ethereum transactions as well as EIP-712 transactions. The EIP712 transaction format will be changed to have the bytes
type of signature. It will have the following structure:
Each account abstraction must implement the following method:
It should also implement the ERC-1271 signature verification standard:
Our SDK will use this method to validate signatures out of the box.
Let’s say that we want to have an L2 AA controllable by an L1 smart contract. We can not provide the signature of the L1 smart contract, but what we can do is the following:
_fromAddressL2
equal to the L2 AA address and the rest of the params as the appropriate call params.From the perspective of the smart contract, the transaction will also require bytes _signature
. For instance, here is the call for an execute on the L1 bridge:
The QueueType and OpTree parameters are further explained here.
The _signature
field is needed in case the _fromAddressL2
is a multisig controlled by multiple accounts and requires multiple signatures to conduct an operation.
Since the AA code is the same as the smart contract code, it won’t be upgradable by default. If users want to allow upgradability for their AA code, the Proxy
pattern can be used.
What if the user only wants to modify the tx validation process, but not modify the rest of the functionality?
The user can create a smart contract Validator
that will implement a Proxy pattern and will be fully responsible for the tx validation process. The validation code of the main contract will look the following way:
At the genesis, all the contracts with address greater than uint256(1023)
will have the default smart contract code assigned to them.
Its main purpose is to emulate the behavior of the existing EOAs on Ethereum. It will implement all of the following two methods:
Transaction execution under AA can be separated into two parts:
In Ethereum, transaction validation of signature, nonce, and value of EOAs can be done in parallel, and once added to the mempool, it remains valid with a guarantee of fee payment to the miner.
In AA, the result of the validation of a transaction can be changed by the execution of a previous one, so the validation and execution steps must be done sequentially for the currently forming block. This is a major DoS threat: if millions of transactions with failed verification steps flood the system, all must be processed sequentially before processing transactions that actually change the state.
To prevent this attack, we need to maximize the amount of “free” computation the operator can do in parallel.
To mitigate the DoS vector, the verification step will have the following limitations:
ergs
this step is allowed to spend.block.timestamp
.The first limitation will be so severe that privacy-preserving tooling will not be allowed. The second limitation will allow free verification to be done in parallel.
The rules below do not apply to L1-originated transactions, which are included even if it does not pass the verification & fee payment steps.
To force sequential processing of n
transactions’ verifications for free, the attacker needs to change at least n/k
storage slots, where k
is the max number of the simultaneous transactions from the same account in the mempool.
If the transaction passes the preliminary validation by the read-only API node, it is accepted to the mempool.
The mempool will have a limited size of n=5 transactions per address.
Once in the mempool, the transaction can either:
Since all new transactions are validated against the most recent state before getting accepted to the mempool and there can be at most 5 transactions with the same address in the mempool, this storage slot change could invalidate at most 5 transactions in the mempool.
All transactions keep the nonce
field, for server purposes in managing the mempool. Mempool rules must allow for the ability of users to replace their transactions and the need to keep only a small constant amount of transactions originating from a single address.
nonce
field equal to last_nonce+k
, where k <= 5
, where last_nonce
is the nonce
field of the last successfully executed transaction from this account.last_nonce+1
.The main issue with the provided rules is that it is hard to use with shared contracts, like Tornado Cash or Uniswap to pay the fees, because nonces provided in the txs by different users may interfere. Unfortunately, the alternative is not using nonces for transaction ordering and it is very inconvenient for Metamask / other wallet users. Even multisig users might get confused without nonce ordering. In this particular situation, we prioritize wallet/multisig users’ experience over protocol users’ experience. Any ideas are welcome.
FailedVerify
state and it will not be added to the block and deleted from the mempool. If the verification step & the fee payment step succeed, the transaction is executed and applied to the state. It will be included in the next block.The following features were left out of the current AA design because they can be implemented without changes to our circuits. These are pure server-side changes which can be added but are non-trivial to implement. If you are passionate about these use cases, please reach out!
Reading the immutable state of other contracts during the verification step is safe but currently not allowed.
Complex verifications such as SNARK verification is currently not possible under the current verification gas limit.
Because current mempool rules use nonce to sort/override transactions, privacy-preserving applications (e.g. Tornado Cash) cannot work conveniently, because users’ supplied-nonces will interfere.
We can support such applications by applying the following modifications to the mempool rules:
nonce
supplied as a part of the transaction, then the newest one overrides the previous one.Nonces provided by different users interfere with using shared contracts such as Uniswap to pay fees. The alternative is to not use nonces for transaction ordering, which presents an inconvenience for wallet users. In this situation, we have chosen to prioritize wallet/multisig users’ experience over protocol users’ experience.
To support this, we could implement a mechanism similar to paymasters detailed in EIP-4337. Paymasters do introduce an additional DoS vector, so we would introduce EIP-4337's reputation scoring system as well.