We propose splitting the Ethereum transaction scope into multiple steps: validations, execution, and post-operation logic. Transaction validity is determined by the result of the validation steps of a transaction.
We further separate transaction validation for the purposes of authorization and the gas fee payment, allowing one contract to pay gas for a transaction that will be executed from another contract.
Motivation
Native Account Abstraction allows custom validation logic of a transaction and custom gas payment logic, opening new use-cases and features for wallets and dApps.
A more detailed motivation for this proposal can be found in the README document.
Specification
Constants
Name
Value
AA_TX_TYPE
TBD
AA_ENTRY_POINT
address(0x7701)
AA_BASE_GAS_COST
15000
ROLE_SENDER_DEPLOYMENT
0xA0
ROLE_SENDER_VALIDATION
0xA1
ROLE_PAYMASTER_VALIDATION
0xA2
ROLE_SENDER_EXECUTION
0xA3
ROLE_PAYMASTER_POST_OP
0xA4
New Transaction Type
A new EIP-2718 transaction with type AA_TX_TYPE is introduced.
Transactions of this type are referred to as “AA transactions”.
current_context_role is a context variable set by the AA transaction to the current role.
During AA transactions, it is set to the current role in the transaction’s lifecycle for each top level call.
During non-AA transactions it is always set to ROLE_SENDER_EXECUTION.
It remains unchanged on DELEGATECALL but is reset to ROLE_SENDER_EXECUTION on CALL / STATICCALL / CALLCODE. This behavior resembles msg.sender.
The CURRENT_ROLE opcode returns the current_context_role value.
The ACCEPT_ROLE opcode is equivalent to RETURN in the sense that it copies a memory slice, ends execution, and pastes the memory slice onto parent returndata, with a single modification:
It accepts the frame_role as the additional input parameter, and reverts if it differs from the current_context_role
For each role in the transaction’s lifecycle, a successful ACCEPT_ROLE is expected with the frame_role == role.
If any validation frame failed to perform an ACCEPT_ROLE matching its role, the transaction fails the validity checks and cannot be included.
TXPARAM* opcodes
The TXPARAMDLOAD, TXPARAMSIZE, TXPARAMCOPY opcodes follow the pattern of CALLDATA* / RETURNDATA* opcode families.
Each TXPARAM* opcode takes an extra stack input value as a first input compared to its CALLDATA* equivalent.
The values of this input are as follows:
In all top-level frames, the global variables have the following meaning:
Opcode Name
Solidity Equivalent
Value
CALLER
msg.sender
The AA_ENTRY_POINT address
ORIGIN
tx.origin
The transaction sender address
CALLDATA*
msg.data
Empty for all call frames except for the sender execution frame, for which it is set to sender_execution_data
Costs of accessing cold addresses for Sender, Paymaster, and Deployer
The Sender address is pre-warmed as part of the AA_BASE_GAS_COST.
When a non-zero address that is not equal to the Sender address, is provided for a Paymaster or a Deployer contract,
an additional EIP-2930ACCESS_LIST_ADDRESS_COST cost of 2400 gas is charged and the address is added to accessed_addresses.
AA transaction processing flow
We define processing flow for an AA transaction as follows:
A full list of rationales for the decisions made in this proposal can be found in the README document.
Backwards Compatibility
Security Considerations
As the ACCEPT_ROLE opcode represent a generic way to authorize any action on behalf of the contract,
correct and secure implementation of this code is critical.
We expect that compilers targeting EVM will play a major role in enabling and ensuring Smart Contract Accounts’ security.
For smart contract security auditors and security-oriented developer tools it is crucial to ensure that contracts not
meant to have roles in AA transactions do not have unexpected ACCEPT_ROLE opcode.
Otherwise, these contracts may present an immediate security threat.
As an example, block explorers should tag contracts as “user accounts” or “paymasters” if they have the ACCEPT_ROLE opcode used in their source code.