Abstract
This proposal introduces a new EIP-2718 transaction type (AA_TX_TYPE), split out of EIP-8130 as an independent transaction type with no Keystore dependency. It works for today's EOAs with native secp256k1 authentication, giving them call batching with phased atomicity, native value in calls, gas sponsorship with bound and open payers, two-dimensional nonces with a nonce-free mode, and in-band EIP-7702-style code delegation. Its authenticator selector, actor-resolution hook, and reserved account-change types let other account models plug in without a new transaction type. EIP-8130 specifies one such integration, for the Keystore.
Motivation
Wallets want to batch calls, have a third party pay gas, run independent transaction lanes in parallel, and set code delegation in the same transaction that uses it. Today these require an ERC-4337 bundler stack, several transactions, or a smart account for every user.
This proposal provides these capabilities as protocol features of one transaction type. Validation is fixed-cost: nodes verify a secp256k1 signature per role and check nonce, balance, and validity window, and never simulate wallet code to decide whether a transaction is valid.
The wire format is designed so that richer authentication can be added later without a new transaction type. The sender and payer authorization fields already carry an authenticator selector, account changes are a typed registry, and the actor-resolution step is a named hook. EIP-8130 (Keystore Accounts) specifies how the Keystore fills these in (Keystore integration). This document refers to it only where an extension point needs naming.
Specification
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
Constants
| Name | Value | Comment |
|---|---|---|
AA_TX_TYPE | 0x79 | EIP-2718 transaction type |
AA_PAYER_TYPE | 0x7A | Magic byte for payer signature domain separation |
REPLAY_ID_TYPE | 0x7901 | Magic prefix for replay_id domain separation |
AA_BASE_COST | 15000 | Base intrinsic gas cost |
K1_AUTHENTICATOR | address(1) | Selector for native secp256k1 authentication |
K1_AUTH_COST | 5100 | Fixed secp256k1 authentication cost: ecrecover (3,000) plus one cold account-state read (2,100). See Intrinsic Gas |
TX_VALUE_COST | 6000 | Per value-bearing call: the recipient balance write and the transfer log. Charged statically because to and value are signed fields |
DELEGATION_COST | 4600 | Delegation indicator deposit (200 × 23 bytes) |
NONCE_MANAGER_ADDRESS | 0x813000000000000000000000000000000000aa01 | Nonce Manager precompile |
NONCE_KEY_MAX | 2^256 - 1 | Nonce-free mode |
TIMESTAMP_MS_THRESHOLD | 100_000_000_000 | Unit-detection boundary for valid_after/valid_before |
REPLAY_BUFFER_CAPACITY | chain parameter | Capacity of the nonce-free replay_id ring buffer (consensus) |
NONCE_FREE_EXPIRY_WINDOW | chain parameter | Maximum valid_before − now for nonce-free transactions (consensus) |
MAX_AUTHENTICATION_GAS | configurable (suggested 100,000) | Bound on payer-authentication gas metered outside gas_limit |
Transaction Type
A new EIP-2718 transaction with type AA_TX_TYPE:
AA_TX_TYPE || rlp([
chain_id,
sender, // empty = recover from sender_auth | 20-byte address
nonce_key, // uint256: nonce channel selector
nonce_sequence, // uint64: sequence number
valid_after, // uint64: Unix timestamp (ms or s, auto-detected); 0 = no lower bound
valid_before, // uint64: Unix timestamp (ms or s, auto-detected); 0 = no expiry
max_priority_fee_per_gas,
max_fee_per_gas,
gas_limit,
account_changes, // typed entries | empty
calls, // [[call, ...], ...] | empty
metadata, // opaque attribution/annotation bytes | empty
payer, // empty = self-pay | 0x00 = open | 20-byte payer address
sender_auth,
payer_auth
])
call = rlp([to, value, data]) // to: address, value: uint256, data: bytesField Definitions
| Field | Description |
|---|---|
chain_id | Chain ID per EIP-155 |
sender | Empty: the sender is recovered from sender_auth. 20-byte address: the named sender, authenticated by sender_auth (see Authentication) |
nonce_key | uint256 nonce channel selector. 0 for standard sequential ordering, 1 through NONCE_KEY_MAX - 1 for parallel channels, NONCE_KEY_MAX for nonce-free mode |
nonce_sequence | uint64 expected sequence number within nonce_key. Must match the current sequence for (sender, nonce_key), which for nonce_key == 0 is the account nonce (see Nonces). Incremented after inclusion regardless of execution outcome. Must be 0 when nonce_key == NONCE_KEY_MAX |
valid_after | uint64 Unix timestamp, milliseconds or seconds (see Timestamp Normalization). After normalization, the transaction is invalid when block.timestamp * 1000 < valid_after. 0 means no lower bound. Many mempools will not hold a not-yet-active transaction and MAY reject one whose valid_after is in the future |
valid_before | uint64 Unix timestamp, milliseconds or seconds. After normalization, the transaction is invalid when block.timestamp * 1000 > valid_before. 0 means no expiry. Must be non-zero when nonce_key == NONCE_KEY_MAX |
max_priority_fee_per_gas | Maximum priority fee per gas unit (EIP-1559) |
max_fee_per_gas | Maximum fee per gas unit (EIP-1559) |
gas_limit | Maximum gas for sender-intrinsic gas and call execution. Payer authentication is metered separately (see Intrinsic Gas) |
account_changes | Empty: no account changes. Non-empty: array of typed entries (see Account Changes) |
calls | Empty: no calls. Non-empty: array of call phases (see Call Execution) |
metadata | Empty: no metadata. Non-empty: opaque attribution or annotation bytes (see Transaction Metadata) |
payer | Empty: sender pays. 0x00 (the single byte): open payer, recovered from payer_auth. 20-byte address: that payer is required. See Payer Modes |
sender_auth | Sender authorization (see Authentication) |
payer_auth | Payer authorization. Empty for self-pay (see Payer Modes) |
Timestamp Normalization
valid_after and valid_before MAY be expressed in either seconds or milliseconds. The unit is a fixed function of each value against TIMESTAMP_MS_THRESHOLD:
- a value below
TIMESTAMP_MS_THRESHOLDis interpreted as seconds and normalized to milliseconds asvalue * 1000; - a value at or above
TIMESTAMP_MS_THRESHOLDis interpreted as milliseconds and used as-is; 0means "no bound" and is not normalized.
A 64-bit Unix timestamp in seconds does not reach 10^11 until the year 5138, while any Unix timestamp in milliseconds has exceeded 10^11 since 1973, so the rule is unambiguous and consensus-safe. All validity-window comparisons in this specification operate on the normalized millisecond value.
The effective resolution of the window equals the chain's block-timestamp resolution. The millisecond form exists for off-chain clock compatibility and forward-compatibility with sub-second block times.
Authentication
sender_auth and payer_auth share one shape rule. When the corresponding identity is recovered (not named in the transaction), the blob is a raw 65-byte ECDSA signature r || s || v. When the identity is named by a 20-byte address, the blob is authenticator (20 bytes) || data.
sender | sender_auth | Resolved sender |
|---|---|---|
| empty | r || s || v (65 bytes) | ecrecover of the sender signature hash |
| 20-byte address | K1_AUTHENTICATOR || r || s || v | sender; the recovered address MUST equal sender |
Without Keystore integration, K1_AUTHENTICATOR is the only accepted authenticator, and the recovered address MUST equal the named account. Any other authenticator selector or blob length is invalid. The shape is decided by whether the identity is named, never by blob length.
Resolved actor. Validation resolves an actor for each authorization: the identity that signed, and the authority it holds on the account. Without Keystore integration the resolved actor is always the account's own key, which holds full authority. Every authorization rule in this specification is written as a requirement on the resolved actor, so these rules are trivially satisfied without Keystore integration and become meaningful with it.
Signature Payload
Sender and payer use different type bytes for domain separation.
Sender signature hash, all fields through payer, excluding sender_auth and payer_auth:
keccak256(AA_TX_TYPE || rlp([
chain_id, sender, nonce_key, nonce_sequence, valid_after, valid_before,
max_priority_fee_per_gas, max_fee_per_gas, gas_limit,
account_changes, calls, metadata,
payer
]))Payer signature hash:
keccak256(AA_PAYER_TYPE || rlp([
chain_id, sender, nonce_key, nonce_sequence, valid_after, valid_before,
max_priority_fee_per_gas, max_fee_per_gas, gas_limit,
account_changes, calls, metadata,
payer
]))The sender field in the payer signature hash MUST be the resolved sender address. When sender is empty in the wire format, the recovered sender address MUST be substituted before computing this hash. This binds every payer signature, including an open-mode one, to one specific sender (see Security Considerations). The payer field is the wire value (empty, 0x00, or the address).
Payer Modes
payer | payer_auth | Mode | Resolved payer |
|---|---|---|---|
| empty | empty | Self-pay | sender |
0x00 | r || s || v (65 bytes) | Open | ecrecover of the payer signature hash |
sender | K1_AUTHENTICATOR || r || s || v | Self-pay, explicit | sender; the recovered address MUST equal sender |
| other address | K1_AUTHENTICATOR || r || s || v | Sponsored | payer; the recovered address MUST equal payer |
In open mode the sender does not name a payer: any key willing to pay signs the payer hash, which already binds to the resolved sender and the full transaction body. Open mode is always secp256k1, because an identity that is recovered rather than named has no address to resolve another authenticator against.
The explicit self-pay form is redundant without Keystore integration. It is kept so that a dedicated gas key on the sender's own account (see EIP-8130) is a widening of an existing shape rather than a new one.
Nonces
nonce_key 0 uses the sender's account nonce, the same nonce used by other transaction types: nonce_sequence MUST equal it, and inclusion increments it. Keys 1 through NONCE_KEY_MAX - 1 are held by a precompile at NONCE_MANAGER_ADDRESS, separate from the account nonce. The protocol reads and increments them directly during transaction processing; the precompile exposes a read-only getNonce() interface to the EVM.
nonce_key Range | Name | Description |
|---|---|---|
0 | Standard | The account nonce, shared with other transaction types. Sequential ordering, mempool default |
1 through NONCE_KEY_MAX - 1 | User-defined | Parallel transaction channels defined by wallets |
NONCE_KEY_MAX | Nonce-free | No nonce state read or incremented |
Nonce-Free Mode (NONCE_KEY_MAX)
When nonce_key == NONCE_KEY_MAX, the protocol neither reads nor increments a nonce counter; nonce_sequence MUST be 0 and valid_before MUST be non-zero. Replay protection uses replay_id deduplication held in a fixed-capacity circular buffer that is consensus state: a seen map (replay_id → valid_before) of live entries plus a ring that evicts the oldest entry once elapsed. A still-live replay_id is rejected, and a buffer full of still-live entries rejects the transaction. REPLAY_BUFFER_CAPACITY MUST be at least peak accepted nonce-free throughput × NONCE_FREE_EXPIRY_WINDOW so an entry always elapses before its ring slot is reused. Entries are ephemeral, so there is no permanent state growth.
Replay Identifier
replay_id = keccak256(REPLAY_ID_TYPE || rlp([
chain_id, resolved_sender, valid_after, valid_before,
account_changes, calls, metadata,
payer
]))nonce_key and nonce_sequence are omitted because they are constant in nonce-free mode. resolved_sender keeps the identifier unique per sender when sender is empty. replay_id excludes the fee fields and gas_limit, so a fee bump does not change identity, and excludes sender_auth and payer_auth, which are non-deterministic and can be re-signed without changing the logical transaction. It includes the payer wire field, so retargeting a transaction at a different named payer is a new logical transaction. In open mode two submissions of the same body with different payers share a replay_id.
The full transaction hash MUST NOT be used for nonce-free deduplication or replacement.
Mempool Replacement
- Standard and 2D transactions (
nonce_key != NONCE_KEY_MAX): two pending transactions sharing(sender, nonce_key, nonce_sequence)are replacement candidates. Fornonce_key == 0the sequence is the account nonce, so a pending transaction of another type from the same sender with the same nonce is also a replacement candidate. - Nonce-free transactions: two pending transactions from the same
senderwith the samereplay_idare replacement candidates, and block builders MUST NOT include two transactions with the same(sender, replay_id)in one block.
In both modes a replacement MUST increase both max_fee_per_gas and max_priority_fee_per_gas by at least the node's configured minimum bump and MUST be independently valid, including a fresh payer_auth when sponsored, since payer_auth commits to the fee fields and gas_limit.
Account Changes
account_changes is an array of typed entries. Each entry is rlp([type, ...]).
| Type | Name | Defined by |
|---|---|---|
0x00 | Reserved | Future entry types |
0x01 | Delegation | This specification |
0x02+ | Reserved | Future entry types |
A transaction containing an entry type not accepted on the chain is invalid. At most one delegation entry is allowed.
Delegation Entry
A delegation entry sets EIP-7702-style code delegation for the sender, replacing the need for an authorization_list. It is authorized by sender_auth; no separate signature is required.
rlp([
0x01, // type: delegation
target // address: delegate to this contract, or address(0) to clear
])Rules:
- At most one delegation entry per transaction.
- The sender MUST have been authenticated through the native secp256k1 path (
senderempty, orK1_AUTHENTICATOR) with the resolved actor being the sender's own key with full authority. code(sender)MUST be empty or begin with the delegation designator0xef0100. Non-delegation bytecode is never replaced.target != address(0)setscode(sender) = 0xef0100 || target.target == address(0)clears the indicator and resets the code hash to the empty code hash.
Delegation Indicator
An account is delegated when its code is exactly 0xef0100 || target. All code-executing operations targeting a delegated account load code from target. Because this transaction type depends on the indicator directly, it MUST be supported on chains that adopt this proposal even where standalone EIP-7702 transactions are not enabled. This proposal never delegates an account automatically.
Transaction Metadata
metadata is optional opaque bytes for attribution or annotation, for example builder or app attribution, a payment reference, or a commitment to off-chain data. It is covered by both signature payloads, charged through tx_payload_cost, and does not affect validation or execution.
Call Execution
The protocol dispatches calls directly from sender:
| Parameter | Value |
|---|---|
caller / msg.sender at target | sender |
tx.origin | sender |
to | call.to |
msg.value | call.value |
data | call.data |
call.value is transferred from sender to call.to as part of the call frame and is reverted with it. If sender cannot cover call.value when the call runs, the call fails as a CALL with insufficient balance would, and its phase reverts. Block validity does not depend on the sender's balance covering call values; mempools check it at entry (see Mempool Acceptance). If call.value > 0 and call.to does not exist, the account-creation charge applies after the balance check and before the callee's code runs. It is charged at runtime because whether call.to exists is only known when the call executes. A non-zero transfer to an address other than sender emits the transfer log of EIP-7708 where that EIP is active.
Call Phases
calls is an ordered array of phases, each an ordered array of calls ([[call, ...], [call, ...]]). Phases execute in order from a single gas pool. Within a phase, calls are atomic: if any call reverts, all state changes of that phase are discarded and remaining phases are skipped. Completed phases persist.
Common patterns:
- Simple call:
[[call]] - Atomic batch:
[[call_a, call_b, call_c]] - Sponsor + user:
[[sponsor_payment], [user_action_a, user_action_b]]; the sponsor payment commits in phase 0 and can be a plain value transfer
Intrinsic Gas
intrinsic_gas = AA_BASE_COST + tx_payload_cost + nonce_key_cost + value_transfer_cost
+ account_changes_cost + sender_auth_cost + payer_auth_cost
sender_intrinsic_gas = intrinsic_gas - payer_auth_cost
execution_gas_available = gas_limit - sender_intrinsic_gas
effective_gas_limit = gas_limit + payer_gas_reserveSender-intrinsic gas is bounded by gas_limit. payer_auth_cost is metered separately and charged to the payer on top of gas_limit: payer_auth is excluded from both signature hashes and chosen by the payer, so if it drew from gas_limit a payer could starve calls.
payer_gas_reserve is payer_floor from the calldata floor below: 0 for self-pay (payer empty), otherwise fixed by the authenticator and the serialized payer_auth bytes. A transaction whose payer_gas_reserve exceeds MAX_AUTHENTICATION_GAS is rejected. The gas charged never exceeds effective_gas_limit.
| Component | Value |
|---|---|
AA_BASE_COST | 15,000: transaction decoding, sender resolution, nonce-mode dispatch, payer settlement, receipt assembly |
tx_payload_cost | 16 gas per non-zero byte and 4 per zero byte (EIP-2028) over the RLP-serialized transaction excluding payer_auth, subject to the calldata floor below |
nonce_key_cost | 0: 0 (account nonce, covered by AA_BASE_COST). NONCE_KEY_MAX: 13,000 (ring-buffer replay state). Otherwise 22,100 for first use of a nonce_key, 5,000 for an existing key |
value_transfer_cost | TX_VALUE_COST for each call with value > 0 and to != sender |
account_changes_cost | DELEGATION_COST for a delegation entry, else 0 |
sender_auth_cost | K1_AUTH_COST |
payer_auth_cost | 0 for self-pay (payer empty). Otherwise K1_AUTH_COST + payer_data_cost, where payer_data_cost is 16 gas per non-zero byte and 4 per zero byte over the serialized payer_auth, subject to the calldata floor below |
K1_AUTH_COST includes one cold account-state read that validation without Keystore integration does not perform. It is charged regardless so that secp256k1 transactions cost the same gas before and after Keystore integration activates (see Rationale).
Calldata floor. As in EIP-7623, the floor applies to the transaction as a whole, including the payer_auth bytes. Let payload_tokens = zero_bytes + 4 * nonzero_bytes over the bytes tx_payload_cost covers, payer_tokens the same count over the serialized payer_auth (0 for self-pay), and execution_gas_used the gas used by calls:
sender_floor = (sender_intrinsic_gas - tx_payload_cost) + 10 * payload_tokens
payer_floor = (payer_auth_cost - payer_data_cost) + 10 * payer_tokens
gas_used = max(
sender_intrinsic_gas + execution_gas_used + payer_auth_cost,
sender_floor + payer_floor
)A transaction whose gas_limit is below sender_floor is invalid. payer_floor is 0 for self-pay. Because payer_gas_reserve == payer_floor >= payer_auth_cost, both branches stay within effective_gas_limit.
Gas-schedule profiles. On a base layer the values above are protocol constants, changeable only through a hard fork (L1 profile). An L2 or other high-throughput chain MAY adopt a different schedule fixed under its own consensus (L2 profile), but MUST keep the formula's structure and MUST NOT set the calldata-floor rate below 4 or drop the floor.
Fees
Fees follow EIP-1559, applied over effective_gas_limit. With base_fee the block's base fee per gas:
priority_fee_per_gas = min(max_priority_fee_per_gas, max_fee_per_gas - base_fee)
effective_gas_price = base_fee + priority_fee_per_gasThe transaction is invalid if max_fee_per_gas < base_fee or if the payer's balance is below max_fee_per_gas * effective_gas_limit. GASPRICE returns effective_gas_price.
Before execution the payer is precharged effective_gas_limit * effective_gas_price. After execution, with gas_used as defined in Intrinsic Gas, the payer is charged gas_used * effective_gas_price and refunded the difference. gas_used * priority_fee_per_gas goes to the block's fee recipient and gas_used * base_fee is burned.
Validation Flow
Mempool Acceptance
- Parse and structurally validate the transaction: accepted
account_changesentry types and counts, andsender_auth/payer_authshapes per Authentication. - Resolve the sender and its actor.
- If a delegation entry is present, verify
code(sender)is empty or a delegation indicator, and that the resolved actor may delegate. - Resolve the payer and its actor per Payer Modes. Reject if
payer_gas_reserve > MAX_AUTHENTICATION_GAS. - Verify the validity window (after normalization), that
gas_limitcoverssender_floor, thatmax_fee_per_gascovers the current base fee, and that the payer's balance coversmax_fee_per_gas * effective_gas_limit(see Fees). Also verify that the sender's balance covers the sum ofcall.valueover all calls, plusmax_fee_per_gas * effective_gas_limitwhen the sender is the payer. - Verify the nonce:
nonce_sequenceequals the sender's account nonce for key0, orcurrent_sequence(sender, nonce_key)for keys1throughNONCE_KEY_MAX - 1; forNONCE_KEY_MAX, requirenonce_sequence == 0, a non-zerovalid_beforeno farther out thanNONCE_FREE_EXPIRY_WINDOW, and a freshreplay_id. - Apply per-payer pending limits and the Mempool Replacement rules.
Nodes MAY reject a transaction whose valid_before is too near to be reliably included, and MAY reject rather than hold one whose valid_after is not yet active.
Block Execution
- Check Fees validity and precharge the payer.
- If
nonce_key == 0, increment the sender's account nonce. Ifnonce_keyis1throughNONCE_KEY_MAX - 1, increment the Nonce Manager sequence for(sender, nonce_key). Ifnonce_key == NONCE_KEY_MAX, recordreplay_id. - Apply
account_changesin order. - Execute
callsper Call Execution.
Settlement charges the payer for gas_used per Fees: sender-intrinsic gas plus executed calls (together bounded by gas_limit) plus payer_auth_cost, subject to the calldata floor. It refunds the rest of the precharge. Payer authentication gas is never refundable.
Receipts
The EIP-2718 ReceiptPayload for this transaction type is rlp([status, cumulative_gas_used, logs_bloom, logs]), as for EIP-1559 receipts. status is 1 if every phase succeeded (or calls was empty) and 0 otherwise. Logs from reverted phases are discarded with their state changes.
status == 0 does not imply no state change: committed earlier phases, applied account_changes, nonce consumption, and fee payment persist.
RPC Extensions
eth_getTransactionCount: extended with an optional nonceKey parameter (uint256). Omitted or 0 returns the account nonce; other keys read the Nonce Manager.
eth_getTransactionReceipt: in addition to the standard fields, receipts for this type include:
payer(address): the resolved payer (senderfor self-pay, the named payer, or the payer recovered in open mode).phaseStatuses(uint8[]): one entry per phase,0x01(success) or0x00(reverted). Phases after a revert are not executed and are reported as0x00. Empty ifcallswas empty.gasUsedisgas_usedfrom Intrinsic Gas, including payer authentication.
eth_estimateGas / eth_call: accept the transaction's fields (sender, nonceKey, accountChanges, calls, validAfter, validBefore, metadata, payer, senderAuth, payerAuth) alongside the standard request object, and execute the request as an AA_TX_TYPE transaction. The sender is taken from sender or from; if both are present they MUST be equal. Signatures are never verified.
- Default: secp256k1. When
senderAuthorpayerAuthis omitted, the node assumes the role is authenticated by the account's own secp256k1 key with full authority. It prices a placeholder of the shape Authentication requires: a 65-byte signature when the identity is recovered,K1_AUTHENTICATORfollowed by 65 bytes when it is named.payeromitted means self-pay, with no payer placeholder. - Supplied blob. When
senderAuthorpayerAuthis supplied, its shape and length are used for pricing and its contents are ignored. - Placeholder pricing. Placeholder and supplied auth bytes are priced as non-zero bytes, so a zero-filled dummy never underestimates.
Other authentication mechanisms, such as the Keystore, define how requests select them (see EIP-8130).
Rationale
Why Delegation via Account Changes?
EIP-7702 introduced authorization_list with a separate signature per authorization. Here delegation is authorized by sender_auth, in the same nonce stream as the calls that use the new code. It is restricted to the native secp256k1 path so it stays portable to chains that only support EIP-7702.
Why a Metadata Field?
Attribution and annotation data traditionally rides as a suffix on tx.input. The structured calls array has no such location, so metadata gives it a signed home.
Charging the Keystore Read Before the Keystore
K1_AUTH_COST includes the account-state read that Keystore integration performs for a secp256k1 self-actor. Charging it before that integration activates means signed gas_limit values and wallet estimates do not change when it does, so accounts without Keystore state see identical validity, execution, and gas with or without the integration.
Backwards Compatibility
No breaking changes. Existing transaction types and accounts are unaffected. nonce_key 0 uses the account nonce, so this type and other transaction types from one account share one sequence at that key; other keys live in the Nonce Manager. Adoption is opt-in: an account sends this transaction type or does not. No account is delegated automatically. Activating Keystore integration does not change validity, execution results, or gas for accounts without Keystore state.
Reference Implementation
INonceManager (Precompile)
interface INonceManager {
function getNonce(address account, uint256 nonceKey) external view returns (uint64);
}Read-only. For nonceKey == 0 it returns the account nonce. Gas is a base cost plus a cold (2,100) or warm (100) read per EIP-2929 access rules.
Security Considerations
Replay Protection. Transactions include chain_id, a 2D nonce, and a validity window. For nonce_key != NONCE_KEY_MAX, inclusion increments (sender, nonce_key), so each (sender, nonce_key, nonce_sequence) is included at most once. Nonce-free transactions rely on a short valid_before bound and replay_id deduplication. The transaction hash must not be used for nonce-free deduplication: fee bumps, re-signed payer_auth, and randomized or malleable ECDSA signatures all change it without changing the logical transaction, and all resolve to the same replay_id. The validity window cannot be extended through replacement, because valid_after and valid_before are part of replay_id.
Payer Security. AA_TX_TYPE and AA_PAYER_TYPE domain separation prevents reuse of signatures between roles. A bound payer is committed in the sender hash. The payer's exposure is bounded by max_fee_per_gas * effective_gas_limit. Payer authentication is metered outside gas_limit, so the payer's choice of payer_auth cannot affect execution.
Cross-sender Payer Replay. The payer hash substitutes the resolved sender. Without this, two EOAs that construct identical transaction bodies would produce identical payer hashes, letting one reuse a payer signature issued for the other. This matters most in open mode, where the sender does not name the payer: the substitution is what binds an open-mode payer signature to one sender.
Open Payer Replacement. In open mode a third party that sees a pending transaction may attach its own payer_auth and submit it as a replacement. The body and sender are unchanged, and the replacement must pay the minimum fee bump, so the only effect is who pays.
Value in Calls. Value transfers are executed as part of each call frame and revert with their phase. status == 0 does not mean no value moved: transfers in committed earlier phases persist.
Delegation. Delegation requires native secp256k1 authentication as the account's own key, never replaces non-delegation bytecode, and is authorized by the transaction's own signature in the same nonce stream as the calls.
Keystore Integration. Security properties of actors, scopes, and policies, and the checks the Keystore integration adds to this transaction type, are specified in EIP-8130.
Copyright
Copyright and related rights waived via CC0.
