---
eip: 7701
title: Native Account Abstraction
description: Native Account Abstraction protocol, relying on a new transaction type and a family of opcodes
author: Vitalik Buterin (@vbuterin), Yoav Weiss (@yoavw), Alex Forshtat (@forshtat), Dror Tirosh (@drortirosh), Shahaf Nacson (@shahafn)
discussions-to: https://ethereum-magicians.org/t/eip-7701-native-account-abstraction/19893
status: Stagnant
type: Standards Track
category: Core
created: 2024-05-01
---

## Abstract

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](../assets/eip-7701/README.md).


## 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](./eip-2718) transaction with type `AA_TX_TYPE` is introduced.
Transactions of this type are referred to as "AA transactions".

Their payload should be interpreted as:

```
AA_TX_TYPE || rlp([
  chain_id,
  nonce,
  sender, sender_validation_data,
  deployer, deployer_data,
  paymaster, paymaster_data,
  sender_execution_data,
  max_priority_fee_per_gas, max_fee_per_gas,
  sender_validation_gas, paymaster_validation_gas,
  sender_execution_gas, paymaster_post_op_gas,
  access_list,
  authorization_list
])

```

### `CURRENT_ROLE` and `ACCEPT_ROLE` opcodes

`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:


| `n`  | Return value               | Data size | Default      | Comment                                                                           |
|------|----------------------------|-----------|--------------|-----------------------------------------------------------------------------------|
| 0x00 | current transaction type   | 32        |              |                                                                                   |
| 0x01 | `nonce`                    | 32        |              |                                                                                   |
| 0x02 | `sender`                   | 32        |              |                                                                                   |
| 0x03 | `sender_validation_data`   | dynamic   |              |                                                                                   |
| 0x04 | `deployer`                 | 0 or 32   | `address(0)` |                                                                                   |
| 0x05 | `deployer_data`            | dynamic   | empty array  |                                                                                   |
| 0x06 | `paymaster`                | 0 or 32   | `address(0)` |                                                                                   |
| 0x07 | `paymaster_data`           | dynamic   | empty array  |                                                                                   |
| 0x08 | `sender_execution_data`    | dynamic   |              |                                                                                   |
| 0x0B | `max_priority_fee_per_gas` | 32        |              |                                                                                   |
| 0x0C | `max_fee_per_gas`          | 32        |              |                                                                                   |
| 0x0D | `sender_validation_gas`    | 32        |              |                                                                                   |
| 0x0E | `paymaster_validation_gas` | 32        | `0`          |                                                                                   |
| 0x0F | `sender_execution_gas`     | 32        |              |                                                                                   |
| 0x10 | `paymaster_post_op_gas`    | 32        | `0`          |                                                                                   |
| 0x11 | `access_list` hash         | 32        |              |                                                                                   |
| 0x12 | `authorization_list` hash  | 32        |              |                                                                                   |
| 0xf1 | `execution_status`         | 32        |              | See transaction scoped vars in [processing flow](#aa-transaction-processing-flow) |
| 0xf2 | `execution_gas_used`       | 32        |              | See transaction scoped vars in [processing flow](#aa-transaction-processing-flow) |
| 0xff | `tx_hash_for_signature`    | 32        |              | Hash of the transaction without the signature                                     |

### Affected opcodes

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-2930](./eip-2930) `ACCESS_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:

```
def state_transition_function(tx, block, state):
    # Empty refunds, warm list, execution status and gas used (new), etc
    state.transaction_scoped_vars = {}

    max_gas = tx.sender_validation_gas + tx.paymaster_validation_gas + tx.sender_execution_gas + tx.paymaster_post_op_gas
    gas_price = min(tx.max_fee_per_gas, block.base_fee_per_gas + tx.max_priority_fee_per_gas)
    payer = tx.sender if tx.paymaster is None else tx.paymaster
    total_max_cost = max_gas * gas_price
    balances[payer] -= total_max_cost
    gas_used = 0

    if get_code(tx.sender) is None:
        deployer_result = call(tx.deployer, [], tx.sender_validation_gas_limit, ROLE_SENDER_DEPLOYMENT)
        assert deployer_result.accepted_role == ROLE_SENDER_DEPLOYMENT
        gas_used += deployer_result.gas_used

    sender_result = call(tx.sender, [], tx.sender_validation_gas_limit - gas_used, ROLE_SENDER_VALIDATION)
    assert sender_result.accepted_role == ROLE_SENDER_VALIDATION
    gas_used += sender_result.gas_used

    if tx.paymaster:
        paymaster_result = call(tx.paymaster, [], tx.paymaster_validation_gas, ROLE_PAYMASTER_VALIDATION)
        assert paymaster_result.accepted_role == ROLE_PAYMASTER_VALIDATION
        gas_used += paymaster_result.gas_used

    checkpoint = state.take_snapshot()
    sender_execution_result = call(tx.sender, [], tx.sender_execution_gas, ROLE_SENDER_EXECUTION)
    gas_used += sender_execution_result.gas_used
    state.transaction_scoped_vars[execution_status] = sender_execution_result.output_code
    state.transaction_scoped_vars[execution_gas_used] = gas_used

    if tx.paymaster:
        postop_result = call(tx.paymaster, [], tx.paymaster_post_op_gas, ROLE_PAYMASTER_POST_OP)
        gas_used += postop_result.gas_used
        if postop_result.accepted_role != ROLE_PAYMASTER_POST_OP:
            state.revert_snapshot(checkpoint)

    balances[payer] += gas_price * (max_gas - gas_used)
```

## Rationale

A full list of rationales for the decisions made in this proposal can be found in the [README document](../assets/eip-7701/README.md).

## 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.

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
