| 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 |
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.
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.
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.
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.
| Parameter | Value |
|---|---|
EIPXXX_TX_TYPE |
0x76 |
FEE_PAYER_MAGIC |
0x78 |
MAX_WEBAUTHN_SIG_SIZE |
2049 |
An EIP-XXX Transaction is an EIP-2718 typed transaction with transaction type byte 0x76.
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
])
chain_id: chain identifier for replay protection (EIP-155)max_priority_fee_per_gas,max_fee_per_gas,gas_limit: EIP-1559 semantics
calls := [ [to, value, input], ... ]
callsMUST 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:toMAY 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 follows EIP-2930 semantics.
nonce_key:uint256nonce: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.
valid_after: optional unix timestamp lower boundvalid_before: optional unix timestamp upper bound
A transaction is valid in a block with timestamp ts iff:
valid_afteris unset ORts >= valid_after- AND
valid_beforeis unset ORts <= valid_before
Unset values MUST be encoded as 0x80.
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.
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_placeholderMUST be0x00. - Otherwise, it MUST be
0x80.
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.
sender_signature MUST be parsed as one of the following encodings:
- Encoding:
r(32) || s(32) || v(1) - Detection: exactly 65 bytes
- Verification:
ecrecover(sender_hash, v, r, s)with low-srule as per EIP-2.
- Encoding:
0x01 || r(32) || s(32) || pub_key_x(32) || pub_key_y(32) || pre_hash(1) - Detection: first byte
0x01and total length 130 - Verification: verify P-256 signature of
sender_hashusing the provided public key. - If
pre_hash == 1, verifiers MUST computedigest = sha256(sender_hash)and verify againstdigestinstead.
- 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_SIZEbytes - Verification: verifiers MUST:
- Parse
webauthn_dataasauthenticatorData || clientDataJSON. - Validate that
clientDataJSONincludes"type":"webauthn.get". - Validate that
clientDataJSONincludes a"challenge"value equal tobase64url(sender_hash). - Compute
clientDataHash = sha256(clientDataJSON)andmessageHash = sha256(authenticatorData || clientDataHash). - Verify a P-256 signature
(r,s)overmessageHashusing(pub_key_x, pub_key_y).
- Parse
- Implementations SHOULD require the User Presence (UP) flag in
authenticatorDatato be set.
- Encoding:
0x03 || user_address(20) || inner_signature - Detection: first byte
0x03 - Semantics:
user_addressis the root account whose transaction is being authorized.inner_signatureMUST be a valid sender signature encoding (secp256k1 / P-256 / WebAuthn).- The recovered/derived signer of
inner_signatureis the access key identifierkey_id. - The protocol MUST validate that
key_idis authorized foruser_addressunder the Access Key rules below.
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 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).
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.
After transaction validity checks, the protocol MUST execute calls sequentially:
tx.originMUST be the root account (sender_addressfor non-Keychain signatures, oruser_addressfor Keychain signatures).- The first-frame
msg.senderMUST equaltx.origin.
If the sender account has EIP-7702 delegation code, execution MUST follow EIP-7702 delegation semantics for code-executing operations.
Clients MUST apply the following state transition order for an EIP-XXX Transaction:
- Decode the typed transaction and verify it is well-formed RLP.
- Compute intrinsic gas (see Gas Costs) and verify
gas_limit >= intrinsic_gas. - Validate time bounds: check
valid_after/valid_beforeagainstblock.timestamp. - Verify sender signature and recover/derive the root account:
- If Keychain wrapper: derive
key_idfrominner_signature, setroot = user_address. - Otherwise: derive
root = sender_addressfrom the signature.
- If Keychain wrapper: derive
- Resolve fee payer:
- If no
fee_payer_signature, setfee_payer = root. - If present: verify
fee_payer_signatureoverfee_payer_hashand setfee_payerto the recovered address.
- If no
- Validate nonce:
- If
nonce_key == 0: requiretx.nonce == account.nonce(root). - Else: require
tx.nonce == nonce_stream(root, nonce_key).
- If
- Balance check for fees: require
balance(fee_payer) >= gas_limit * max_fee_per_gas(per EIP-1559 semantics; refunds apply after execution). - Increment nonce stream (EVM rules):
- Increment the relevant nonce stream for
rootby 1 before processingauthorization_listand executing calls.
- Increment the relevant nonce stream for
- Process
authorization_list(if present) using EIP-7702 semantics. - Execute batched
callssequentially. - Finalize gas accounting per EIP-1559 (charge fee payer, refund unused gas).
- Emit receipt as specified below.
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_receiptsMUST have the same length ascalls.- Each entry corresponds to the call at the same index.
successMUST be1if the call returned successfully and0if it reverted.gas_usedMUST be the gas consumed by the call (exclusive of subsequent calls).logsMUST contain only logs emitted during that call.logs_bloomMUST be the bloom over all logs across all calls.cumulative_gas_usedfollows 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).
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.
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_gasas computed in this EIP.- The transaction is already expired at time of admission (
block_timestamp > valid_before, ifvalid_beforeis 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.
For pool ordering and readiness, a node MUST treat the effective sender for nonce purposes as:
root = sender_addressfor non-Keychain signatures; orroot = user_addressfor 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 pernonce_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.
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, andnonceare identical, andT2provides a sufficiently higher effective fee thanT1under EIP-1559 replacement policy.
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.
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.
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 Type | Additional Gas |
|---|---|
| secp256k1 | 0 |
| P-256 | 5,000 |
| WebAuthn | 5,000 + calldata_gas(webauthn_data) |
| Keychain wrapper | inner signature gas + 3,000 |
| Nonce Key Case | Gas |
|---|---|
nonce_key == 0 |
0 |
| Existing nonce key | 5,000 |
| New nonce key | 22,100 |
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.
Clients MUST reject WebAuthn signatures whose total signature encoding exceeds MAX_WEBAUTHN_SIG_SIZE.
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.
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.
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.
- 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 (
0x76vs0x78) prevents cross-role signature replay. - Access keys increase delegation surface area; implementations SHOULD support revocation and short expiries.
Copyright and related rights waived via CC0.