This EIP introduces SETCODEFROM, a runtime-only EVM instruction that sets the current account's code hash to the code hash of a source account with existing deployed code. The new code is visible to later code execution.
This EIP has two primary use cases.
First, it improves code reuse and deployment economics. Deploying many contracts with identical runtime code is expensive, especially when contract deployment is repriced more closely to state growth, for example under EIP-8037. A factory can deploy a minimal initializer runtime, call it to initialize per-instance storage, then have it adopt shared deployed code without paying code-deposit gas for identical runtime code. Existing contracts can also adopt a new shared implementation through their own upgrade logic.
Second, it provides an account migration path for disabling ECDSA-based EOA transaction authority. Migration code can store account-specific wallet state, including post-quantum (PQ) wallet state, then adopt regular wallet code. After that update, account control is through the installed wallet code rather than ECDSA transaction origination. This is because the account now has regular deployed code, not an EIP-7702 delegation indicator, so ECDSA-authenticated transactions remain invalid under EIP-3607. EIP-7702 authorization processing can no longer redelegate the account because the authority code check only accepts empty code or an existing delegation indicator. The account can still upgrade through upgrade logic in the installed code, for example by calling SETCODEFROM again or by using other methods. Protocol-level ECDSA transaction origination remains permanently disabled.
SETCODEFROM provides the code-adoption step for both cases after any per-instance state has been initialized.
The opcode is defined as follows:
| Parameter | Value |
|---|---|
SETCODEFROM_OPCODE |
TBD |
SETCODEFROMSETCODEFROM(source) takes one stack item. The low 160 bits of the stack item are interpreted as source.
Before execution:
[..., source]
After execution:
[..., success]
success is 1 if source is a valid source account, and 0 otherwise.
The instruction is address-based: its input is source address, not a raw code hash. It reads source.codeHash from a live account in consensus state.
For this instruction, the current account is the current execution-environment address, meaning the account returned by ADDRESS and whose storage is affected by SSTORE. If the executing code was loaded from another account, including through EIP-7702 delegated execution, SETCODEFROM updates the execution-environment account, not the code source account.
A source account is valid for SETCODEFROM if all of the following are true:
source.codeHash != EMPTYCODEHASH, where EMPTYCODEHASH = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470.source.code is valid regular deployed code under the active fork, e.g. it does not start with 0xEF, which is reserved by EIP-3541 and used by EIP-7702 delegation indicators.If initcode executes SETCODEFROM, whether in a contract-creation transaction or during CREATE/CREATE2, execution causes an exceptional halt.
If executed in a static context, SETCODEFROM causes an exceptional halt.
If source is not a valid source account, SETCODEFROM pushes 0 and makes no state change.
If source is a valid source account, SETCODEFROM sets the current account's codeHash to source.codeHash and pushes 1. Subsequent changes to or deletion of source must not affect the current account's codeHash and must not affect the availability of the bytecode referenced by that code hash.
State changes made by SETCODEFROM follow normal EVM revert semantics. If the frame or transaction reverts, the code update reverts.
When SETCODEFROM succeeds while executing deployed code, it updates the code hash of the current execution-context account.
The current execution frame continues running the code that was already loaded for that frame. The updated code hash is used by later code executing operations, including later calls to the same account in the same transaction, subject to normal revert semantics.
After SETCODEFROM installs regular deployed code on an account, the account is controlled through that code. The account has nonempty regular code, so an ECDSA-authenticated transaction whose recovered sender is that account is invalid under EIP-3607. It also disables EIP-7702 redelegation, because EIP-7702 authorization processing accepts only empty code or an existing valid delegation indicator for the authority account.
The following gas parameters are used:
SOURCE_ACCOUNT_ACCESS_COST is COLD_ACCOUNT_ACCESS if source is cold, otherwise WARM_ACCESSSETCODEFROM_SOURCE_GAS is SOURCE_ACCOUNT_ACCESS_COST + WARM_ACCESSSETCODEFROM_CURRENT_ACCESS_GAS is WARM_ACCESSSETCODEFROM_WRITE_GAS is ACCOUNT_WRITESETCODEFROM_STATE_GAS is 0SETCODEFROM charges SETCODEFROM_SOURCE_GAS in execution gas for each execution attempt. This covers the source lookup and validation:
source address = 0, charged by ordinary calldata or deployed-code costsSOURCE_ACCOUNT_ACCESS_COSTWARM_ACCESS, a fixed charge covering the additional code-store access required when deployed bytecode must be inspectedIf source is valid, the instruction charges SETCODEFROM_CURRENT_ACCESS_GAS before comparing source.codeHash with the current account's codeHash:
WARM_ACCESSIf the two code hashes differ, the instruction charges SETCODEFROM_WRITE_GAS before updating the current account's code hash. Its write component follows EIP-8038:
ACCOUNT_WRITEAn invalid source charges neither SETCODEFROM_CURRENT_ACCESS_GAS nor SETCODEFROM_WRITE_GAS. A valid source with the same code hash charges SETCODEFROM_CURRENT_ACCESS_GAS but not SETCODEFROM_WRITE_GAS. Under the current EIP-8038 parameters, ACCOUNT_WRITE is 9000, COLD_ACCOUNT_ACCESS is 3000, and WARM_ACCESS is 100. The resulting execution-gas costs are:
| Result | Cold source | Warm source |
|---|---|---|
| Invalid source | 3100 |
200 |
| Valid source with unchanged code hash | 3200 |
300 |
| Current account's code hash is updated | 12200 |
9300 |
Under EIP-8037, SETCODEFROM_STATE_GAS is 0. SETCODEFROM performs no code-deposit operation and creates no new account leaf. It only updates an existing account leaf to reference the source's existing or pending codeHash => code mapping. The gas cost is not affected by source code size.
Using an address rather than a raw code hash avoids depending on client-local code database contents, which may differ across nodes. A newly synced node may have a smaller local code database than a long-running node because it may not keep historical or unreferenced bytecode entries. For this reason, this EIP makes SETCODEFROM copy the code hash from a live source account, so the adopted code hash is confirmed by current consensus state.
Under EIP-6780, a factory can create a source contract, create a second contract with an initializer runtime, call the initializer to adopt the source code, and then call the source contract to execute SELFDESTRUCT. The second contract must retain the adopted code even though the source account is deleted. Clients must ensure that the bytecode referenced by the adopting account remains available after the source account is deleted. This does not require copying the bytecode on every adoption. The existing codeHash => code mapping can be retained.
One possible implementation for a code store keyed by code hash is:
code_hash, code = state.get_code_entry(source)
if not code_store.contains_persisted(code_hash):
journal.retain_code(code_hash, code)
journal.set_code_hash(current_account, code_hash)
contains_persisted reports whether the codeHash => code mapping is already guaranteed to be present after the current transaction commits. If it is not, retain_code preserves the source's pending codeHash => code mapping and ensures that it is persisted when the transaction commits, so the adopted code remains available even if the source is deleted.
This does not require a second bytecode copy or duplicate persistent code entry. Code that is already stored needs only the current account's code hash update. Code created in the current transaction already has a pending write from CREATE or CREATE2, and retain_code prevents that write from being discarded if the source is later deleted. The pending map is keyed by code hash, so multiple adoptions reuse the same write. Code-deposit gas was already charged when the bytecode was originally deployed. Under EIP-8037 and EIP-3529, SELFDESTRUCT returns no gas for deleting a source created in the same transaction. Therefore, no additional code-deposit charge is required.
The instruction is self-only during deployed-code execution to keep authority local to the account whose code is executing. It does not allow the executing code to update any other account's code hash.
Keeping SETCODEFROM runtime-only preserves a simple creation invariant: contract creation installs exactly the bytes returned by initcode. This avoids a second code-installation path during construction and the resulting interactions with RETURN output, code-deposit gas and validation, and creation failure handling.
Per-instance initialization can still be atomic in the factory path. A factory deploys an account with a minimal initializer runtime, calls that account to write per-instance storage and execute SETCODEFROM, and can require the call to succeed. The only non-atomic path is direct contract creation with a nil to field, which requires a second transaction to call the initializer, but this path is expected to be uncommon for the intended use cases.
For example, the instruction can be used in the following patterns.
An account migration function can store account-specific wallet state, then adopt a shared wallet implementation:
SSTORE(pq_pubkey_slot, userPubkey)
SSTORE(recovery_slot, recoveryConfig)
if SETCODEFROM(PQ_WALLET_TEMPLATE) == 0: REVERT()
STOP
An ERC-20 clone factory can deploy a tiny initializer with CREATE2, then call it to initialize token metadata and ownership before adopting a shared token implementation:
SSTORE(name_slot, "MyToken")
SSTORE(symbol_slot, "MYT")
SSTORE(owner_slot, msg.sender)
if SETCODEFROM(ERC20_TEMPLATE) == 0: REVERT()
STOP
This EIP requires a hard fork to implement because it introduces a new instruction which did not exist previously. As a result, already deployed contracts using this instruction could change their behavior after this EIP.
The 0xEF source restriction also excludes three contracts whose code starts with 0xEF. These contracts were deployed on Ethereum mainnet after EIP-3541's state survey but before its activation. Because 0xEF is an undefined instruction that causes an exceptional halt, none of them provides executable source code. Excluding these contracts therefore has no negative effect on practical code reuse.
SETCODEFROM can change the code used by later executions of an account. Contracts that expose this instruction must restrict access to trusted control paths, because a successful call can permanently change account behavior if the transaction does not revert.
SETCODEFROM changes account-code identity semantics. Code executing with an account's authority can replace the code identity visible to later execution and code-inspection with regular code from another account. This also departs from EIP-7702's conservative codehash-introspection design by introducing a related codehash-presentation risk through explicit code adoption, rather than through EXTCODEHASH following delegation.
Unlike EIP-6913, which forbids code replacement when the executing code differs from the account code, this EIP allows delegated execution to update the caller's account code. This preserves existing proxy upgrade patterns, which already rely on delegated code running with the caller's authority. Wallets must treat any such module as upgrade-authorized code, restrict delegatecall targets accordingly, and require explicit authorization before execution.
The source restriction requires valid regular deployed code under the active fork, e.g. code that does not use the 0xEF prefix reserved by EIP-3541 and used by EIP-7702 delegation indicators. It also excludes empty code and precompiles. This prevents SETCODEFROM from bypassing deployed-code validity rules or treating precompile behavior as deployed code.
Protocol-level ECDSA transaction origination is disabled once the account has regular deployed code, meaning code that is not an EIP-7702 delegation indicator. Contracts that verify ECDSA signatures directly through ecRecover may still recover that address. This affects signature-based authorization such as permit. A companion ecRecover change, such as EIP-8151, can reject recovered addresses whose account code is regular deployed code rather than an EIP-7702 delegation indicator, and return 32 zero bytes.
Because the current frame keeps executing already-loaded code, implementations must clearly separate the executing code for the current frame from the account code visible to later calls. Re-entrant calls after a successful SETCODEFROM observe the updated code.
Copyright and related rights waived via CC0.