EIP-8298 SETCODEFROM code reuse instruction

Hegota Considered for Inclusion · EVM & execution · EIP status Draft · created 2026-06-11

Adds SETCODEFROM, an EVM instruction that copies the code hash of an already deployed contract to the current account. It removes the cost of redeploying the same code and also opens a path for regular accounts to operate through code alone, without an ECDSA key.

Why it is needed

Today on Ethereum, deploying multiple contracts with the same code means paying to store the identical code again on every deployment. For cases that stamp out the same code repeatedly, such as token issuers, this cost simply accumulates. Proposals like EIP-8037, which reprices contract deployment in line with state growth, would make the burden even larger. Control over regular accounts (EOAs) is also a problem. Today an EOA can only initiate transactions with an ECDSA signature, and even when code is delegated through EIP-7702, only a delegation indicator is attached, so transactions signed with the original key remain valid. To protect an account by other means, such as a post-quantum (PQ) wallet, there must be a way to cut off ECDSA transaction authority, and there is no such way today. SETCODEFROM solves both problems with a single instruction. It first writes the per-account storage values, then adopts an already deployed shared code as its own code.

What changes

Today

After EIP-8298

Who is affected

In depth

Instruction definition: takes one address and copies its code hash

SETCODEFROM is defined as opcode 0xA7. It pops one item from the stack, interprets the low 160 bits as the source address, and pushes success after execution. It is 1 if source is valid and 0 otherwise. The input is an address, not a raw code hash, and it reads source.codeHash of a live account in consensus state. The account that changes is the current execution context account. This is the address that ADDRESS returns and the very account whose storage SSTORE touches. Even if the running code was loaded from another account, as with an EIP-7702 delegation, the code hash that changes is that of the execution context account, not the code source account. On success, later changes to source must not affect the current account's codeHash or the availability of the bytecode that hash points to. State changes follow the normal EVM revert rules. If the frame or transaction is reverted, the code change is reverted with it.

Valid source conditions and exceptional halts

For source to be valid, it must satisfy all four conditions. It must be an account that exists in state, source.codeHash must not be EMPTYCODEHASH (0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470), and source.code must be regular deployable code valid under the active fork. That is, it must not start with 0xEF, which EIP-3541 reserves and which EIP-7702 delegation indicators use. Finally, it must not be an account created in the current transaction. What counts as created is exactly the same as the case where EIP-6780 allows deletion via SELFDESTRUCT. This restriction applies only to source, and the current account may be in the middle of being created inside its own initcode. The instruction halts exceptionally if it runs in a static context or if the current account is a system contract. A system contract is an account that the protocol calls from SYSTEM_ADDRESS (0xfffffffffffffffffffffffffffffffffffffffe) during block processing, and the EIP-6110 deposit contract, whose logs are only read, does not count. Both halts occur before SETCODEFROM_SOURCE_GAS is charged and do not access source. If the source is invalid, it pushes 0 and does not change state. The input is taken as an address because the local code DB contents can differ between nodes. The existence condition is separate to prevent implementations that represent the codeHash of a nonexistent account as 0 from installing a hash with no code. A source created in the current transaction is rejected. Its code could be deleted or changed before the end of the transaction, so the bytecode might remain in neither the pre-block state nor the BAL. As a trade-off, a template cannot be adopted within the transaction that deployed it.

Separation of executing code and visible code, adoption during creation

If SETCODEFROM succeeds while deployed code is executing, the code hash of the current execution context account changes, but the current frame keeps executing the code it already loaded. That frame's CODESIZE and CODECOPY refer to the old code, while EXTCODESIZE, EXTCODEHASH, and EXTCODECOPY on the current account see the new code hash. If the same account is called again within the same transaction, the new code runs. It is also allowed during initcode execution. In creation transactions, CREATE, and CREATE2 alike, the account being created becomes the current account, the update takes effect immediately, and the creation frame keeps executing the existing initcode. When the initcode ends normally, there are two branches. If the account's codeHash is EMPTYCODEHASH, the return data is validated, code deposit gas is charged, and the code is installed. Otherwise, the return data is treated as empty, and validation, hashing, installation, and code deposit gas charging are all skipped, leaving the adopted codeHash as it is. In this case the deployed code is the code from the last successful SETCODEFROM that was not reverted, and execution traces and eth_call results also report that code. A successful CREATE or CREATE2 leaves the caller's return data buffer empty, as in EIP-211. The account creation state gas for adding a new account leaf is still incurred, but the code deposit state gas and execution gas for the adopted code are not. Adoption during creation is allowed to keep a single set of installation rules. Creation installs only one of two things, either the bytes returned by the initcode or the adopted code hash, and the codeHash at the moment the initcode ends decides which.

Gas cost

There are five gas parameters. SOURCE_ACCOUNT_ACCESS_COST is COLD_ACCOUNT_ACCESS if source is cold and WARM_ACCESS if it is warm. SETCODEFROM_SOURCE_GAS is SOURCE_ACCOUNT_ACCESS_COST + WARM_ACCESS, SETCODEFROM_CURRENT_ACCESS_GAS is WARM_ACCESS, SETCODEFROM_WRITE_GAS is ACCOUNT_WRITE, and SETCODEFROM_STATE_GAS is 0. Each execution attempt first charges SETCODEFROM_SOURCE_GAS. It is the sum of loading the source account leaf (SOURCE_ACCOUNT_ACCESS_COST) and verifying the source code (WARM_ACCESS, a fixed cost covering the code storage access needed to inspect the bytecode). Once this charge is made, source is added to EIP-2929's accessed_addresses regardless of validity. Verification reads only source's own code and does not follow EIP-7702 delegation, so the delegation target is not accessed, charged, or warmed. If source is valid, SETCODEFROM_CURRENT_ACCESS_GAS is charged, the two code hashes are compared, and if they differ SETCODEFROM_WRITE_GAS is charged and the update is made. The write cost follows ACCOUNT_WRITE from EIP-8038. Based on the current EIP-8038 values (ACCOUNT_WRITE 9000, COLD_ACCOUNT_ACCESS 3000, WARM_ACCESS 100), an invalid source costs 3100 when cold and 200 when warm, a valid source with the same hash costs 3200 and 300, and an actual update costs 12200 and 9300. Because there is no code storage work, the cost is independent of the source code size, and it is the same when executed inside initcode. The state gas for adding an account leaf at creation itself may be incurred separately.

Ending ECDSA transaction authority and public mempool rules

When SETCODEFROM installs regular deployed code, the account is controlled only by that code. If an EIP-7702 delegation indicator was present, the adopted code replaces it. Because the code is non-empty, an ECDSA transaction whose recovered sender is that account becomes invalid under EIP-3607, and since EIP-7702 authorization handling accepts only empty code or an existing delegation indicator, re-delegation is also blocked. The mempool rules below are recommendations that do not affect consensus. ECDSA transactions already pending at the time of adoption also become invalid, so nodes should evict them when processing a new block and reject new ones. What retires is the key, not the account, so the account keeps transacting as the sender of EIP-8141 frame transactions that its own code approves, and it also works when other transactions call it. An EOA can adopt code only by executing EIP-7702 delegated code, so the transactions that adoption invalidates do not go beyond what delegated code could already invalidate, and the EIP-7702 recommendation of one pending transaction per delegated EOA applies as is. ERC-7562 user operation validation must block SETCODEFROM the way it does SELFDESTRUCT. For EIP-8141 frame transactions, SETCODEFROM is forbidden during validation prefix execution. If contract code reached through CALL* or EXTCODE* in the validation prefix contains a SETCODEFROM instruction (excluding immediate values such as PUSH data), it is treated as mutable code, like an account with an EIP-7702 delegation indicator. If it instead contains DELEGATECALL or CALLCODE, SETCODEFROM can be reached through delegated code, so its code hash is tracked as a validation dependency and the number of pending transactions relying on it is limited. This measure is meant to keep proxy-based accounts usable.

Block access list (BAL) encoding change

This EIP adds an optional trailing element, new_code_hash, to the CodeChange of EIP-7928. Code installed by creation or by EIP-7702 is recorded as before with two elements, [block_access_index, new_code], and code adopted through SETCODEFROM is recorded with three elements, [block_access_index, b"", new_code_hash]. If an account's code hash changed within a transaction and its end-of-transaction value was set by SETCODEFROM, the three-element form must be used, and a BAL recorded any other way is invalid. The bytecode behind new_code_hash must be present in the pre-block state or in the new_code of a code_changes entry with a lower block access index, and no entry may reference an entry with the same or a higher index. From the moment SETCODEFROM_SOURCE_GAS is charged, the source must be included in the BAL regardless of whether it is valid, and if there are no other changes it is included with an empty change list. If the charge fails, it is not included. In the pre-state-access gas validation of EIP-7928, the pre-state validation cost of SETCODEFROM is SETCODEFROM_SOURCE_GAS. The reason for recording a hash instead of the bytecode is that the bytecode already exists. If the BAL could carry code up to the maximum code size for 9300 gas with a warm source, that would be well under 1 gas per byte, which breaks the assumption behind the EIP-7928 bal_items limit. The hash is a separate element because a 32-byte new_code value cannot be distinguished from 32-byte runtime code. Because the entry format reveals the origin and the size is fixed, it can be metered with a byte-floor approach such as EIP-8279.

Security considerations

SETCODEFROM permanently changes account behavior unless the transaction is reverted, so a contract that exposes this instruction must restrict access to a trusted control path. A valid source can change its own code hash, and it can change between the time an adoption is approved and the time it is executed. An adoption that is pre-approved by a signature or a proposal must specify the expected code hash, not just the source address, and the adopting code must compare EXTCODEHASH(source) to that hash, with no external call, immediately before SETCODEFROM. Unlike EIP-6913, this EIP allows delegated execution to change the caller's account code. This preserves existing proxy upgrade patterns, and wallets should treat such modules as code with upgrade authority and restrict delegatecall targets. Delegating via EIP-7702 to an account that can reach SETCODEFROM means trusting all code that account will adopt in the future, and EOAs are now included here. An EOA that adopts ordinary code cannot be reverted. It cannot initiate ECDSA transactions, it cannot re-delegate with 7702, and there is no instruction to return to empty code. Contracts that verify signatures directly with ecRecover (such as permit) will still recover that address, so a companion change such as EIP-8151 is needed, and with 8151 in place, ecRecover authentication for the account's own address fails permanently. Authentication that relies only on uninitialized state can lock the account, so initialization must be completed within the adoption transaction, and initialization that anyone can perform can be front-run. After adoption, ETH arriving by CALL or a token transfer with a receive hook also executes the adopted code. On chains without EIP-8141, the account acts only when it is called, so code without a relay path such as an ERC-4337 entry point is stuck. If the code is called back by a callback before its initialization finishes, the already adopted code runs on top of incomplete storage, so initialization must be finished before adoption.

Current status and fork discussion

This EIP is in Draft status, created on 2026-06-11, and its Test Cases section is still empty (TODO). It adds a new instruction, so it requires a hard fork, and already deployed contracts that use this opcode may change behavior. A client that implements only EIP-7928 rejects blocks that use new_code_hash, and the reverse is also true. Three mainnet contracts that start with 0xEF are excluded as sources, but 0xEF is an undefined instruction and these are not executable code, so there is no practical loss. In the core developer calls, it was accepted as a Hegota candidate (PFI) at 07.02 ACDE #240. It was discussed at 09.16 AMA #15 and 09.24 ACDE #246, but no decision was made. At 10.08 ACDE #247 it was moved to Considered for Inclusion (CFI) as a pair with EIP-8151 (ecRecover restriction). The reason given was that the combination opens a path for ordinary accounts to migrate to post-quantum without relying on ECDSA. At 10.22 ACDE #248, the scope of bogota-devnet-2 was fixed at four EIPs, EIP-8253, EIP-4758, EIP-8298, and EIP-8151, and it was said to ship the following week with three clients, Nethermind, Geth, and ethrex. It is a testnet for running Hegota candidate EIPs on a real network. Because it is in Draft status, details such as opcode values, gas figures, and the BAL encoding may still change.

Original EIP · ← EIPs