-
Notifications
You must be signed in to change notification settings - Fork 1.4k
feat(chain): add EIP-7702 set-code transactions for EOAs #13408
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
…setext to ATX and fix nesting
…, EthTx.authorizationList, and dispatch (Phase-1)
…rd checks in test plan
…ENTS with scaffolding and next steps
… ToUnsignedFilecoinMessage; adjust delegator types to avoid cycles; update AGENTS.md
…ons; actor: add no-op ApplyDelegations stub; update AGENTS.md
… expand AGENTS with state + scaffolding pointers
…dFilecoinMessage; delegator: add ApplyDelegationsParams; update AGENTS
… feature enabled and delegator-targeted; update docs
…stment wiring; list new scaffolding files
…ainId set) with tests; update AGENTS
…e ToEthTx carries authorizationList; update AGENTS
…ests; docs: update AGENTS tests list
…s; tests for writes and mismatched nonce; clarify actor stub
…d mapping/nonce tests
… validation commands and test guidance
…; add unit test for application + nonce bump
…ests (unit-only; package requires FFI to run full tests)
…sages; add isolated policy helper + tests
…hen build tag enabled
…s completed; note scaffolded ApplyDelegations core
… event ABI; trivial fmt diffs
…topic/data (authority) confirmed; tests to follow
… update AGENTS Quick Validation
…flict by centralizing ParseEthRevert in chain/types/ethtypes and updating tests
…avoid OpenCL; plan targeted tests if needed
…ove single-EVM-actor references; mark EVM ApplyAndCall/InvokeAsEoa removed; update next steps and test plans
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please update the PR title to match https://github.com/filecoin-project/lotus/blob/master/CONTRIBUTING.md#pr-title-conventions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements EIP-7702 ("Set Code for EOAs") support in Lotus, enabling Ethereum-style delegated execution for Externally Owned Accounts (EOAs) on the Filecoin network. The implementation routes type-0x04 transactions to an EthAccount actor's ApplyAndCall entrypoint, with delegation semantics handled via VM intercept in ref-fvm.
Key Changes:
- Added RLP decoding/encoding for type-0x04 transactions with authorization tuples and per-type element limits
- Implemented routing to EthAccount.ApplyAndCall with canonical CBOR parameter encoding
- Extended receipts to surface authorizationList and delegatedTo fields for attribution
Reviewed Changes
Copilot reviewed 68 out of 70 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
chain/types/ethtypes/rlp.go |
Added per-type RLP element limits for 0x04 (13 elements vs 12 for EIP-1559) |
chain/types/ethtypes/eth_types.go |
Extended EthTxReceipt with authorizationList and delegatedTo fields |
chain/types/ethtypes/eth_transactions.go |
Added 0x04 transaction parsing, CBOR decoding for ApplyAndCall params, and routing logic |
node/impl/eth/utils.go |
Added embedded status decoding from ApplyAndCall return for receipts |
node/impl/eth/receipt_7702_scaffold.go |
Implemented receipt adjustment for delegated execution attribution |
node/impl/eth/gas_7702_scaffold.go |
Added behavioral gas overhead computation for authorization tuples |
node/impl/eth/gas.go |
Integrated 7702 intrinsic overhead into gas estimation |
| Test files | Comprehensive test coverage for RLP parsing, receipts, gas estimation, and E2E flows |
| Documentation | OpenRPC updates and migration plan documentation |
Comments suppressed due to low confidence (2)
node/impl/eth/utils.go:1
- Use the named constant
EIP7702TxTypeinstead of the magic number0x04for consistency with the rest of the codebase and improved maintainability.
itests/kit/node_unmanaged.go:1 - This change appears unrelated to EIP-7702. If this is addressing a separate CI flakiness issue, it should be in a separate commit or PR to maintain atomic changes.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
PR title now matches the required format.
Related PRs
filecoin-project/FIPs#1209
filecoin-project/builtin-actors#1705
#13408
filecoin-project/ref-fvm#2227
EIP‑7702 Reviewers Guide (Lotus + builtin‑actors + ref‑fvm)
Audience: Filecoin core devs and reviewers looking at the coordinated 7702 changes in
../builtin-actors,../ref-fvm, and../lotus.Scope: Explains the current EthAccount + VM‑intercept design, how the three repos fit together, and where to focus review and testing.
1. Conceptual Model
What 7702 does (in this branch)
0x04txs carry anauthorizationListof signed tuples that let an EOA delegate execution to a contract.delegate_to,auth_nonce,evm_storage_root.ref-fvm) intercepts CALLs to delegated EOAs and implements the execution semantics and EXTCODE* pointer projection.EthAccount.ApplyAndCallmessage, and reconstructs receipts (status +authorizationList+delegatedTo).Key invariants (cross‑repo)
SELFDESTRUCTin authority context is a no‑op.0xEF 0x01 0x00 || delegate(20).keccak256("Delegated(address)"), data is a 32‑byte ABI word with the authority address.2. End‑to‑End Data Flow
eth_sendRawTransaction(0x04)0x04payload intoEth7702TxArgswithauthorizationListand outer call fields (to,value,input).ToUnsignedFilecoinMessageAtomicbuilds a Filecoin message targetingEthAccount.ApplyAndCallwith canonical CBOR params(
[ [tuple...], [to(20), value, input] ])– see
chain/types/ethtypes/eth_7702_transactions.go:121.EthAccount.ApplyAndCall(builtin‑actors)0x05 || rlp(...)domain, enforces per‑authority nonce equality, updatesdelegate_to/auth_nonce/evm_storage_root, and then executes the outer call (possibly to an EVM contract).ApplyAndCallReturn– see
../builtin-actors/actors/ethaccount/src/lib.rs:187.VM Execution (
ref-fvm)CALLto an EOA that hasdelegate_toset, the VM’sDefaultCallManagerintercepts the call instead of the EVM interpreter following delegation.evm_storage_rootfrom EthAccount state).InvokeAsEoaWithRoot).Delegated(address)best‑effort, and returns revert codes/data back to the caller.– see
../ref-fvm/fvm/src/call_manager/default.rs:560.EXTCODE Pointer Projection (
ref-fvm+ EVM)*delegate_toset (via a new syscall).EXTCODESIZE/HASH/COPYoperate over the virtual pointer image0xEF 0x01 0x00 || delegate(20); windowing and zero‑fill semantics are enforced in tests.Receipts & RPC (Lotus)
newEthTxReceiptcomputes the 7702 receipt status from theApplyAndCallReturnCBOR (status field), not from the Filecoin exit code; the actor always exits OK – seenode/impl/eth/utils.go:450.adjustReceiptForDelegationpopulates:authorizationListfrom the tx view, anddelegatedToeither from tuples or from the syntheticDelegated(address)event emitted by the VM intercept – seenode/impl/eth/receipt_7702_scaffold.go:19andnode/impl/eth/transaction.go:345.3. On‑Chain Logic (builtin‑actors)
3.1 EthAccount Actor
State
State { delegate_to: Option<EthAddress>, auth_nonce: u64, evm_storage_root: Cid }– see
../builtin-actors/actors/ethaccount/src/state.rs:5.delegate_toandauth_noncepersist across transactions;evm_storage_rootis used by the VM intercept to mount authority storage.Validation & Authority Recovery
validate_tupleenforces:chain_id ∈ {0, local}len(r), len(s) ≤ 32, rejects> 32randsnon‑zeroy_parity ∈ {0,1}sis low‑s after left‑padding to 32 bytes – seevalidate_tupleandis_high_sinethaccount/src/lib.rs.recover_authoritycomputes:msg = keccak256(0x05 || rlp([chain_id, address(20), nonce]))(domain separator)EthAddress– seeethaccount/src/lib.rsabove the constructor.ApplyAndCall semantics
(
EthAccountActor::apply_and_call,ethaccount/src/lib.rs:189)authorizationListnon‑empty and≤ 64tuples (tuple cap).auth_noncevs tuple nonce, absent treated as 0).rt.transaction, for each tuple:delegate_to.delegate_to = Some(address).auth_nonce(saturating).evm_storage_rootif empty.call.to(EthAddress→ FilecoinAddress) andcall.value(bytes →U256→TokenAmount).get_actor_code_cid.InvokeContractParams { input_data }and calls EVM’sInvokeEVMentrypoint with that payload and value.METHOD_SENDwith the value and no params.ApplyAndCallReturn { status, output_data }to the caller, wherestatus = 1iff the callee exit code wasExitCode::OK.rt.sendfails at the syscall level,status=0andoutput_data=[].–
../builtin-actors/actors/ethaccount/tests/apply_and_call_invalids.rs–
../builtin-actors/actors/ethaccount/tests/apply_and_call_cbor_fuzz.rs.apply_and_call_nonces.rs,apply_and_call_tuple_cap_boundary.rs.apply_and_call_rs_padding.rs.apply_and_call_value_transfer.rs.apply_and_call_outer_call.rs.3.2 EVM Actor
../builtin-actors/actors/evm/src/lib.rs)ApplyAndCallandInvokeAsEoaare no longer used;InvokeAsEoais a stub returningillegal_state.InvokeAsEoaWithRootremains as a private trampoline used by the VM intercept to execute delegate bytecode under the authority context, with an explicit storage root.ref-fvm(see section 4.2).4. VM Layer (
ref-fvm)4.1 Delegated CALL Intercept
Entry point
DefaultCallManager::intercept_evm_call_to_ethaccount(inlined intocall_actor_unchecked) – see../ref-fvm/fvm/src/call_manager/default.rs:560."InvokeEVM"(EVM Invoke entrypoint).delegate_toset.Flow (high level)
delegate_to,auth_nonce,evm_storage_root). Ifdelegate_toisNone, do not intercept.delegate_toas a delegated f4 under EAM, ensure actor exists.GetBytecodemethod (method 3) to obtain the bytecode CID; abort interception if missing or non‑success.paramsblock.caller_eth20from the caller’s f4 delegated address, andauthority_eth20from the EthAccount’s f4 delegated address.InvokeAsEoaWithRootparams:code: delegate bytecode CID.input: original CALL input.caller: callerEthAddress(20 bytes).receiver: authorityEthAddress(20 bytes).value: original CALL value.initial_storage_root:ea.evm_storage_root.value != 0, charge gas andtransfer(from, to, value).evm_storage_root– seedelegated_value_transfer_short_circuit.rs.delegation_active = truefor this call so nested CALLs by the delegate do not re‑enter the interception path (depth limit = 1).InvokeAsEoaWithRootmethod (self‑call) with full available gas.delegated_call_mapping.rs.(output_data, new_storage_root)from the return block.evm_storage_rootwhile preserving balance and code.Delegated(address)event:topic0 = keccak256("Delegated(address)").authority_eth20.output_dataas IPLDIPLD_RAWblock to the EVM interpreter.Depth limit & SELFDESTRUCT
delegation_activeflag ensures nested CALLs are not re‑intercepted; depth is strictly 1 – see../ref-fvm/fvm/tests/depth_limit.rs.SELFDESTRUCTdoes not move balance or tombstone the authority; behavior is tested inselfdestruct_noop_authority.rs.Storage overlay semantics
evm_storage_rootis mounted before executing delegate code.overlay_persist_success.rs.evm_storage_rootis left unchanged – seedelegated_call_mapping.rsanddelegated_value_transfer_short_circuit.rs.Tests to review
delegated_call_mapping.rs– success path and revert payload propagation.delegated_event_emission.rs– topic and ABI word correctness forDelegated(address).overlay_persist_success.rs– storage overlay persistence on success.delegated_value_transfer_short_circuit.rs– value transfer failure semantics.depth_limit.rs– depth=1 enforcement.selfdestruct_noop_authority.rs–SELFDESTRUCTno‑op.4.2 EXTCODE* Pointer Projection
Runtime helper + syscall
actor::get_eth_delegate_to:../ref-fvm/fvm/src/syscalls/actor.rs:182.extract_eth20andget_eth_delegate_toin../ref-fvm/sdk/src/actor.rs:180.delegate_toif set; supports both 20‑byte and 32‑byte (ABI word) encodings by slicing the last 20 bytes.Interpreter behavior
get_eth_delegate_to(target_id)when executing EXTCODE* on EOAs.EXTCODESIZEreturns23.EXTCODEHASHreturnskeccak(pointer_code).EXTCODECOPYreturns the appropriate window intopointer_code, with zero‑fill on out‑of‑range offsets.evm_extcode_projection.rs(windowing and zero‑fill) and by hash checks.Helper tests
sdk/src/actor.rshas unit tests forextract_eth20to ensure correct slicing behavior for short/20/32‑byte inputs.4.3 Test Harness / Runner
../ref-fvm/scripts/run_eip7702_tests.sh:ref-fvmmounted) and then runscargo test -p fvm.5. Lotus Client Behavior
5.1 Transaction Parsing and Encoding
RLP and magic constants
Eth7702TxArgsandEthAuthorizationlive inchain/types/ethtypes/eth_7702_transactions.go.SetCodeAuthorizationMagic = 0x05.{Eip7702BytecodeMagicHi = 0xEF, MagicLo = 0x01, Version = 0x00}.AuthorizationPreimageandAuthorizationKeccakimplement the hashing logic used by EthAccount – seechain/types/ethtypes/eth_7702_magic.go.ToUnsignedFilecoinMessageAtomic (
eth_7702_transactions.go:121)ChainID == buildconstants.Eip155ChainId.Eip7702FeatureEnabledand a configuredEthAccountApplyAndCallActorAddr.[ [tuples...], [to(20), value, input] ]and builds atypes.Message:To = EthAccountApplyAndCallActorAddr.Method = MethodHash("ApplyAndCall")(FRC‑42).Value = 0(gas and fees only; outer call value is embedded in params).5.2 Receipts & RPC Surface
Types
EthTxgainsAuthorizationList []EthAuthorization.EthTxReceiptgains:AuthorizationList []EthAuthorization(copied from tx view), andDelegatedTo []EthAddress(derived by Lotus) – seechain/types/ethtypes/eth_types.go:1260.Receipt construction (
node/impl/eth/utils.go:450)newEthTxReceipt:Tx+MessageReceipt.AuthorizationListif present on the tx.Statusoff the FilecoinExitCode(1 on success, 0 otherwise).tx.Type == 0x04and the Filecoin return payload is non‑empty,decodeApplyAndCallReturnStatusparses[status(uint), output_data(bytes)]and setsStatus = (status != 0).Delegation attribution (
adjustReceiptForDelegation)EthGetTransactionReceiptandEthGetBlockReceipts*– see
node/impl/eth/transaction.go:345.AuthorizationListis non‑empty,DelegatedTois populated from the tuple addresses.DelegatedTois still empty, it scans receipt logs for topickeccak256("Delegated(address)")and:dataas a 32‑byte ABI word and copies the last 20 bytes into anEthAddress, appending toDelegatedTo.delegatedToeither from tuples or from the synthetic event emitted byref-fvm.Tests to review
node/impl/eth/utils_7702_test.go– ensuresAuthorizationListround‑trips into receipts.node/impl/eth/receipt_7702_scaffold_test.go– exercisesadjustReceiptForDelegationboth from tuples and logs.node/impl/eth/transaction_7702_receipts_test.go– validates end‑to‑end receipt behavior for 0x04.5.3 Gas Estimation
node/impl/eth/gas_7702_scaffold.go)compute7702IntrinsicOverhead(authCount int) int64is a placeholder model:0whenauthCount == 0.baseOverheadGas + perAuthBaseGas * authCountotherwise.countAuthInApplyAndCallParams(params []byte) intparses the CBOR ApplyAndCall payload and returns the number of tuples in the list; this is used byeth_estimateGasto add per‑tuple overhead when the target isEthAccount.ApplyAndCall.5.4 E2E Tests
itests/eth_7702_e2e_test.go(build tageip7702_enabled)TestEth7702_SendRoutesToEthAccount:authorizationList.eth_sendRawTransaction.EthAccount.ApplyAndCallfrom the recovered f4 sender.TestEth7702_ReceiptFields:authorizationListanddelegatedTo.6. Security, Spec Compliance, and Edge Cases
Atomicity and persistence
auth_nonceinside a transaction before the outer call.statusembedded in return.ref-fvm:evm_storage_root) persists only on successful delegated CALLs; it is discarded on revert or transfer short‑circuit.Pre‑existence policy
Tuple cap and duplicates
≤ 64enforced in EthAccount.authorizationListare rejected.Signature robustness
r/s.1..31and32byter/sand left‑pads to 32 bytes; rejects> 32.r/srejected.apply_and_call_rs_padding.rslock in the positive/negative cases.Depth,
SELFDESTRUCT, and revertsSELFDESTRUCTis a no‑op in authority context (no balance move, no tombstone).RETURNDATASIZE/RETURNDATACOPYsee the delegate’s revert payload, subject to the minimal‑feature caveat in tests.Pointer semantics
Adelegated toB:EXTCODESIZE(A) == 23.EXTCODECOPY(A, 0, 0, 23)→0xEF 0x01 0x00 || B(20).EXTCODEHASH(A) == keccak(pointer_code).evm_extcode_projection.rs.7. How to Review (Per Repo)
builtin‑actors (
../builtin-actors)actors/ethaccount/src/lib.rs:187–ApplyAndCallvalidation, nonce/mapping updates, pre‑existence checks, and outer call routing.actors/ethaccount/src/state.rs:5– state struct.actors/evm/src/lib.rs– removal of legacy delegation entrypoints; presence and use ofInvokeAsEoaWithRoot.actors/ethaccount/tests/*.AuthorizationKeccakencoding and RLP rules.ref-fvm(../ref-fvm)fvm/src/call_manager/default.rs:560.keccak32and FRC‑42 helpers and their tests in the same file.get_eth_delegate_to:fvm/src/syscalls/actor.rs:182.sdk/src/sys/actor.rsandsdk/src/actor.rs:180.SELFDESTRUCT, and events infvm/tests/*.rs.InvokeEVMto EthAccount with activedelegate_to).Lotus (
./lotus)chain/types/ethtypes/eth_7702_transactions.go:121.AuthorizationKeccakinchain/types/ethtypes/eth_7702_magic.go.AuthorizationListcopying innode/impl/eth/utils.go:450.adjustReceiptForDelegationand wiring innode/impl/eth/receipt_7702_scaffold.go:19andnode/impl/eth/transaction.go:345.node/impl/eth/gas_7702_scaffold.go.itests/eth_7702_e2e_test.go.TxHash/AuthorizationKeccakparity with EthAccount’s internal recovery logic.EthTx/EthTxReceiptJSON surfaces match expectations (tooling should seeauthorizationListanddelegatedTo).ApplyAndCallReturn.status.8. How to Run the Relevant Tests
ref-fvm+ builtin‑actors../ref-fvm/scripts/run_eip7702_tests.sh(Docker bundle +cargo test -p fvm).builtin‑actors (local)
make checkcargo test -p fil_actor_evmcargo test -p fil_actor_ethaccountLotus
go test ./chain/types/ethtypes -run 7702 -count=1go test ./node/impl/eth -run 7702 -count=1eip7702_enabledtag):go test ./itests -run Eth7702 -tags eip7702_enabled -count=1This guide should match the current EthAccount + VM‑intercept implementation across all three repos. If you want, I can now tailor a shorter reviewer checklist per PR (e.g., “things to look at commit‑by‑commit” for each repo).
Checklist
Before you mark the PR ready for review, please make sure that:
management)