Skip to content

Back to the catalog

Pre-ERC: Adoption Profile and Reference Kernel for EOAs Adopting Code via SETCODEFROM
ethereum-magicians.orgthread

Pre-ERC: Adoption Profile and Reference Kernel for EOAs Adopting Code via SETCODEFROM

Pre-ERC proposal for EOAs that adopt account code via EIP-8298 SETCODEFROM, which with EIP-8151 retires the secp256k1 key. It lists seven failure modes (FM1-FM7), such as self-recovery lockout, ERC-1271 passing while VERIFY fails, front-runnable initialization and a mutable code source. It proposes requirements R1-R8, a MigrationCheck guard with two routes, and a reference kernel with post-quantum ERC-7913 verifiers.

TL;DR Proposes an adoption profile, migration guard and reference kernel so Ethereum EOAs can irreversibly retire their secp256k1 key without lockout.
Document

What it is

A pre-ERC draft by an author working on the EELS implementation of EIP-8151 (ethereum/execution-specs#3860). It defines an adoption profile for EOAs that replace their account code via EIP-8298 SETCODEFROM. Together with EIP-8151, adoption retires the secp256k1 key. Adoption is one-way, and neither EIP specifies what code to adopt. The proposal covers requirements R1–R8, a MigrationCheck guard, a migration typed-data format and a non-normative reference kernel.

Status as of the page: EIP-8141 (frame transactions) is Scheduled for Inclusion in Hegotá. EIP-8151 and EIP-8298 have been Considered for Inclusion since ACDE #247 (8 October 2026). The reference kernel needs all three. The profile and Route A need only EIP-8298 and EIP-8151.

How it works

The guard, MigrationCheck, reverts unless four checks hold in one transaction:

  • P1: the old key signed the migration.
  • P2: the signed code hash was adopted.
  • P3: the signed initialization ran.
  • P4: ecrecover now rejects the old key.

P1 and P4 are the same ecrecover call made twice. An invalid signature and an EIP-8151 rejection both return empty output (since ethereum/EIPs#12540, merged 18 October 2026). So P1 must return the account and P4 must return empty. Check returndatasize before reading memory, and forward gas() in both calls. A successful recovery costs 6,100 gas cold and 3,200 warm under EIP-8151, so a fixed 3,000 runs out of gas.

flowchart TD
  A[Migration signed by old key] --> B{Route}
  B -->|A: type-4 tx, 7702 to Migrator| C[begin: P1]
  B -->|B: 8141 frames, needs EIPs#12506| C
  C --> D[SETCODEFROM, P2]
  D --> E[initialize, P3]
  E --> F[finish: P4]
  F --> G[Migrated event]

Route A (normative) is a single type-4 transaction that delegates the EOA to Migrator and calls migrate. Route B (informative) is a VERIFY frame plus an atomic batch of four SENDER frames: begin, set-code, initialize, finish. Route B depends on ethereum/EIPs#12506, which is still open.

Failure modes

  • FM1: code that falls back to ecrecover(...) == address(this) locks the account out once adopted.
  • FM2: ERC-1271 can pass while the EIP-8141 VERIFY path is broken, leaving the account unable to act, even to replace its code.
  • FM3: initialization outside the adopting transaction either leaves the code with no key or can be front-run.
  • FM4: ETH and ERC-721/1155 safe transfers now run the code and revert without a payable path and receiver hooks. Senders that hard-code 21,000 gas can fail.
  • FM5: SETCODEFROM copies whatever code the source holds at that moment, so the user must sign a code hash, not an address.
  • FM6: an empty ecrecover result proves nothing, hence the double call.
  • FM7: EIP-8298 does not require EIP-8141. Without it, code that has no relay path can never send anything again, and no on-chain check detects this.

What to do

Wallet requirements proposed by the page:

  • Never sign Migration for an external origin such as a dApp's eth_signTypedData. Start it only from the wallet's own UI.
  • Register authorities only under verifiers the wallet recognizes, and check the old key can satisfy none of them.
  • Do not adopt code on a chain where the code cannot act. VERIFY needs EIP-8141, and a relay path needs its entry contract deployed.
  • Simulate on a fork before submitting: the whole migration, then an action signed with the new key. Keep the signed simulation off public networks, since it spends one signature with few-time PQ schemes.
  • Sign the 7702 authorization for the target chain ID, never 0.
  • Submit privately, and confirm by the Migrated event, not transaction success. If the 7702 authorization was skipped, migrate hits empty code and still succeeds.
  • Offer a second, separately held execution-capable authority.

Adopted-code requirements that matter most:

  • Initialize only from the account itself, and revert if the recorded hash equals EXTCODEHASH(this).
  • Make every signature path (VERIFY, ERC-1271, registration proofs, relay) call one shared verification.
  • Call verifiers via STATICCALL.
  • Make replacement carry the expected code hash and run the new code's initialize in the same call.
  • Verifiers must be stateless and immutable. An ecrecover-based secp256k1 verifier does not conform, because EIP-8151 makes ecrecover read code. Inline ecrecover owner checks common in ERC-4337 accounts break the same way.
  • Avoid bytes 0xA7, 0xF4 and 0xF2 at opcode positions in verifiers. A raw 1,312-byte ML-DSA-44 key contains 0xA7 at an opcode position in about 80% of cases, so the kernel stores keys as PUSH32 data.

Integrators should use ERC-1271 when an address holds code that is neither empty nor a 7702 delegation.

Caveats

  • The old key stays valid on chains where the account has not migrated, and on all chains if the authorization used chain ID 0.
  • EIP-8151 does not cover off-chain verification (SIWE, order books), Solidity secp256k1 code, or EIP-8141 SECP256K1 entries. The entries stay exploitable until ethereum/EIPs#12505 or an equivalent rule is active.
  • The guard checks the signed inputs, not code quality. Conformance comes from choosing a code hash checked against the profile and a test suite that does not exist yet.
  • The 100,000 MAX_VERIFY_GAS budget is tight. JARDIN's compact path is about 48K per its note or about 60K per its README. SLH-DSA-Keccak-128-24 is about 94K for verification alone.
  • The initData layout is undefined, so signers cannot yet display what it installs. The author also leaves open whether EIP-8298's mempool scan applies to the sender's own code.
  • The author found no prior standard targeting SETCODEFROM adoption. PoC-1 on EELS is planned for early November 2026.

Organisations named here

  • ecrecover
  • EIP-3607
  • EIP-8151
  • EIP-8298
  • EIP-8425
  • ERC-1271
  • ERC-7913
  • ERC-8286
  • ERC-8403
  • MigrationCheck
  • ML-DSA
  • Q-Day
  • SETCODEFROM

Technologies named here

  • Migrator
  • EIP-8141 frame transactions
  • Reference kernel
  • Chains with EIP-8298 but without EIP-8141
  • ERC-7913 verifiers
  • EELS PoC-1 implementation of EIP-8151 and EIP-8298
  • EIP-8141 SECP256K1 entries naming a migrated account
  • JARDIN
  • SLH-DSA-Keccak-128-24
  • EIP-712 typed data
  • Prior art reviewed
  • Ethereum
  • EIP-7702
  • Solidity
  • EIP-8141
  • ERC-4337

Techniques named here

  • FM1 self-recovery lockout
  • FM2
  • FM3
  • FM4
  • FM5
  • FM7