--- eip: 8202 title: Scheme-Agile Transactions description: A new EIP-2718 transaction type with a common EIP-1559 fee header, scheme-agile sender authorization, and flat typed extensions author: Giulio Rebuffo (@Giulio2002), Ben Adams (@benaadams) discussions-to: https://ethereum-magicians.org/t/eip-8202-schemed-transaction/28044 status: Draft type: Standards Track category: Core created: 2026-03-22 requires: 2, 155, 1559, 2718, 2780, 4844, 7702, 7976 --- ## Abstract This EIP introduces a new [EIP-2718](./eip-2718.md) typed transaction (`TransactionType = 0x05`) called `SchemedTransaction`. A `SchemedTransaction` has one common [EIP-1559](./eip-1559.md)-style fee header and one common execution payload (`to`, `value`, `data`). Optional features are attached as flat typed components inside the payload rather than by minting a new top-level transaction family for every combination. The transaction has two typed attachment lists: * `authorizations` - ordered transaction authorizations * `extensions` - flat typed extensions, unique by `extension_id` Scheme agility is expressed as an authorization capability, not a separate transaction family. This EIP initially defines one required top-level authorization role, `SENDER`, and two sender signature schemes: * secp256k1 ECDSA * Ephemeral secp256k1 (Merkle-committed one-time ECDSA keys) This EIP also defines two initial extensions: * a blob extension carrying the transaction-local blob fields of [EIP-4844](./eip-4844.md) * a set-code extension carrying [EIP-7702](./eip-7702.md)-style pre-execution authorizations The extension model is open to future additions. For example, an [EIP-8141](./eip-8141.md)-style frame extension could attach nested execution frames to the same transaction envelope without requiring a new top-level transaction type. The sender address is derived deterministically from the public key recovered or verified from the `SENDER` authorization. For secp256k1, address derivation is exactly the same as legacy Ethereum. For ephemeral secp256k1, the address is derived from a Merkle root over the full key sequence, providing a stable identity across key rotations. This design keeps transaction composition flat: one execution payload, many orthogonal capabilities, and no recursive transaction structure or frame execution model. ## Motivation ### Stop proliferating top-level transaction families Ethereum currently adds new features such as blobs and set-code authorizations by minting fresh [EIP-2718](./eip-2718.md) transaction types whose payloads are each mostly [EIP-1559](./eip-1559.md)-shaped with a few appended fields. That approach does not compose well. A user who wants passkey signing, blobs, and set-code authorization should not require yet another top-level transaction family. The cleaner model is: * [EIP-1559](./eip-1559.md) is the common fee header * call/create is the base execution payload * blobs are an optional extension * set-code authorization is an optional pre-execution extension * scheme agility is the sender authorization mechanism Under [EIP-2718](./eip-2718.md), the payload of a typed transaction is already just an opaque byte string. This EIP uses that flexibility to define one outer type whose inner parts compose cleanly. ### Native quantum-safe support Quantum computers will eventually break ECDSA over secp256k1. Ethereum needs a user-facing transaction format that lets EOAs migrate to quantum-safe signing without wrapping execution in a new abstraction. The ephemeral secp256k1 scheme achieves quantum safety by making each key pair single-use, eliminating long-term public key exposure. This requires no new cryptographic primitives beyond Keccak-256 preimage resistance. Future signature schemes (P256/passkeys, Falcon-512, or other post-quantum algorithms) can be added as new `scheme_id` values without changing the transaction envelope. ### Flat composition, not recursive composition This EIP is intentionally not a frame transaction system. It does not introduce recursive transactions, multiple execution payloads, new execution modes, or new opcodes. The model is: * one execution payload * one or more typed authorizations * zero or more typed extensions This keeps validation phase-based and close to today's transaction processing, while still allowing new protocol features and new signature schemes to be added without minting a new outer transaction type for every combination. ## Specification ### Constants | Name | Value | Description | | ------------------------ | ------- | ------------------------------------------------------- | | `SCHEMED_TX_TYPE` | `0x05` | [EIP-2718](./eip-2718.md) transaction type byte | | `ROLE_SENDER` | `0x00` | Top-level sender authorization | | `ROLE_PAYER` | `0x01` | Reserved for future use | | `SCHEME_SECP256K1` | `0x00` | secp256k1 ECDSA | | `SCHEME_EPHEMERAL_K1` | `0x01` | Ephemeral secp256k1 with Merkle-committed key rotation | | `EXT_BLOB` | `0x01` | Blob extension | | `EXT_SET_CODE` | `0x02` | Set-code / delegation extension | | `SET_CODE_AUTH_MAGIC` | `0x05` | Domain byte for set-code authorization messages | | `PER_AUTH_BASE_COST` | `12500` | Per-authorization processing base cost | | `PER_EMPTY_ACCOUNT_COST` | `25000` | Per-authorization intrinsic charge | | `EPHEMERAL_TREE_DEPTH` | `20` | Merkle tree depth for ephemeral key commitments | | `EPHEMERAL_PROOF_LEN` | `640` | Merkle proof length in bytes (20 × 32) | The `role_id`, `scheme_id`, and `extension_id` spaces each range from `0x00` to `0xFF`. New values MUST be specified by a distinct EIP. `SET_CODE_AUTH_MAGIC`, `PER_AUTH_BASE_COST`, and `PER_EMPTY_ACCOUNT_COST` intentionally match the corresponding [EIP-7702](./eip-7702.md) constants. ### Transaction Envelope A `SchemedTransaction` is serialized as: 0x05 || rlp([ chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data, authorizations, extensions ]) ``` This defines one canonical base transaction body: base = [ chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data ] ``` #### Field Definitions | Field | Type | Description | | -------------------------- | --------------------- | ------------------------------------------------ | | `chain_id` | `uint256` | [EIP-155](./eip-155.md) chain identifier | | `nonce` | `uint64` | Sender account nonce | | `max_priority_fee_per_gas` | `uint256` | [EIP-1559](./eip-1559.md) priority fee | | `max_fee_per_gas` | `uint256` | [EIP-1559](./eip-1559.md) max fee | | `gas_limit` | `uint64` | Gas limit | | `to` | `Address \| null` | Recipient address, or null for contract creation | | `value` | `uint256` | Wei to transfer | | `data` | `bytes` | Calldata / initcode | | `authorizations` | `List[Authorization]` | Ordered transaction authorizations | | `extensions` | `List[Extension]` | Typed extension list | Base rules: * `to = null` means contract creation. * There is no `access_list` in the base transaction type. * `authorizations` is ordered and the order is signed. * `extensions` is a flat typed list and MUST be unique by `extension_id`. * Unknown `extension_id` is invalid. * Exactly one `ROLE_SENDER` authorization is required. * In this version, `ROLE_PAYER` is reserved and MUST NOT appear. ### Authorization and Extension Containers An authorization is encoded as: ```text authorization = [role_id, scheme_id, witness] ``` An extension is encoded as: ```text extension = [extension_id, extension_payload] ``` `witness` and `extension_payload` are opaque bytes whose internal meaning is determined by `scheme_id` and `extension_id` respectively. In this EIP, each defined witness or extension payload is itself a canonical RLP encoding of the scheme-specific or extension-specific structure. ### Signing Data The sender signs the full base transaction and all extensions, with authorization witnesses elided from the current and later authorization positions. For this EIP, valid transactions contain exactly one top-level authorization, so this reduces to signing the full transaction with the sender witness omitted. ```python def signing_hash(tx, auth_index): committed_auths = [] for j, auth in enumerate(tx.authorizations): if j < auth_index: committed_auths.append(auth) else: committed_auths.append([auth.role_id, auth.scheme_id]) return keccak256( SCHEMED_TX_TYPE || rlp([ tx.chain_id, tx.nonce, tx.max_priority_fee_per_gas, tx.max_fee_per_gas, tx.gas_limit, tx.to, tx.value, tx.data, committed_auths, tx.extensions ]) ) ``` For the required sender authorization at index `0`, this is equivalent to: ```python def sender_signing_hash(tx): return keccak256( SCHEMED_TX_TYPE || rlp([ tx.chain_id, tx.nonce, tx.max_priority_fee_per_gas, tx.max_fee_per_gas, tx.gas_limit, tx.to, tx.value, tx.data, [[ROLE_SENDER, tx.authorizations[0].scheme_id]], tx.extensions ]) ) ``` ### Scheme Registry Each registered signature scheme defines: * `scheme_id` * witness format * `verify_or_recover(message, witness) -> pubkey` * sender address derivation * intrinsic gas surcharge This EIP initially defines two `scheme_id` values. ### Signature Schemes #### secp256k1 (`0x00`) Witness payload: ```text rlp([y_parity, r, s]) ``` | Field | Size | | ---------- | -------- | | `y_parity` | 1 byte | | `r` | 32 bytes | | `s` | 32 bytes | `s` MUST satisfy `s <= secp256k1n / 2` per [EIP-2](./eip-2.md). Public key recovery and address derivation: ```python pubkey = ecrecover(sender_signing_hash(tx), y_parity, r, s) # 64-byte uncompressed x || y sender = keccak256(pubkey)[12:] ``` This intentionally preserves legacy Ethereum address derivation for secp256k1 keys. Scheme gas surcharge: **0**. #### Ephemeral secp256k1 (`0x01`) This scheme achieves quantum safety by making each secp256k1 key pair single-use. At account creation, the user derives a deterministic sequence of key pairs (e.g. via [BIP 44]) and commits to all future public keys by constructing a Merkle tree over their hashes. The Merkle root is embedded in the sender address. Each transaction provides a standard ECDSA signature plus a Merkle proof that the signing key is the leaf at position `nonce` in the committed tree. [BIP 44]: https://github.com/bitcoin/bips/blob/69a63f629f4c27b249882b4e0db6af516f1bcea9/bip-0044.mediawiki The long-lived secret is the user's seed (e.g. a BIP-39 mnemonic), which never touches the chain. Each ephemeral private key `sk_i` is derived on-the-fly, used exactly once for the transaction at nonce `i`, and is never valid again because the protocol binds the Merkle leaf index to the account nonce. ##### Account Setup Account setup is performed entirely off-chain: ```python seed = generate_bip39_mnemonic() leaves = [] for i in range(2**EPHEMERAL_TREE_DEPTH): sk_i = derive_bip44(seed, path=f"m/44'/60'/0'/0/{i}") pk_i = secp256k1_pubkey(sk_i) # 64 bytes, uncompressed x || y leaves.append(keccak256(pk_i)) merkle_root = build_merkle_tree(leaves) # binary Keccak-256 Merkle tree # The address is derived from the root — no on-chain state required address = keccak256(SCHEME_EPHEMERAL_K1 || merkle_root)[12:] ``` No on-chain registration, storage writes, or contract deployment is required. The Merkle root is carried in every transaction witness and validated against the sender address. ##### Witness Payload ```text rlp([y_parity, r, s, merkle_root, merkle_proof]) ``` | Field | Size | | -------------- | --------------------------------------- | | `y_parity` | 1 byte | | `r` | 32 bytes | | `s` | 32 bytes | | `merkle_root` | 32 bytes | | `merkle_proof` | `EPHEMERAL_TREE_DEPTH * 32` = 640 bytes | `s` MUST satisfy `s <= secp256k1n / 2` per [EIP-2](./eip-2.md). `merkle_proof` is an ordered list of `EPHEMERAL_TREE_DEPTH` sibling hashes for the leaf-to-root path. ##### Signing ```python def sign_ephemeral(tx, seed, merkle_tree): i = tx.nonce sk_i = derive_bip44(seed, path=f"m/44'/60'/0'/0/{i}") # Compute signing hash — identical to all other schemes msg = sender_signing_hash(tx) # Standard secp256k1 ECDSA y_parity, r, s = ecdsa_sign(sk_i, msg) # Merkle proof that pk_i is the leaf at position i merkle_root = merkle_tree.root merkle_proof = merkle_tree.prove(i) # EPHEMERAL_TREE_DEPTH × 32 bytes # Construct the witness witness = rlp([y_parity, r, s, merkle_root, merkle_proof]) # Build the authorization tx.authorizations = [[ROLE_SENDER, SCHEME_EPHEMERAL_K1, witness]] return tx ``` ##### Verification and Address Derivation ```python def verify_ephemeral_k1(tx): auth = tx.authorizations[0] assert auth.role_id == ROLE_SENDER assert auth.scheme_id == SCHEME_EPHEMERAL_K1 y_parity, r, s, merkle_root, merkle_proof = rlp_decode(auth.witness) # 1. Address binding — the Merkle root must match the sender address derived_address = keccak256(SCHEME_EPHEMERAL_K1 || merkle_root)[12:] assert derived_address == tx.sender # 2. Recover public key from ECDSA signature msg = sender_signing_hash(tx) pubkey = ecrecover(msg, y_parity, r, s) # 3. Merkle membership — pubkey hash must be the leaf at position nonce leaf = keccak256(pubkey) assert verify_merkle_proof(merkle_root, merkle_proof, leaf, index=tx.nonce) # 4. Standard s-value check (EIP-2) assert s <= secp256k1n // 2 return derived_address ``` The Merkle proof verification uses a standard binary Keccak-256 Merkle tree. `verify_merkle_proof` checks that hashing the leaf with the provided sibling path from position `index` produces `merkle_root`. ##### Key Material Summary | Secret | Location | On-chain exposure | | --- | --- | --- | | [BIP 39] seed | User's device only | Never | | `sk_i` (ephemeral private key) | Derived on-the-fly for nonce `i` | Never (public key exposed for exactly one transaction) | | `merkle_root` | Encoded in the address, carried in witness | Fully public by design | | `merkle_tree` | User's device (or recomputable from seed) | Per-transaction proof is public | [BIP 39]: https://github.com/bitcoin/bips/blob/69a63f629f4c27b249882b4e0db6af516f1bcea9/bip-0039.mediawiki ##### Why This Is Quantum-Safe After transaction at nonce `i`, the attacker observes `pk_i` (recoverable from the ECDSA signature). A quantum computer running Shor's algorithm can derive `sk_i` from `pk_i`. However, `sk_i` is now useless: the next valid transaction requires nonce `i+1`, which requires a Merkle proof for leaf `i+1`. To forge that transaction, the attacker needs `sk_{i+1}`, which requires `pk_{i+1}`, which requires inverting `keccak256(pk_{i+1})` from the Merkle leaf — a preimage attack on Keccak-256. Grover's algorithm provides a quadratic speedup on brute-force preimage search but Keccak-256 retains 128-bit security against Grover's, which is computationally infeasible. The security assumption is therefore: Keccak-256 preimage resistance, not the hardness of the discrete logarithm problem. Scheme gas surcharge: **5,000 gas**. ### Extensions Extensions attach optional typed protocol features to the transaction without minting a new outer transaction type. Each extension is encoded as: ```text extension = [extension_id, extension_payload] ``` Rules: * `extensions` MUST be unique by `extension_id` * unknown `extension_id` is invalid * extension payloads are fully committed by the sender signing hash * extension processing is flat and non-recursive This EIP defines two initial extensions. #### Blob Extension (`EXT_BLOB = 0x01`) Extension payload: ```text rlp([max_fee_per_blob_gas, blob_versioned_hashes]) ``` | Field | Type | Description | | ----------------------- | --------------- | ------------------------------------- | | `max_fee_per_blob_gas` | `uint256` | Per-blob gas cap | | `blob_versioned_hashes` | `List[bytes32]` | Versioned hashes for referenced blobs | This extension carries the transaction-local blob fields of [EIP-4844](./eip-4844.md) under a typed extension instead of requiring a dedicated top-level blob transaction family. [EIP-4844](./eip-4844.md) defines these as `max_fee_per_blob_gas` and `blob_versioned_hashes`, and blob transactions there also forbid `to = nil`; this extension preserves those transaction-local semantics. The sidecar format, blob fee lane, and block-level blob accounting remain those of [EIP-4844](./eip-4844.md). Additional rules: * if `EXT_BLOB` is present, `to` MUST NOT be `null` * `blob_versioned_hashes` MUST be non-empty * blob validity, fee charging, and inclusion rules follow [EIP-4844](./eip-4844.md) #### Set-Code Extension (`EXT_SET_CODE = 0x02`) Extension payload: ```text rlp([authorization_list]) ``` Where each authorization item is: ```text set_code_authorization = [chain_id, delegate_address, nonce, scheme_id, witness] ``` This extension carries [EIP-7702](./eip-7702.md)-style pre-execution set-code authorizations. All processing rules, gas constants, and refund behavior follow [EIP-7702](./eip-7702.md). The differences from [EIP-7702](./eip-7702.md) are: * `(y_parity, r, s)` is replaced by `(scheme_id, witness)`, making authorizations scheme-agile * `scheme_id` is included in the authorization message hash: `keccak256(SET_CODE_AUTH_MAGIC || rlp([chain_id, delegate_address, nonce, scheme_id]))` * authority address derivation uses the same scheme-specific rules as top-level sender authorization * no inherited `access_list` intrinsic charge (the base envelope has no `access_list`) If `EXT_SET_CODE` is present, `authorization_list` MUST be non-empty. ##### Set-Code Gas Accounting Relative to [EIP-7702](./eip-7702.md), the gas accounting delta is only envelope-level: * this extension charges `25000` per authorization exactly as [EIP-7702](./eip-7702.md) does * this extension refunds `12500` for non-empty `authority` exactly as [EIP-7702](./eip-7702.md) does * unlike [EIP-7702](./eip-7702.md), there is no inherited access-list intrinsic charge because `SchemedTransaction` has no base `access_list` The set-code authorization gas constants and refund behavior are otherwise identical to [EIP-7702](./eip-7702.md). The intrinsic gas for a `SchemedTransaction` follows the decomposed model of [EIP-2780](./eip-2780.md) and the calldata floor of [EIP-7976](./eip-7976.md): ```text intrinsic_gas = TX_BASE_COST + calldata_gas(data) + sender_scheme_gas_surcharge(sender_authorization) + extension_intrinsic_gas(extensions) ``` Where `TX_BASE_COST` is the decomposed base cost from [EIP-2780](./eip-2780.md) (replacing the legacy flat 21,000) and `calldata_gas` follows the uniform per-byte floor of [EIP-7976](./eip-7976.md). The sender scheme surcharge replaces the `ECRECOVER` component of the [EIP-2780](./eip-2780.md) base cost. For secp256k1, the cost is equivalent. For other schemes, the surcharge reflects the verification cost and witness size: | Scheme | Surcharge | | -------------------- | --------- | | `SCHEME_SECP256K1` | 0 | | `SCHEME_EPHEMERAL_K1`| 5,000 | Extension-specific charging rules are: * `EXT_BLOB` reuses the blob fee lane and blob accounting of [EIP-4844](./eip-4844.md) * `EXT_SET_CODE` adds `25000 * len(authorization_list)` intrinsic gas and refunds `12500` for each successfully processed non-empty authority The overhead of a non-secp256k1 sender scheme relative to a standard ECDSA transaction is: ```text scheme_overhead = calldata_cost(scheme_witness) - calldata_cost(ecdsa_witness) + scheme_surcharge ``` Where `ecdsa_witness` is the 65-byte secp256k1 `(y_parity, r, s)` witness and `calldata_cost` follows the [EIP-7976](./eip-7976.md) uniform floor (64 gas/byte). For ephemeral secp256k1 (737-byte witness including Merkle root and proof), the calldata overhead is `(737 - 65) * 64 = 43,008 gas` plus the 5,000 gas surcharge; verification is a standard ecrecover plus `EPHEMERAL_TREE_DEPTH` Keccak-256 hashes for the Merkle proof. ### Transaction Validation A node validating a `SchemedTransaction` MUST perform the following checks in order: 1. **Type check** * First byte is `0x05`. 2. **RLP decode** * Decode the payload according to the field list above. 3. **Chain ID** * `chain_id` matches the node's chain. 4. **Authorization structure** * `authorizations` contains exactly one `ROLE_SENDER`. * Unknown `role_id` is invalid. * Unknown `scheme_id` is invalid. 5. **Extension structure** * `extensions` contains no duplicate `extension_id`. * Unknown `extension_id` is invalid. * Each extension payload is statelessly well-formed. 6. **Sender verification** * Compute `sender_signing_hash(tx)`. * Verify or recover the sender public key using the sender authorization scheme. * For `SCHEME_EPHEMERAL_K1`: verify that the Merkle root in the witness matches the sender address, recover the public key, and verify the Merkle proof at leaf index `tx.nonce`. * Derive the sender address. 7. **Nonce and balance** * Sender account nonce matches `tx.nonce`. * Sender has sufficient balance for transaction execution and all extension-specific fee lanes. 8. **Pre-execution extension processing** * Apply stateless and fee-lane checks for `EXT_BLOB`. * Apply set-code authorizations for `EXT_SET_CODE`. 9. **Intrinsic gas** * Charge base intrinsic gas, calldata cost, sender scheme surcharge, and extension-specific intrinsic charges. 10. **Execute** * Execute the normal call/create payload using `to`, `value`, and `data`. ### Receipt The [EIP-2718](./eip-2718.md) `ReceiptPayload` for this transaction is: ```text rlp([status, cumulative_transaction_gas_used, logs_bloom, logs]) ``` Identical to [EIP-1559](./eip-1559.md), [EIP-4844](./eip-4844.md), and [EIP-7702](./eip-7702.md). ## Rationale ### Why a single outer transaction type? A single new transaction type is still needed because the transaction body itself changes. The point of this EIP is not to avoid adding one new outer type - it is to avoid adding a new outer type for every future combination of features. ### Why make scheme agility an authorization capability? Signature scheme choice determines how the sender proves control of the transaction. That is an authorization concern, not a payload family. Defining scheme agility as an authorization capability means future signature schemes only register: * a `scheme_id` * a witness format * verification or recovery logic * address derivation * gas pricing They do not need to redefine the outer transaction envelope. ### Why flat extensions instead of nested transactions? Composing whole existing payloads inside a new transaction preserves the inheritance tree this EIP is trying to remove. The cleaner model is: * one fresh canonical base transaction * one execution payload * orthogonal typed attachments This yields: * plain secp256k1 transaction = base + sender auth(k1) * ephemeral quantum-safe transaction = base + sender auth(ephemeral k1) * blob transaction = base + sender auth(...) + blob extension * set-code transaction = base + sender auth(...) + set-code extension * ephemeral k1 + blobs + set-code = base + sender auth(ephemeral k1) + blob extension + set-code extension No new outer type is needed for any of those combinations. ### Why no access list in the base type? Transaction-level access lists are being deprecated. Any protocol benefit they provided has been superseded by block-level access lists ([EIP-7928](./eip-7928.md)), and [EIP-7981](./eip-7981.md) increases their cost to reflect their diminished utility. This EIP omits `access_list` from the base transaction entirely rather than carrying forward a deprecated field. Similarly, a frame extension as proposed in [EIP-8141](./eip-8141.md) could be added as a new `extension_id` to support nested execution frames within the same transaction envelope. ### Why preserve the legacy secp256k1 address? For `SCHEME_SECP256K1`, this EIP intentionally preserves Ethereum's existing `keccak256(pubkey)[12:]` address derivation. That avoids creating a second address for the same secp256k1 key and lets current EOAs use the new transaction format without on-chain migration. ### Why hash `scheme_id` into non-secp256k1 addresses? For non-secp256k1 schemes, `keccak256(scheme_id || pubkey)[12:]` or `keccak256(scheme_id || merkle_root)[12:]` provides address domain separation from secp256k1 and from each other. Future schemes (P256/passkeys, Falcon-512, etc.) added via new `scheme_id` values will inherit this separation automatically. ### Why include an ephemeral secp256k1 scheme? The ephemeral secp256k1 scheme provides an immediately deployable quantum-safe alternative that reuses existing ECDSA infrastructure, with no new cryptographic primitives. The security model shifts from "the signature scheme is quantum-resistant" to "each key is used exactly once, so recovering it is useless." This relies only on Keccak-256 preimage resistance (128-bit security against Grover's algorithm), not on any new cryptographic assumption. The ephemeral scheme is stateless at the protocol level: the Merkle root is embedded in the sender address and carried in every witness. No new account fields, no storage writes, no contract deployment. The account nonce, already enforced by the protocol, serves as the Merkle leaf index. This makes it the lightest-weight quantum migration path available. Users can start with `SCHEME_EPHEMERAL_K1` for immediate quantum safety and later migrate to a future post-quantum scheme as those mature — potentially using `EXT_SET_CODE` to delegate their ephemeral account to a contract that bridges the transition. ### Why spell out the set-code extension instead of inheriting [EIP-7702](./eip-7702.md) by reference? Because set-code authorizations now participate in a scheme-agile transaction model, each authorization in the list carries its own `(scheme_id, witness)` pair. This means different authorizations within the same transaction can use different schemes. [EIP-7702](./eip-7702.md) hardcodes `(y_parity, r, s)` which limits set-code to secp256k1 only. The exact signed payload and exact gas accounting must therefore be explicit. This EIP spells out: * the exact authorization message hash * the exact per-tuple processing order * the exact intrinsic and refund accounting * the exact deltas relative to [EIP-7702](./eip-7702.md) The only semantic changes are: * `scheme_id` is added to the signed set-code authorization payload * `(y_parity, r, s)` is replaced by `(scheme_id, witness)` * base transaction access-list intrinsic gas is absent because the base envelope has no `access_list` Everything else intentionally stays aligned with [EIP-7702](./eip-7702.md). ## Backwards Compatibility * A `SchemedTransaction` using `SCHEME_SECP256K1` produces the same sender address and the same execution semantics as a normal [EIP-1559](./eip-1559.md) transaction, but it uses a distinct typed envelope and signing hash. * Existing EOAs can migrate to `SchemedTransaction` without changing address when they continue using secp256k1. * Contracts see the derived sender address through `msg.sender` and `tx.origin` regardless of which authorization scheme was used. * A user who migrates from secp256k1 to ephemeral secp256k1 will have a new address, because the ephemeral address is derived from the Merkle root rather than a single public key. * Blob and set-code semantics remain those of [EIP-4844](./eip-4844.md) and [EIP-7702](./eip-7702.md), but are attached as extensions rather than as separate top-level transaction families. ## Security Considerations ### Address collision across schemes For secp256k1, this EIP deliberately preserves Ethereum's existing address derivation. For all other schemes, `keccak256(scheme_id || pubkey)[12:]` or `keccak256(scheme_id || merkle_root)[12:]` provides domain separation from secp256k1 and from each other. A collision would require a preimage attack on Keccak-256 across distinct inputs, which is computationally infeasible. ### Unknown capability handling Unknown `scheme_id`, `role_id`, or `extension_id` values are invalid. Clients MUST reject them rather than ignore them. Silent acceptance of unknown capabilities would create consensus and wallet-safety hazards. ### Flat composition reduces validation complexity This EIP allows multiple orthogonal capabilities, but only one execution payload. It intentionally forbids recursive transaction composition. That avoids drifting into frame-transaction validation complexity, where mempool validation may require richer execution-aware processing before inclusion. ### Quantum migration timing Any secp256k1 address whose public key has already been revealed on-chain remains vulnerable once ECDSA can be broken. This EIP enables proactive migration to `SCHEME_EPHEMERAL_K1`. Users of `SCHEME_EPHEMERAL_K1` are protected against retrospective key recovery: even after a quantum computer exists, previously used ephemeral keys are useless because the nonce has advanced. However, the mempool exposure window remains (see below). ### Mempool exposure for ephemeral secp256k1 While a `SCHEME_EPHEMERAL_K1` transaction is pending in the mempool, the current signing public key `pk_i` is visible in the witness. A quantum attacker who can run Shor's algorithm within a single block time could recover `sk_i` and submit a competing transaction at the same nonce. This requires breaking ECDSA within seconds, which is far beyond near-term quantum capabilities. Mitigations include private mempools and L2s with shorter inclusion latencies. ### Ephemeral key exhaustion A `SCHEME_EPHEMERAL_K1` account with tree depth `EPHEMERAL_TREE_DEPTH = 20` supports `2^20` (approximately 1,048,576) transactions. This is more than sufficient for any individual EOA. If exhaustion approaches, the user should migrate funds to a new ephemeral account (new seed, new Merkle root, new address) or transition to a post-quantum scheme. ### Large witness DoS Ephemeral secp256k1 witnesses are larger than standard ECDSA witnesses (737 bytes vs 65 bytes). The sender surcharge exists to avoid systematic under-pricing of bandwidth and storage costs. Extensions with large payloads must likewise carry their own appropriate pricing. ### Set-code non-rollback As with [EIP-7702](./eip-7702.md), processed set-code authorizations are not rolled back if the later execution phase reverts or otherwise fails. Wallets and users MUST treat set-code authorization as a state change that can persist even when the call payload does not succeed. ### Downgrade attacks A future attacker who can forge secp256k1 signatures could target addresses that continue to authorize transactions with `SCHEME_SECP256K1`. This is not introduced by this EIP. It is the pre-existing quantum threat. Users concerned about it SHOULD migrate to `SCHEME_EPHEMERAL_K1`. ### Keccak-256 and post-quantum security margin Address derivation, signing hashes, and ephemeral key Merkle trees all rely on Keccak-256. While Keccak is not broken by Shor's algorithm, Grover's algorithm reduces its effective security margin from 256 bits to 128 bits for preimage resistance. For the ephemeral scheme, this 128-bit margin is the primary security parameter — it is what prevents an attacker from recovering a future key from its Merkle leaf. This remains adequate for the foreseeable future, but a later fully post-quantum Ethereum may wish to revisit the hash choice for signing and address derivation. This EIP does not require such a change. ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md).