Skip to content

Instantly share code, notes, and snippets.

@gakonst
Last active April 10, 2026 19:47
Show Gist options
  • Select an option

  • Save gakonst/00117aa2a1cd327f515bc08fb807102e to your computer and use it in GitHub Desktop.

Select an option

Save gakonst/00117aa2a1cd327f515bc08fb807102e to your computer and use it in GitHub Desktop.
Native AA Tx Type
eip XXX
title EIP-XXX Transaction
description A typed transaction supporting batching, scheduled execution, gas sponsorship, parallelizable nonces, passkey signatures, and access keys.
author <Your Name>
discussions-to TBD
status Draft
type Standards Track
category Core
created 2025-XX-XX
requires 2718, 1559, 2930, 7702, 2, 2929

Abstract

This EIP introduces a new EIP-2718 typed transaction, EIP-XXX Transaction, that standardizes a constrained set of transaction-level features intended to improve user experience and wallet ergonomics:

  • Atomic batching of multiple calls
  • Scheduled / expiring transactions via a validity window
  • Gas sponsorship via an optional fee payer
  • Parallelizable (two-dimensional) nonces
  • Multiple signature schemes, including secp256k1, P-256, and WebAuthn (passkeys)
  • Protocol-enforced access keys with optional expiry and spending limits

This EIP does not introduce native ERC-20 fee payment or any protocol-level fee conversion mechanism. A fee payer that expects non-ETH reimbursement MUST only co-sign transactions that include explicit calls compensating the fee payer.

Motivation

Externally Owned Accounts (EOAs) are constrained by sequential nonces, a single mandatory signature scheme (secp256k1), ETH-only fee payment, and the absence of native batching or scoped delegation. These constraints impose user-experience and throughput limitations on wallets and applications.

Many of the features addressed by this EIP can be implemented using smart contracts. For example, ERC-4337 enables account abstraction without protocol changes by introducing UserOperations, an alternative mempool, and an on-chain EntryPoint contract. However, smart-contract-based approaches require transaction validation and authorization semantics to be enforced by contract logic rather than by consensus rules, increasing implementation surface area and complicating static reasoning about transaction validity and cost.

This EIP instead standardizes a deliberately constrained set of transaction-level primitives at the protocol layer. Protocol-native validation provides uniform semantics across clients and removes reliance on bespoke contract implementations for core transaction validity rules such as nonce handling, signature domain separation, validity windows, and sponsorship semantics.

At the same time, protocol-level features are intentionally more limited than fully general smart contract abstractions. This EIP prioritizes a narrow, reviewable set of primitives sufficient for common workflows, while leaving application-specific logic and more expressive authorization models to higher layers.

Passkeys without relayers or bundlers

ERC-4337 UserOperations are not Ethereum transactions and cannot be included directly in blocks. They must be packaged into an Ethereum transaction that calls the EntryPoint contract, typically by an off-chain bundler.

By contrast, EIP-XXX Transaction allows a user to submit a single Layer-1 transaction whose authorization is provided directly by a P-256 or WebAuthn signature. This enables passkey-based signing at the transaction layer without requiring a relayer or bundler. Gas sponsorship remains optional and explicit via a fee payer signature.

Non-Goals

This EIP explicitly does not attempt to:

  • Replace ERC-4337 or its alternative mempool and execution model
  • Provide a fully general native account abstraction framework (e.g., arbitrary user-defined validation/execution logic)
  • Introduce native ERC-20 or multi-asset fee payment, or protocol-defined fee conversion
  • Define a universal permissions system for arbitrary contract interactions
  • Remove the need for smart contract wallets or EIP-7702 delegation for advanced functionality
  • Add blob semantics or expand EIP-4844 transaction behavior

The goal of this EIP is to standardize a limited set of transaction-level primitives that address common UX requirements, not to subsume more expressive abstraction frameworks.

Specification

Parameters

Parameter Value
EIPXXX_TX_TYPE 0x76
FEE_PAYER_MAGIC 0x78
MAX_WEBAUTHN_SIG_SIZE 2049

Transaction Type

An EIP-XXX Transaction is an EIP-2718 typed transaction with transaction type byte 0x76.

Transaction Payload

The TransactionPayload is the RLP encoding of:

rlp([
  chain_id,
  max_priority_fee_per_gas,
  max_fee_per_gas,
  gas_limit,
  calls,
  access_list,
  nonce_key,
  nonce,
  valid_before,
  valid_after,
  fee_payer_signature,
  authorization_list,
  sender_signature
])

Field Semantics

Standard Fee Fields

  • chain_id: chain identifier for replay protection (EIP-155)
  • max_priority_fee_per_gas, max_fee_per_gas, gas_limit: EIP-1559 semantics

Calls (Batching)

calls := [ [to, value, input], ... ]
  • calls MUST be non-empty.
  • Calls MUST be executed sequentially in the order provided.
  • If any call reverts, the entire transaction MUST revert.
  • A call tuple MUST be interpreted as CALL(to, input, value) executed in the transaction context, except that:
    • to MAY indicate contract creation if a create marker is used (TxKind).
    • Creation semantics (address derivation, initcode, etc.) follow existing EVM rules for contract creation.

Access List

access_list follows EIP-2930 semantics.

Parallelizable Nonces (2D Nonces)

  • nonce_key: uint256
  • nonce: uint64

Nonce validation rules:

  • If nonce_key == 0, the transaction uses the sender’s protocol nonce stored in the account state.
  • If nonce_key > 0, the transaction uses an independent nonce stream identified by (sender_address, nonce_key).

Nonce keys whose most significant byte is 0x5b are reserved and MUST be rejected unless enabled by a future fork.

After successful inclusion, the relevant nonce stream MUST be incremented by one.

Validity Window (Scheduled / Expiring)

  • valid_after: optional unix timestamp lower bound
  • valid_before: optional unix timestamp upper bound

A transaction is valid in a block with timestamp ts iff:

  • valid_after is unset OR ts >= valid_after
  • AND valid_before is unset OR ts <= valid_before

Unset values MUST be encoded as 0x80.

Gas Sponsorship

fee_payer_signature is optional.

  • If absent, gas fees MUST be charged to the sender.
  • If present, gas fees MUST be charged to the recovered fee_payer_address.

This EIP does not define ERC-20 fee payment. Sponsors requiring reimbursement in other assets MUST only co-sign transactions that include explicit compensating calls.

Signature Domains

Sender Signature

The sender MUST sign:

sender_hash = keccak256(
  0x76 || rlp([
    chain_id,
    max_priority_fee_per_gas,
    max_fee_per_gas,
    gas_limit,
    calls,
    access_list,
    nonce_key,
    nonce,
    valid_before,
    valid_after,
    fee_payer_placeholder,
    authorization_list,
  ])
)

Where:

  • If a fee payer signature will be present, fee_payer_placeholder MUST be 0x00.
  • Otherwise, it MUST be 0x80.

Fee Payer Signature

If present, the fee payer MUST sign:

fee_payer_hash = keccak256(
  0x78 || rlp([
    chain_id,
    max_priority_fee_per_gas,
    max_fee_per_gas,
    gas_limit,
    calls,
    access_list,
    nonce_key,
    nonce,
    valid_before,
    valid_after,
    sender_address,
    authorization_list,
  ])
)

Fee payer signatures MUST be secp256k1.

Signature Types

sender_signature MUST be parsed as one of the following encodings:

secp256k1 (65 bytes)

  • Encoding: r(32) || s(32) || v(1)
  • Detection: exactly 65 bytes
  • Verification: ecrecover(sender_hash, v, r, s) with low-s rule as per EIP-2.

P-256 (130 bytes)

  • Encoding: 0x01 || r(32) || s(32) || pub_key_x(32) || pub_key_y(32) || pre_hash(1)
  • Detection: first byte 0x01 and total length 130
  • Verification: verify P-256 signature of sender_hash using the provided public key.
  • If pre_hash == 1, verifiers MUST compute digest = sha256(sender_hash) and verify against digest instead.

WebAuthn (variable, max 2049 bytes)

  • Encoding: 0x02 || webauthn_data || r(32) || s(32) || pub_key_x(32) || pub_key_y(32)
  • Detection: first byte 0x02
  • Size: total signature encoding MUST be ≤ MAX_WEBAUTHN_SIG_SIZE bytes
  • Verification: verifiers MUST:
    1. Parse webauthn_data as authenticatorData || clientDataJSON.
    2. Validate that clientDataJSON includes "type":"webauthn.get".
    3. Validate that clientDataJSON includes a "challenge" value equal to base64url(sender_hash).
    4. Compute clientDataHash = sha256(clientDataJSON) and messageHash = sha256(authenticatorData || clientDataHash).
    5. Verify a P-256 signature (r,s) over messageHash using (pub_key_x, pub_key_y).
  • Implementations SHOULD require the User Presence (UP) flag in authenticatorData to be set.

Keychain Wrapper (variable)

  • Encoding: 0x03 || user_address(20) || inner_signature
  • Detection: first byte 0x03
  • Semantics:
    • user_address is the root account whose transaction is being authorized.
    • inner_signature MUST be a valid sender signature encoding (secp256k1 / P-256 / WebAuthn).
    • The recovered/derived signer of inner_signature is the access key identifier key_id.
    • The protocol MUST validate that key_id is authorized for user_address under the Access Key rules below.

Address Derivation

For P-256 and WebAuthn signatures, the signer address MUST be derived as:

address = last20bytes(keccak256(pub_key_x || pub_key_y))

For secp256k1 signatures, address derivation follows standard Ethereum conventions.

Authorization List (EIP-7702 Interop)

authorization_list is OPTIONAL. If present, it MUST be a list of tuples formatted as:

authorization_list = [[chain_id, address, nonce, y_parity, r, s], ...]

If authorization_list is present, clients MUST process it using the same state transition semantics defined in EIP-7702 (including the MAGIC-prefixed signing domain, tuple validation rules, code-setting semantics, and the "continue on failure" per-tuple behavior), except that the sender transaction type is 0x76 rather than 0x04.

Unless explicitly stated otherwise by a future fork, the effects of processing authorization_list MUST NOT be reverted if execution of the subsequent batched calls reverts (matching EIP-7702 behavior for authorizations).

Access Keys

This EIP intentionally does not define access keys directly. A companion EIP (EIP-XXX: Access Keys) specifies an optional protocol-enforced access key subsystem that can be used with this transaction type.

Execution Semantics

After transaction validity checks, the protocol MUST execute calls sequentially:

  • tx.origin MUST be the root account (sender_address for non-Keychain signatures, or user_address for Keychain signatures).
  • The first-frame msg.sender MUST equal tx.origin.

If the sender account has EIP-7702 delegation code, execution MUST follow EIP-7702 delegation semantics for code-executing operations.

State Transition Order (Normative)

Clients MUST apply the following state transition order for an EIP-XXX Transaction:

  1. Decode the typed transaction and verify it is well-formed RLP.
  2. Compute intrinsic gas (see Gas Costs) and verify gas_limit >= intrinsic_gas.
  3. Validate time bounds: check valid_after / valid_before against block.timestamp.
  4. Verify sender signature and recover/derive the root account:
    • If Keychain wrapper: derive key_id from inner_signature, set root = user_address.
    • Otherwise: derive root = sender_address from the signature.
  5. Resolve fee payer:
    • If no fee_payer_signature, set fee_payer = root.
    • If present: verify fee_payer_signature over fee_payer_hash and set fee_payer to the recovered address.
  6. Validate nonce:
    • If nonce_key == 0: require tx.nonce == account.nonce(root).
    • Else: require tx.nonce == nonce_stream(root, nonce_key).
  7. Balance check for fees: require balance(fee_payer) >= gas_limit * max_fee_per_gas (per EIP-1559 semantics; refunds apply after execution).
  8. Increment nonce stream (EVM rules):
    • Increment the relevant nonce stream for root by 1 before processing authorization_list and executing calls.
  9. Process authorization_list (if present) using EIP-7702 semantics.
  10. Execute batched calls sequentially.
  11. Finalize gas accounting per EIP-1559 (charge fee payer, refund unused gas).
  12. Emit receipt as specified below.

Receipt Format

Receipts for EIP-XXX Transactions are typed.

The receipt MUST be encoded as:

0x76 || rlp([
  status,
  cumulative_gas_used,
  logs_bloom,
  call_receipts
])

Where:

call_receipts := [
  [ success, gas_used, logs ],
  ...
]
  • call_receipts MUST have the same length as calls.
  • Each entry corresponds to the call at the same index.
  • success MUST be 1 if the call returned successfully and 0 if it reverted.
  • gas_used MUST be the gas consumed by the call (exclusive of subsequent calls).
  • logs MUST contain only logs emitted during that call.
  • logs_bloom MUST be the bloom over all logs across all calls.
  • cumulative_gas_used follows legacy receipt semantics.

If the overall transaction reverts, status MUST be 0, and call_receipts MUST reflect the call-level results up to the point of failure (clients MAY choose to include empty receipts for unexecuted calls; if so, they MUST set success=0, gas_used=0, and logs=[] for those entries).

Transaction Pool Requirements

This section specifies requirements for transaction pool (mempool) handling of EIP-XXX Transactions. These requirements are intended to preserve denial-of-service resistance, minimize invalid transaction propagation, and ensure consistent behavior across clients.

Admission Checks

A node MUST reject an EIP-XXX Transaction from its transaction pool if any of the following conditions hold:

  • The transaction is not well-formed RLP for type 0x76.
  • The sender signature encoding is invalid or exceeds MAX_WEBAUTHN_SIG_SIZE.
  • Signature verification fails for the sender signature (including WebAuthn challenge validation rules).
  • If present, the fee payer signature is malformed, unrecoverable, or fails verification.
  • gas_limit < intrinsic_gas as computed in this EIP.
  • The transaction is already expired at time of admission (block_timestamp > valid_before, if valid_before is set).

A node SHOULD defer (not broadcast, but may keep locally) a transaction whose valid_after is in the future. If retained, it MUST NOT be considered eligible for block inclusion prior to valid_after.

State-Dependent Pool Classification

For pool ordering and readiness, a node MUST treat the effective sender for nonce purposes as:

  • root = sender_address for non-Keychain signatures; or
  • root = user_address for Keychain signatures.

A node MUST maintain per-root readiness across nonce streams, keyed by (nonce_key, nonce):

  • For nonce_key == 0, readiness is identical to legacy nonce sequencing.
  • For nonce_key > 0, readiness MUST be evaluated independently per nonce_key.

Transactions MUST be considered executable from the pool only if their (root, nonce_key, nonce) matches the current on-chain value for that nonce stream. Transactions with higher nonces for the same (root, nonce_key) SHOULD be placed in a queued pool until predecessors are mined.

Replacement Rules

Clients SHOULD apply replace-by-fee (RBF) rules independently per (root, nonce_key, nonce) tuple. Specifically, a transaction T2 MAY replace T1 in the pool only if:

  • root, nonce_key, and nonce are identical, and
  • T2 provides a sufficiently higher effective fee than T1 under EIP-1559 replacement policy.

Fee Payer and Balance-Dependency

If a fee payer signature is present, pool admission and eviction MUST consider that transaction validity depends on the fee payer’s ability to cover fees.

A node SHOULD perform a state-dependent funds check for fee_payer at admission and SHOULD re-check when the pool is revalidated against a new head, consistent with existing EIP-1559 pool behavior.

EIP-7702 Authorization List Side-Effects

Because authorization_list may mutate account code and nonces for authorities other than the transaction root (per EIP-7702), pool implementations MUST be robust to cross-account invalidation.

A node MAY apply additional anti-DoS policy for transactions with non-empty authorization_list (e.g., limiting the number of concurrent pending transactions for accounts whose code is delegated), consistent with EIP-7702’s transaction pool considerations.

Gas Costs

Intrinsic Gas Formula

intrinsic_gas =
  21_000
+ calldata_gas(payload_bytes)
+ access_list_gas(access_list)
+ signature_gas(sender_signature)
+ nonce_key_gas(root, nonce_key)
+ fee_payer_signature_gas(fee_payer_signature)

Signature Verification Gas

Signature Type Additional Gas
secp256k1 0
P-256 5,000
WebAuthn 5,000 + calldata_gas(webauthn_data)
Keychain wrapper inner signature gas + 3,000

Parallel Nonce Key Gas

Nonce Key Case Gas
nonce_key == 0 0
Existing nonce key 5,000
New nonce key 22,100

Fee Payer Signature Gas

If fee_payer_signature is present, clients MUST validate it. Implementations MUST ensure the validation work is bounded and comparable to a standard ecrecover operation. Clients MAY charge a fixed 3,000 gas for this validation.

Boundedness

Clients MUST reject WebAuthn signatures whose total signature encoding exceeds MAX_WEBAUTHN_SIG_SIZE.

Rationale

No Native Fee Token

Ethereum does not include a native fee conversion mechanism. Introducing a fee token field would require protocol-defined conversion or acceptance rules and create additional consensus complexity. This EIP therefore restricts protocol fee payment to ETH and supports reimbursement in other assets only through explicit calls that sponsors can verify before co-signing.

Constrained Scope vs General Frameworks

This EIP deliberately standardizes a limited set of transaction-level primitives. This is intended to simplify reasoning about transaction validity, gas accounting, and security properties compared to highly general authorization and execution frameworks.

Backwards Compatibility

This EIP introduces a new transaction type and does not change the validity of legacy transactions.

Clients that do not implement this EIP will treat transactions of type 0x76 as unknown and reject them; post-fork, all consensus clients MUST implement the new type.

Security Considerations

  • Sponsors MUST validate transactions before signing, including validating any reimbursement call(s).
  • WebAuthn parsing and verification MUST be bounded; the signature size cap is REQUIRED.
  • Domain separation (0x76 vs 0x78) prevents cross-role signature replay.
  • Access keys increase delegation surface area; implementations SHOULD support revocation and short expiries.

Copyright

Copyright and related rights waived via CC0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment