Abstract
Allow an externally owned account (EOA) to permanently disable EIP-7702 delegation by installing an account-code marker that consensus rules recognize but the EVM observes as empty code. A narrowly defined, previously invalid form of a set-code transaction performs the opt-out. The account keeps its address and continues to behave as an ordinary EOA at the EVM level, but no subsequent delegation authorization can replace or clear the marker.
Motivation
EIP-7702 gives EOAs a persistent capability to delegate execution. Some accounts, including institutional wallets, exchange hot wallets, and treasuries, do not need this capability. Their operational controls may include withdrawal approvals, frequency and amount limits, monitoring, and emergency suspension outside Ethereum consensus. Delegated execution can invalidate assumptions behind those controls and compress the time available for intervention.
An account owner should be able to eliminate this capability explicitly. This proposal only removes delegation: a compromised private key can still sign ordinary transactions, transfer funds, and authorize actions in contracts. It does not enforce withdrawal delays or replace key management and operational controls.
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.
Except for the changes below, EIP-7702 and ordinary transaction and EVM rules are unchanged. Here, sender is the address recovered from the outer transaction signature; authority is the address recovered from an authorization signature. || denotes byte concatenation.
Parameters and Account State
| Parameter | Proposed value |
|---|---|
OPT_OUT_CODE | 0xef0200 (exactly 3 bytes) |
OPT_OUT_GAS | 33500 |
OPT_OUT_CODE is a candidate encoding for this draft, not an assigned code format. Its allocation requires coordination before this proposal can become final; the namespace concern is described in Rationale. All byte comparisons below use this exact candidate value.
An account is delegation-disabled if and only if its raw stored code equals OPT_OUT_CODE. Clients MUST check the complete code, including its length; a prefix match is insufficient. This marker is not the 23-byte EIP-7702 delegation indicator 0xef0100 || address and MUST NOT be parsed as one.
The account's state-trie codeHash MUST be keccak256(OPT_OUT_CODE) (0x804e3605b87cf0b8b9e86c36d895f477b73bafa75f854f0a2b17712a5c88c2e9 for the candidate bytes), not the literal marker bytes and not the empty-code hash. No storage slot or additional account field is introduced. EIP-3541 continues to prohibit installing code beginning with 0xef through contract creation.
Opt-Out Transaction
Extend the validity rules for EIP-7702 set-code transactions (TransactionType = 0x04). An empty authorization_list, previously always invalid, MUST be accepted only when all of these conditions hold:
destination == sender;value == 0;datais the empty byte string;access_listis the empty list.
This form is an opt-out transaction. Every other set-code transaction with an empty authorization list MUST remain invalid. A non-empty authorization list retains its existing meaning, including when its other fields match the conditions above.
The transaction uses the existing set-code RLP envelope and signature scheme. Explicitly, its signature is over:
keccak256(0x04 || rlp([chain_id, nonce, max_priority_fee_per_gas,
max_fee_per_gas, gas_limit, sender, 0, empty_bytes, [], []]))The signature fields are appended to these unsigned fields as in EIP-7702. There is no new transaction type, authorization signature domain, sentinel delegation address, or relayed opt-out authorization.
The outer transaction's chain ID MUST equal the current chain ID under the existing typed-transaction rules. The chain-agnostic chain_id = 0 exception for EIP-7702 authorization tuples does not apply to this operation. A chain whose own ID is zero still uses its ordinary outer transaction rules.
Existing signature, nonce, fee, balance, block-gas and transaction-gas validity checks apply, with the sender-code exception below. In particular, EIP-2681 requires nonce < 2**64 - 1.
An opt-out transaction's intrinsic gas and gas used MUST both equal OPT_OUT_GAS. A gas limit below this amount MUST make the transaction invalid. Fee purchase, unused-gas return, base-fee burning, and priority-fee payment follow EIP-1559. No gas refund is generated by replacing an existing delegation or repeating the operation.
After validating the transaction, clients MUST perform the ordinary sender nonce increment and fee accounting and set the sender's code to OPT_OUT_CODE. The transaction MUST NOT execute EVM code, invoke the old delegate, process authorizations, transfer value, clear storage, or mark the sender as a newly created contract. Its receipt uses the existing set-code receipt format, with status 1 and no logs. Unused gas above OPT_OUT_GAS MUST be returned through ordinary fee settlement.
An existing EIP-7702 delegation is replaced directly; no preliminary clearing transaction is required. Repeating the operation on an already marked account is valid and leaves its code unchanged while consuming the ordinary nonce and OPT_OUT_GAS. Apart from code, nonce, and normal fee-accounting effects, account state is unchanged.
Transaction Origination
Extend the EIP-3607 exception introduced by EIP-7702: a sender whose raw code is exactly OPT_OUT_CODE MUST be permitted to originate every otherwise valid transaction type. Empty code and valid EIP-7702 delegation indicators remain permitted as before. This exception MUST NOT permit senders with any other code.
The marker MUST NOT be executed merely because its account originates a transaction. Ordinary ETH transfers, contract calls, and contract-creation transactions initiated by that account retain their usual semantics.
Authorization Processing and Ordering
At step 5 of EIP-7702 authorization processing, an authority with raw code equal to OPT_OUT_CODE MUST fail the code-eligibility check. The tuple MUST be skipped, without code or nonce changes and without the successful-authorization refund. The authority remains warm because step 4 has already added it to accessed_addresses. Intrinsic authorization charges remain unchanged; this failure does not by itself invalidate the containing transaction.
This rule applies to every delegation target, including the zero address used to clear delegation, and to both chain-specific and chain-agnostic authorizations. The marker MUST NOT be included in the authorization processor's definition of "already delegated". An opted-out sender MAY still submit non-empty set-code transactions carrying authorizations from other eligible accounts.
Transactions take effect in block order. A delegation processed before opt-out is replaced by the marker; any authorization processed after opt-out is skipped. An earlier transaction that changes the account nonce may invalidate a pending opt-out transaction under ordinary nonce rules. A valid opt-out is a single state transition with no execution phase that can revert or overwrite it. It MUST remain effective if a later transaction or call reverts. Invalid transactions make no state changes.
EVM Behavior
When loading account runtime code for a transaction destination or for CALL (0xf1), CALLCODE (0xf2), DELEGATECALL (0xf4), or STATICCALL (0xfa), clients MUST treat exact OPT_OUT_CODE as empty executable code. This also applies if the code is obtained as the target of the single EIP-7702 delegation-resolution hop. It MUST NOT be interpreted as EVM instructions. Initcode supplied to contract creation is not subject to this substitution.
Consequently, a call to a marked account succeeds with empty return data if the ordinary call preconditions and gas requirements are met. ETH value transfer, static-context restrictions, depth and balance checks, account-access charges, and enclosing-call rollback follow normal empty-code call behavior. Resolving the marker itself introduces no delegation-target access or additional execution gas charge; an actual delegation hop to a marked target retains its usual access charge. Existing precompile dispatch is unchanged.
EVM code inspection MUST also treat exact OPT_OUT_CODE as empty code:
| Operation on a marked account | Result |
|---|---|
EXTCODESIZE (0x3b) | 0 |
EXTCODECOPY (0x3c) | Zero bytes, as for an account with empty code, with ordinary offset, length, and zero-padding rules |
EXTCODEHASH (0x3f) | keccak256("") (0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470) |
A marked account always has a nonzero nonce and therefore always exists, so EXTCODEHASH returns the empty-code hash, not zero. These operations retain their existing gas rules, including account-access charges. Clients MAY implement the substitution by comparing the account's codeHash with keccak256(OPT_OUT_CODE), without loading the code.
This substitution applies only to EVM-visible code. Consensus checks that this specification defines on raw code continue to use raw stored code: authorization eligibility, the transaction-origination exception, EIP-684 collision checks, and EIP-161 account emptiness. The state trie, state proofs, and JSON-RPC methods that return stored state, such as eth_getCode and eth_getProof, MUST expose the raw marker and its codeHash. For marked accounts, the state-trie codeHash therefore differs from the value returned by EXTCODEHASH.
Permanence and State Costs
No transaction or EVM operation specified here can remove or replace a marker. Authorization processing rejects it; an ordinary originating transaction changes no sender code; and calls execute no instructions in the marked account. Contract creation at its address continues to fail the nonce or raw-code collision check of EIP-684. Account clearing under EIP-161 MUST continue to use raw code, so draining the account's balance cannot erase the marker.
Opt-out stores three persistent code bytes and changes the account's state-trie code hash. The code blob may be shared by clients, but account-trie updates, code-database metadata, and persistent state still have costs. The fixed gas charge is 21000 + 12500: the ordinary base transaction cost plus the existing EIP-7702 per-authorization base cost as a conservative allowance for installing the marker. There is no separate code-deposit charge or storage-slot charge. The operation introduces no additional account beyond the ordinary sender transition and does not delete any pre-existing delegated storage.
Rationale
A code marker uses existing account state and the existing authorization code-eligibility check. Two explicit exceptions are essential: EIP-3607 otherwise prevents transaction origination, and executing 0xef otherwise causes an exceptional halt. The design invariant is that an opted-out account continues to behave as an ordinary EOA at the EVM level; the only permanently disabled capability is EIP-7702 delegation. Treating the marker as empty code for both execution and inspection preserves incoming ETH transfers and keeps applications that classify accounts by EXTCODESIZE or EXTCODEHASH working. In particular, ERC-721 safe transfers and ERC-1155 transfers to accounts with nonzero code size call the recipient's receiver hook; an empty-code call returns no data, which cannot be decoded as the expected selector, so the transfer reverts. Exposing the raw marker to the EVM would therefore permanently prevent opted-out accounts from receiving such tokens, which ordinary EOAs can do, and unlike a delegated account it could never add the hooks later.
The cost is a divergence between the state-trie codeHash and EVM-visible code for marked accounts, and on-chain contracts cannot distinguish an opted-out account from an ordinary EOA. Opt-out status remains observable through eth_getCode, eth_getProof, and state proofs. EIP-7702 delegation indicators remain visible to the EVM as raw code because delegated accounts execute code; a marked account executes none. Alternatives that avoid the divergence, such as recording opt-out in a system-contract registry or in a new account field, require additional persistent structures or account-model changes, and were not chosen for that reason.
The constrained empty-list set-code form reuses an existing envelope, fee mechanism, and signature domain. No previously valid transaction or authorization changes meaning. In contrast, reinterpreting an existing delegation authorization to a special target could turn an old signature into an irreversible opt-out. A dedicated transaction type would provide separate encoding but require another type assignment and additional infrastructure. This proposal keeps the new operation restricted to the signing sender and performs no accompanying calls.
The repository's EIP-8141 Rationale discusses 0xef02 || version || key_type || pubkey_len || pubkey for possible future public-key aliases. That is not an assignment of this exact three-byte marker, but it is a namespace overlap requiring coordination. EIP-7851 and EIP-8164 also propose adjacent 0xef0101 formats for disabling ECDSA authority, a different objective. This draft does not claim that 0xef0200 is allocated or that this namespace is uncontested.
Backwards Compatibility
This is a consensus change requiring a network upgrade. Existing EOAs and delegations retain their behavior unless their owner opts out. Smart contracts cannot invoke opt-out on another account or install the marker through contract creation. Chains with pre-existing or genesis code equal to the chosen marker need a collision review before adoption, because exact matches acquire the marker semantics.
Opted-out accounts retain ordinary protocol transaction capabilities. Because the EVM observes them as empty-code accounts, contracts that classify accounts by EXTCODESIZE or EXTCODEHASH, including token receiver-hook checks, treat them as ordinary EOAs. Off-chain infrastructure that reads raw code through eth_getCode or state proofs sees the marker and must not treat it as contract code or a delegation. Clients, light clients, and stateless verifiers must apply the EXTCODEHASH substitution to marked accounts even though the proven codeHash differs. Wallets, hardware signers, RPC validation, transaction pools, explorers, and gas estimators need to recognize the new transaction form and sender exception, and present opt-out as irreversible. Existing signing interfaces that accidentally construct empty-list type-4 self-transactions need particular care.
This proposal does not change the current ECDSA recovery precompile. Draft EIP-8151, which restricts recovery using raw account code, would need to recognize the marker to preserve contract-based signature authorization if adopted alongside this proposal. Draft gas repricings and future account-code formats likewise require integration review; they are not implicitly activated here.
Test Cases
These are state-transition input/output cases, not results from an implemented client. Let A be an EOA with nonce n < 2**64 - 1, sufficient balance, and initially empty code; D a normal contract; M = OPT_OUT_CODE; and H = keccak256(M). Unless specified otherwise, transactions have valid signatures, matching chain IDs and nonces, sufficient gas, and ordinary fee settings. opt(A,n) denotes the exact opt-out form above. Each row starts from its stated pre-state.
| Pre-state and input | Expected result |
|---|---|
Empty-code A; opt(A,n) with gas limit 33500 | Status 1, gas used 33500, no logs, code M, code hash H, nonce n+1 |
Code 0xef0100 || D and storage slot 0 = 7; opt(A,n) | Code M, nonce n+1, slot remains 7; no invocation of D |
Code M; opt(A,n) with gas limit 40000 | Code M, nonce n+1, gas used 33500, unused 6500 returned; no refund credit |
Opt-out form with gas limit 33499, wrong nonce, wrong chain ID, or invalid signature | Each variant is invalid; no state changes |
| Empty authorization list with destination different from sender, nonzero value, nonempty data, nonempty access list, or absent destination | Each variant is invalid; no state changes |
Self-addressed, zero-value, empty-data set-code transaction with a nonempty valid delegation authorization from A at nonce n+1 | Ordinary EIP-7702 processing; code becomes its delegation indicator, not M |
Code M; valid authorization from A to D, signed for either current chain or chain ID 0 | Tuple skipped; code and nonce unchanged, no successful-authorization refund; A warm; ordinary tuple charge paid |
Code M; valid authorization from A to zero address | Tuple skipped; code M persists |
Code M; multiple sequential-nonce authorizations from A in one list | Every tuple skipped; code and nonce unchanged |
Code M on A; transaction from A carrying a valid authorization from another empty-code account | Other account's authorization processed normally; A stays marked |
Code M; ordinary ETH transfer, contract call, or creation transaction from A | Ordinary outcome and fee/nonce effects; code M persists even if execution reverts |
Code M; all balance transferred out of A, followed by account cleanup | A remains with code M and hash H |
Code M; direct ETH transfer to A | Empty-code execution, successful transfer if otherwise valid, marker retained |
Code M; each call-family operation targeting A with sufficient gas and valid preconditions | Success 1, empty return data, no instructions executed |
Account B delegates to marked A; call B | One ordinary delegation hop; empty-code execution, no invalid-opcode halt |
Code M; EXTCODESIZE, EXTCODEHASH, and EXTCODECOPY of 5 bytes from offset 0 targeting A | Size 0, hash keccak256(""), copied bytes 0x0000000000 |
Code M; eth_getCode and eth_getProof for A | Raw code M; proven codeHash H |
Code M; ERC-721 safeTransferFrom or ERC-1155 transfer to A from a contract that calls receiver hooks only for nonzero code size | Hook not called; transfer succeeds as for an ordinary EOA |
Code M; attempt contract creation at A | Creation collision failure; marker retained |
Code 0xef020000 or another nonempty, non-delegation code value; transaction from that account | Sender rejected; exact marker exception does not apply |
Authorization for A executes in an earlier transaction; then a nonce-correct opt(A, current_nonce) | Earlier delegation replaced by M |
opt(A,n); later transaction includes delegation and clearing authorizations from A, then reverts | Tuples skipped; earlier marker and its nonce increment persist |
Pending opt(A,n); earlier valid authorization consumes nonce n | Pending opt-out invalid due to nonce mismatch; no marker installed by it |
Security Considerations
Opt-out removes only protocol delegation capability. A private-key holder can still send ordinary transactions, drain funds, grant token approvals, or sign contract authorizations. There is no withdrawal delay, protection against every malicious transaction, or substitute for institutional key management, monitoring, and approval controls.
A stolen key can also permanently opt out, disabling delegation-dependent recovery or wallet functionality. Wallets and signers should require an explicit irreversible-action confirmation and distinguish this form from ordinary self-transfers and delegation clearing. Contract-held assets that require the old delegate's code to access may become inaccessible; retained storage does not preserve that functionality. Existing approvals, signed application messages, and other external permissions are not revoked.
Before inclusion, an attacker may invalidate or preempt opt-out using the compromised key or an earlier authorization. It provides no retroactive protection, and a reorganization removing the opt-out also removes its effect. Permanence applies to the resulting canonical state under these consensus rules, not to an off-chain signature or an unconfirmed transaction. Users need to verify the raw marker in finalized state before relying on it.
The guarantee is per chain. Opting out on one chain installs the marker only in that chain's state. An EIP-7702 authorization signed with chain_id = 0 remains valid on every other EIP-7702 chain where the account has not opted out and the authorization nonce matches; in particular, a nonce-0 authorization works on every such chain where the account has never sent a transaction. An owner who wants the property has to opt out separately on each chain where the key could be used, including chains the account has never used, which requires funding gas on each of them first. Chains that adopt EIP-7702 later are not covered by earlier opt-outs elsewhere.
Copyright
Copyright and related rights waived via CC0.
