
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.
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
Related in Blockchain

THORChain Exploit Report #2 — GG20 root-cause disclosure

Black Thursday revisited: MakerDAO keeper exploited for $500K
.jpg)