This proposal comes from an idea raised during an ACDE call: combine the goals of EIP-7851 and EIP-8058 into one lower-level code adoption primitive.
EIP-8298 introduces SETCODEFROM, an EVM instruction that lets the current account adopt the code hash of an existing deployed contract. The source is a live account address, rather than a raw code hash, so the adopted code is tied to the current consensus state.
The proposal has two main uses:
- Contract bytecode reuse and deployment economics: this addresses the deployment-cost problem targeted by EIP-8058. Contracts with identical runtime code can initialize per-instance storage, then adopt shared deployed code without paying code-deposit gas again for bytecode that clients already store. This is especially relevant if contract deployment is repriced more closely to state growth, for example, under EIP-8037.
- EOA migration with ECDSA authority disabled: this addresses the account-migration problem targeted by EIP-7851. Migration code can initialize wallet-specific state, including PQ wallet state, then adopt regular wallet code. Once the account has regular deployed code, protocol-level ECDSA transaction origination is disabled under EIP-3607, and EIP-7702 redelegation through the old ECDSA key is no longer available.
Update Log
External Reviews
None as of 2026-06-12.
Outstanding Issues
None as of 2026-06-12.
2 Likes
Delegation is great but I don’t think we need an opcode for delegations specifically. We just need to let existing opcodes support delegations; for example, we could allow constructors to return eip-7702 delegations. I do support mutable code but I would prefer something more powerful like the SETCODE opcode (EIP-6913). Restricting mutable code to delegation is redundant with delegatecall proxies and is overly cautious.
I also think we should allow infinite redirects with delegation; they just need to be priced fairly.
Thanks for the feedback.
SETCODEFROM is intentionally narrower than SETCODE. It is not an opcode for delegation specifically, and it does not introduce arbitrary new bytecode or a general mutable-code facility. It only lets an account adopt code that already exists in the live consensus state.
That narrower scope is the point: it preserves deterministic code availability, avoids new code-deposit storage, supports clone deployment economics, especially if contract deployment becomes much more expensive under EIP-8037, and gives migrated EOAs regular deployed code rather than a 7702 delegation indicator.
If the goal is general mutable code, SETCODE is the broader primitive. If the goal is code reuse plus ECDSA-disabled account migration with minimal new surface area, SETCODEFROM is the smaller primitive.
1 Like
I’m reading the draft, but I think it might overly complicate what this opcode tries to do. If we hit SETCODEFROM in an initcode, I think it should directly abort and it should deploy the code what is stored at that address (i.e. set codeHash to the hash of that code). If we continue running teh code, this raises questions (and will increase the test vectors by a lot), what should be returned if we query EXTCODECOPY or CODECOPY on current account? (and what if we do this outside of the CREATE frame?) What if we return empty code? Should we then interpret it as deploy the SETCODEFROM? (this is ambiguous and should be avoided)
I think it would also make sense to have an EIP (could be this one, or another) which proposes returning EIP-7702 delegators (maybe with a special type, so 0xef0102 to mark the account as non-EOA but rather as a deployed contract), which could make it possible to upgrade the code also (this ensures that existing code which is not EIP-7702 delgated cannot be upgraded). @wjmelements I suggest you draft an EIP for this

1 Like
The former point makes sense. I’ll simplify the spec accordingly, so SETCODEFROM in initcode just terminates the CREATE path and deploys the code stored at the referenced address.
For the second point, it seems the current EIP-7851 did the same thing, or am I missing anything?
I believe we can completely omit SETCODEFROM in the constructor, This reduces the deployment vector for CREATE because we already have RETURN. Instead, we use an OpenZeppelin initializer written in bytecode, and it’s extremely efficient. Here’s an example:
// constructor
push1 0x03
dup1
push1 0x09
push0
codecopy
push0
return
// Only 3 bytes of runtime code are created, The additional costs are almost negligible
push0
calldataload
setcodefrom
For a 3-byte contract, there is a smaller constructor that uses PUSH3 instead of CODECOPY; it is one byte smaller (12 → 11).
PUSH3 MSIZE CALLDATALOAD SETCODEFROM
MSIZE MSTORE
RETURN(29, 3)
If you use my assembler (docs), it will use the smallest constructor by default.
1 Like
Nice considerations. And I think the following runtime code returned by the constructor might be safer:
PUSH20 <source_address>
SETCODEFROM
As mentioned above, this opcode should not compete with RETURN in the CREATE path. Keep it in the CALL path.
Yes. I mean this. This change will simplify some compatible considerations and keep the change minimal. The only tradeoff I can see now is that contract creations by sending nil to field transactions require two transactions now.
I believe that given the design of this opcode, common use cases are factory contracts and upgradeable contracts. I don’t expect direct deployments.
1 Like
This is slightly more expensive than supporting SETCODEFROM directly in CREATE/CREATE2 initcode, since the factory path needs a small initializer runtime and an extra call. I prefer the runtime-only design for now because it keeps contract creation semantics simple. We can revisit initcode support if the gas savings prove worth the added complexity.
I guess that the majority of the cost will come from state bytes temporarily created during the upgrade process. But since we’ve allowed code changes, considering a repricing of the cost would be helpful. Perhaps we should expand the EIP-8037 refill rule to include the case of updating code 0->x->0.
EIP-7851 lacks a path to set authorization indicators on contracts. One advantage of the EIP-7702 account over proxy contracts is reduced call depth. The call depth increases, the less gas is available for subframes due to the 63/64 rule. This may result in a larger minimum gas limit for valid transactions. The newer opcode you proposed further reduces gas usage during operation because we can work with monolithic contracts while still having the ability to upgrade.