EIP‑7702: VM Intercept for Delegated CALLs, EXTCODE* Pointer Projection, Authority Storage Overlay, and Event Emission
EIP‑7702: VM Intercept for Delegated CALLs, EXTCODE* Pointer Projection, Authority Storage Overlay, and Event Emission
Summary
- Implements EIP‑7702 execution semantics in ref‑fvm:
- Intercept EVM CALL/STATICCALL to EthAccount (EOA) with active delegation and execute the delegate code under an authority context with depth=1.
- Project a virtual 23‑byte pointer code for delegated EOAs on EXTCODESIZE/HASH/COPY.
- Mount and persist an authority storage overlay (
evm_storage_root) on success. - Emit best‑effort
Delegated(address)event with the authority encoded as a 32‑byte ABI word. - Propagate revert codes and bytes to the EVM return buffer.
- Adds runtime/SDK syscall
get_eth_delegate_to(ActorID) -> Option<[u8;20]>for EXTCODE* pointer projection and tests. - Provides a Dockerized test runner to build the builtin‑actors Wasm bundle and run end‑to‑end ref‑fvm tests.
Motivation
- Complete the migration of EIP‑7702 semantics from the EVM actor into the VM:
- Delegation state moves into EthAccount so it is globally visible.
- VM handles delegated dispatch and pointer projection so the interpreter remains minimal and does not re‑follow delegation internally.
- Keeps Lotus’ client behavior aligned (receipts attribution via tuples or the synthetic event; behavioral gas model remains unchanged).
Key Changes
- VM intercept (DefaultCallManager):
- Gate on EVM
InvokeEVMcalls to an EthAccount target with a non‑emptydelegate_to. - Resolve the delegate from the 20‑byte ETH address via EAM into f4, confirm code via
EVM.GetBytecode. - Perform value transfer to the authority first; on failure, short‑circuit with a revert‑like mapping (no execution).
- Invoke the caller EVM actor’s trampoline
InvokeAsEoaWithRoot(FRC‑42 hash) with(code_cid, input, caller, receiver, value, initial_storage_root). - Decode
(output_data, new_storage_root), persistnew_storage_rootto the EthAccount, and emitDelegated(address)(topic keccak("Delegated(address)"), data = 32‑byte ABI word with right‑aligned authority). - Return
ExitCode::OK+ raw IPLD return bytes on success; propagate non‑success code and revert data as received. - Depth limit enforced: delegation is not re‑followed in authority context; SELFDESTRUCT is a no‑op.
- Gate on EVM
- EXTCODE* pointer projection:
- EVM interpreter consults the runtime helper; when
delegate_tois set, expose a 23‑byte virtual code image0xEF 0x01 0x00 || <delegate(20)>. - EXTCODESIZE=23, EXTCODEHASH=keccak(pointer_code), EXTCODECOPY honors windowing with zero‑fill semantics.
- EVM interpreter consults the runtime helper; when
- SDK/syscalls:
- New syscall
actor::get_eth_delegate_toplumbed through kernel + SDK (sdk/src/actor.rs,sdk/src/sys/actor.rs,fvm/src/syscalls/actor.rs). - Adds a pure helper and unit tests for the 20‑byte extraction.
- New syscall
- Utilities:
- Local
frc42_method_hashandkeccak32helpers used in intercept code.
- Local
Files
- VM intercept and helpers:
fvm/src/call_manager/default.rs
- Syscalls/SDK:
fvm/src/syscalls/actor.rsfvm/src/syscalls/mod.rssdk/src/actor.rssdk/src/sys/actor.rs
- Tests:
fvm/tests/evm_extcode_projection.rs(EXTCODESIZE/HASH/COPY pointer image)fvm/tests/delegated_call_mapping.rs(mapping + storage overlay persist)fvm/tests/delegated_value_transfer_short_circuit.rs(failed transfer → revert mapping)fvm/tests/depth_limit.rs(no re‑follow A→B→C)fvm/tests/selfdestruct_noop_authority.rs(SELFDESTRUCT no‑op under authority context)fvm/tests/overlay_persist_success.rs(overlay mount/persist success path)fvm/tests/eth_delegate_to.rs(helper syscall)fvm/tests/ethaccount_state_roundtrip.rs(state view round‑trip)fvm/tests/common.rs(EthAccount install + helper utilities)
- Tooling:
scripts/run_eip7702_tests.sh(Docker bundle build + ref‑fvm test runner with host fallback)
Behavioral Details
- Intercept trigger:
- Only when entrypoint is EVM’s
InvokeEVMand the receiver is an EthAccount withdelegate_toset.
- Only when entrypoint is EVM’s
- Value transfer:
- Charged and executed before invoking the trampoline; failure maps to non‑success without executing the delegate.
- Authority context:
- Depth limit = 1; no nested delegation follow.
- SELFDESTRUCT is a no‑op (no balance move or tombstone).
- Storage overlay:
- Mount
evm_storage_rootprior to execution; persist updated root to EthAccount state on success only.
- Mount
- Events:
- Emit
Delegated(address)with ABI‑encoded 32‑byte word; best‑effort (may be dropped under extreme gas tightness).
- Emit
- Revert mapping:
- Revert exit codes and data are propagated as‑is; EVM surface exposes bytes via
RETURNDATASIZE/RETURNDATACOPY.
- Revert exit codes and data are propagated as‑is; EVM surface exposes bytes via
- EXTCODE*:
- Virtual 23‑byte pointer image is exposed with correct windowing and zero‑fill.
Testing
- Unit tests cover:
- EXTCODE* projection: size/hash/copy and partial/out‑of‑bounds reads.
- Delegated CALL success and revert, revert data correctness.
- Value transfer short‑circuit behavior.
- Depth limit (A→B→C).
- SELFDESTRUCT no‑op under authority context.
- EthAccount state view round‑trips and helper syscall behavior.
- Runner:
scripts/run_eip7702_tests.shbuilds the builtin‑actors bundle in Docker, then runs ref‑fvm tests; falls back to in‑Docker tests if host toolchain fails.
How To Test
- Host (if toolchain permits):
cargo test -p fvm --tests -- --nocapture
- Dockerized (recommended, especially on macOS):
./scripts/run_eip7702_tests.sh
- Pair with builtin‑actors (eip7702 branch) to build a fresh bundle for end‑to‑end EXTCODE*/delegation tests.
Compatibility / Notes
- No runtime NV gate; activation is via the Wasm bundle.
- Adds a new syscall; SDK consumers can use
sdk::actor::get_eth_delegate_toto detect delegation and expose pointer images. - EVM interpreter no longer re‑follows delegation internally; the VM intercept is authoritative.
Follow‑Ups
- Extend negative‑path/edge tests if coverage flags regressions in
call_manager/default.rs. - Telemetry: decide whether to reserve a small fixed gas budget for event emission if
Delegated(address)drops frequently under gas tightness. - Keep coverage profiles consistent between base and patch to ensure delegated paths are exercised.
Related Changes
- builtin‑actors (paired
eip7702): EthAccount state expanded (delegate_to,auth_nonce,evm_storage_root),ApplyAndCalladded; EVM.ApplyAndCall and InvokeAsEoa removed;InvokeAsEoaWithRootremains for the trampoline. - Lotus (paired
eip7702): route type‑0x04 toEthAccount.ApplyAndCall; receipt adjuster recognizesDelegated(address)topic with 32‑byte ABI word; behavioral gas estimation based on tuple count.
Thanks for reviewing. Happy to split or annotate commits further if helpful.
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)
- Ethereum
0x04txs carry anauthorizationListof signed tuples that let an EOA delegate execution to a contract. - In this Filecoin integration:
- Delegation state lives in EthAccount (per‑EOA):
delegate_to,auth_nonce,evm_storage_root. - The EVM actor is kept minimal; it no longer stores delegation or follows it internally.
- The VM (
ref-fvm) intercepts CALLs to delegated EOAs and implements the execution semantics and EXTCODE* pointer projection. - Lotus parses 0x04 RLP, builds an
EthAccount.ApplyAndCallmessage, and reconstructs receipts (status +authorizationList+delegatedTo).
- Delegation state lives in EthAccount (per‑EOA):
- Ethereum
-
Key invariants (cross‑repo)
- Delegation + nonce bumps persist even if the outer call reverts (spec‑compliant atomicity).
- Authorities must not be EVM contracts (pre‑existence policy).
- Delegation depth is capped at 1;
SELFDESTRUCTin authority context is a no‑op. - EXTCODE* on delegated EOAs exposes a 23‑byte pointer code
0xEF 0x01 0x00 || delegate(20). - Event topic for delegated execution is
keccak256("Delegated(address)"), data is a 32‑byte ABI word with the authority address.
2. End‑to‑End Data Flow
-
eth_sendRawTransaction(0x04)- Lotus decodes the RLP
0x04payload intoEth7702TxArgswithauthorizationListand outer call fields (to,value,input). ToUnsignedFilecoinMessageAtomicbuilds a Filecoin message targetingEthAccount.ApplyAndCallwith canonical CBOR params
([ [tuple...], [to(20), value, input] ])
– seechain/types/ethtypes/eth_7702_transactions.go:121.
- Lotus decodes the RLP
-
EthAccount.ApplyAndCall(builtin‑actors)- EthAccount validates the tuples, recovers the authority from the
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). - EthAccount itself always exits OK and embeds the callee’s success bit + returndata in
ApplyAndCallReturn
– see../builtin-actors/actors/ethaccount/src/lib.rs:187.
- EthAccount validates the tuples, recovers the authority from the
-
VM Execution (
ref-fvm)- When an EVM contract later does
CALLto an EOA that hasdelegate_toset, the VM’sDefaultCallManagerintercepts the call instead of the EVM interpreter following delegation. - The intercept:
- Resolves the delegate EVM actor and its bytecode.
- Mounts the authority storage overlay (
evm_storage_rootfrom EthAccount state). - Executes the delegate under an “authority context” trampoline (
InvokeAsEoaWithRoot). - Persists the new storage root on success, emits
Delegated(address)best‑effort, and returns revert codes/data back to the caller.
– see../ref-fvm/fvm/src/call_manager/default.rs:560.
- When an EVM contract later does
-
EXTCODE Pointer Projection (
ref-fvm+ EVM)*- The EVM interpreter calls a runtime helper to check if a target ID has
delegate_toset (via a new syscall). - For delegated EOAs,
EXTCODESIZE/HASH/COPYoperate over the virtual pointer image0xEF 0x01 0x00 || delegate(20); windowing and zero‑fill semantics are enforced in tests. - The interpreter itself no longer performs dynamic delegation or storage mounting.
- The EVM interpreter calls a runtime helper to check if a target ID has
-
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)- recovers the secp256k1 pubkey and then the 20‑byte
EthAddress– seeethaccount/src/lib.rsabove the constructor.
-
ApplyAndCall semantics
(EthAccountActor::apply_and_call,ethaccount/src/lib.rs:189)- Enforces:
authorizationListnon‑empty and≤ 64tuples (tuple cap).- All tuples in a message target the receiver authority only (no multi‑authority apply in one call).
- No duplicate authorities within the list.
- Pre‑existence: rejects if the authority resolves to an EVM contract actor.
- Nonce equality for the receiver (
auth_noncevs tuple nonce, absent treated as 0).
- Persistence:
- Within a
rt.transaction, for each tuple:- If delegate address is zero → clears
delegate_to. - Otherwise sets
delegate_to = Some(address). - Increments
auth_nonce(saturating). - Initializes
evm_storage_rootif empty.
- If delegate address is zero → clears
- This transaction commits before the outer call, so mapping + nonce persist even if the outer call fails or reverts.
- Within a
- Outer call:
- Decodes
call.to(EthAddress→ FilecoinAddress) andcall.value(bytes →U256→TokenAmount). - Detects whether the target is an EVM builtin actor by resolving the ID and
get_actor_code_cid. - If EVM target:
- CBOR‑encodes
InvokeContractParams { input_data }and calls EVM’sInvokeEVMentrypoint with that payload and value.
- CBOR‑encodes
- If non‑EVM or unresolved:
- Sends a plain
METHOD_SENDwith the value and no params.
- Sends a plain
- In all cases:
- EthAccount returns
ApplyAndCallReturn { status, output_data }to the caller, wherestatus = 1iff the callee exit code wasExitCode::OK. - If the
rt.sendfails at the syscall level,status=0andoutput_data=[].
- EthAccount returns
- Decodes
- Tests to check:
- Invalid cases: chainId, yParity, r/s size and zero, tuple arity, CBOR fuzzing
–../builtin-actors/actors/ethaccount/tests/apply_and_call_invalids.rs
–../builtin-actors/actors/ethaccount/tests/apply_and_call_cbor_fuzz.rs. - Nonces and duplicates –
apply_and_call_nonces.rs,apply_and_call_tuple_cap_boundary.rs. - R/S padding (accept 1..31, 32; reject >32) –
apply_and_call_rs_padding.rs. - Value transfer behavior –
apply_and_call_value_transfer.rs. - Outer call routing and status mapping –
apply_and_call_outer_call.rs.
- Invalid cases: chainId, yParity, r/s size and zero, tuple arity, CBOR fuzzing
- Enforces:
3.2 EVM Actor
- Minimalization (
../builtin-actors/actors/evm/src/lib.rs)- Delegation state and execution have been removed from the EVM actor:
- Legacy
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.
- Legacy
- The interpreter:
- Executes EVM bytecode normally for direct calls.
- No longer re‑follows delegation internally – delegation is entirely handled at the VM layer.
- EXTCODE* behavior consults the runtime helper for delegated EOAs, but the pointer image itself is defined in
ref-fvm(see section 4.2).
- Delegation state and execution have been removed from the EVM actor:
4. VM Layer (ref-fvm)
4.1 Delegated CALL Intercept
-
Entry point
- Implemented in
DefaultCallManager::intercept_evm_call_to_ethaccount(inlined intocall_actor_unchecked) – see../ref-fvm/fvm/src/call_manager/default.rs:560. - Gated by:
- Receiver code being an EthAccount builtin actor.
- Entrypoint method matching FRC‑42 hash of
"InvokeEVM"(EVM Invoke entrypoint). - A non‑empty EthAccount state with
delegate_toset.
- Implemented in
-
Flow (high level)
- Fetch caller and receiver actor state.
- Decode EthAccount state (
delegate_to,auth_nonce,evm_storage_root). Ifdelegate_toisNone, do not intercept. - Resolve
delegate_toas a delegated f4 under EAM, ensure actor exists. - Call the delegate’s
GetBytecodemethod (method 3) to obtain the bytecode CID; abort interception if missing or non‑success. - Extract the EVM input bytes from the original
paramsblock. - Compute:
caller_eth20from the caller’s f4 delegated address, andauthority_eth20from the EthAccount’s f4 delegated address.
- Build
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.
- Perform a value transfer to the authority before executing delegate code:
- If
value != 0, charge gas andtransfer(from, to, value). - On failure, short‑circuit: return a non‑success exit code and empty return bytes; do not execute the delegate and do not alter
evm_storage_root– seedelegated_value_transfer_short_circuit.rs.
- If
- Mark
delegation_active = truefor this call so nested CALLs by the delegate do not re‑enter the interception path (depth limit = 1). - Invoke the caller EVM actor’s
InvokeAsEoaWithRootmethod (self‑call) with full available gas. - On non‑success, propagate the exit code + return block as‑is to the original CALL (revert mapping), and do not persist storage – see
delegated_call_mapping.rs. - On success:
- Decode
(output_data, new_storage_root)from the return block. - Write updated EthAccount state with the new
evm_storage_rootwhile preserving balance and code. - Emit a
Delegated(address)event:topic0 = keccak256("Delegated(address)").- Data: one 32‑byte ABI word whose last 20 bytes are
authority_eth20.
- Return OK + raw
output_dataas IPLDIPLD_RAWblock to the EVM interpreter.
- Decode
-
Depth limit & SELFDESTRUCT
delegation_activeflag ensures nested CALLs are not re‑intercepted; depth is strictly 1 – see../ref-fvm/fvm/tests/depth_limit.rs.- In authority context,
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.- On success, the new storage root is persisted back into EthAccount state – see
overlay_persist_success.rs. - On revert or transfer short‑circuit, the overlay is discarded and
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
- New syscall
actor::get_eth_delegate_to:- Kernel implementation:
../ref-fvm/fvm/src/syscalls/actor.rs:182. - SDK wrapper + pure helper:
extract_eth20andget_eth_delegate_toin../ref-fvm/sdk/src/actor.rs:180.
- Behavior: returns the 20‑byte
delegate_toif set; supports both 20‑byte and 32‑byte (ABI word) encodings by slicing the last 20 bytes.
- Kernel implementation:
- New syscall
-
Interpreter behavior
- The EVM interpreter checks
get_eth_delegate_to(target_id)when executing EXTCODE* on EOAs. - If a delegate is present:
EXTCODESIZEreturns23.EXTCODEHASHreturnskeccak(pointer_code).EXTCODECOPYreturns the appropriate window intopointer_code, with zero‑fill on out‑of‑range offsets.
- Validated by
evm_extcode_projection.rs(windowing and zero‑fill) and by hash checks.
- The EVM interpreter 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:- Builds the builtin‑actors bundle in Docker (with
ref-fvmmounted) and then runscargo test -p fvm. - Falls back to running tests inside Docker if the host toolchain fails.
- Coverage includes EXTCODE* projection, depth limit, value transfer short‑circuit, overlay persistence, and event emission.
- Builds the builtin‑actors bundle in Docker (with
5. Lotus Client Behavior
5.1 Transaction Parsing and Encoding
-
RLP and magic constants
Eth7702TxArgsandEthAuthorizationlive inchain/types/ethtypes/eth_7702_transactions.go.- Per‑type RLP list length for 0x04 is enforced (13 elements) with per‑field parsing and yParity checks.
- Magic constants and domain helpers:
SetCodeAuthorizationMagic = 0x05.- Pointer bytecode prefix and version:
{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)- Enforces
ChainID == buildconstants.Eip155ChainId. - Requires
Eip7702FeatureEnabledand a configuredEthAccountApplyAndCallActorAddr. - CBOR‑encodes the atomic params
[ [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).
- Enforces
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:- Builds a base receipt from
Tx+MessageReceipt. - Copies
AuthorizationListif present on the tx. - Defaults
Statusoff the FilecoinExitCode(1 on success, 0 otherwise). - Override for 0x04:
- If
tx.Type == 0x04and the Filecoin return payload is non‑empty,decodeApplyAndCallReturnStatusparses[status(uint), output_data(bytes)]and setsStatus = (status != 0). - This reflects the embedded outer call result from EthAccount, not the actor’s own exit code (which is always OK).
- If
- Builds a base receipt from
-
Delegation attribution (
adjustReceiptForDelegation)- Called from both
EthGetTransactionReceiptandEthGetBlockReceipts*
– seenode/impl/eth/transaction.go:345. - Behavior:
- If
AuthorizationListis non‑empty,DelegatedTois populated from the tuple addresses. - If
DelegatedTois still empty, it scans receipt logs for topickeccak256("Delegated(address)")and:- For each matching log, treats
dataas a 32‑byte ABI word and copies the last 20 bytes into anEthAddress, appending toDelegatedTo.
- For each matching log, treats
- This lets Lotus reconstruct
delegatedToeither from tuples or from the synthetic event emitted byref-fvm.
- If
- Called from both
-
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
- Behavioral overhead only (
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.- Importantly, consensus gas accounting in FVM is unchanged; this is purely an estimation UX feature.
5.4 E2E Tests
itests/eth_7702_e2e_test.go(build tageip7702_enabled)TestEth7702_SendRoutesToEthAccount:- Constructs and signs a 0x04 tx with a non‑empty
authorizationList. - Sends via
eth_sendRawTransaction. - Asserts that the resulting Filecoin message in the mpool targets
EthAccount.ApplyAndCallfrom the recovered f4 sender.
- Constructs and signs a 0x04 tx with a non‑empty
TestEth7702_ReceiptFields:- Mines a 0x04 tx and checks that the JSON‑RPC receipt exposes
authorizationListanddelegatedTo.
- Mines a 0x04 tx and checks that the JSON‑RPC receipt exposes
6. Security, Spec Compliance, and Edge Cases
-
Atomicity and persistence
- EthAccount:
- Applies delegation mapping and bumps
auth_nonceinside a transaction before the outer call. - Always exits OK, with
statusembedded in return. - As a result, delegation mapping + nonce bumps always persist, even if the outer call fails or reverts.
- Applies delegation mapping and bumps
ref-fvm:- Storage overlay (
evm_storage_root) persists only on successful delegated CALLs; it is discarded on revert or transfer short‑circuit.
- Storage overlay (
- EthAccount:
-
Pre‑existence policy
- Authorities cannot be EVM contracts:
- EthAccount rejects tuples whose recovered authority resolves to a builtin EVM actor.
- This aligns with “code must be empty/pointer” semantics.
- Authorities cannot be EVM contracts:
-
Tuple cap and duplicates
- Message‑level tuple cap
≤ 64enforced in EthAccount. - Duplicate authorities within
authorizationListare rejected.
- Message‑level tuple cap
-
Signature robustness
- Lotus uses minimally encoded big‑endian
r/s. - EthAccount accepts
1..31and32byter/sand left‑pads to 32 bytes; rejects> 32. - Low‑s enforced after padding; zero
r/srejected. - Tests in
apply_and_call_rs_padding.rslock in the positive/negative cases.
- Lotus uses minimally encoded big‑endian
-
Depth,
SELFDESTRUCT, and reverts- Delegation chains are not followed beyond depth 1; VM intercept is disabled for nested authority context.
SELFDESTRUCTis a no‑op in authority context (no balance move, no tombstone).- Revert mapping:
- Non‑success exit codes and revert data from the delegate trampoline are propagated back to the EVM caller;
RETURNDATASIZE/RETURNDATACOPYsee the delegate’s revert payload, subject to the minimal‑feature caveat in tests.
- Non‑success exit codes and revert data from the delegate trampoline are propagated back to the EVM caller;
-
Pointer semantics
- For an authority
Adelegated toB:EXTCODESIZE(A) == 23.EXTCODECOPY(A, 0, 0, 23)→0xEF 0x01 0x00 || B(20).EXTCODEHASH(A) == keccak(pointer_code).
- All verified in
evm_extcode_projection.rs.
- For an authority
7. How to Review (Per Repo)
-
builtin‑actors (
../builtin-actors)- Focus on:
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.- EthAccount test suite in
actors/ethaccount/tests/*.
- Validate:
- Tuple validation matches Lotus’
AuthorizationKeccakencoding and RLP rules. - Mapping + nonce behavior (including persistence on outer call failure).
- Pre‑existence policy (authorities are not EVM contracts).
- Outer call routing correctly differentiates EVM vs non‑EVM targets.
- Tuple validation matches Lotus’
- Focus on:
-
ref-fvm(../ref-fvm)- Focus on:
- Delegated CALL intercept and overlay persistence in
fvm/src/call_manager/default.rs:560. keccak32and FRC‑42 helpers and their tests in the same file.- Syscall and SDK plumbing for
get_eth_delegate_to:fvm/src/syscalls/actor.rs:182.sdk/src/sys/actor.rsandsdk/src/actor.rs:180.
- E2E tests for delegation, EXTCODE*, depth,
SELFDESTRUCT, and events infvm/tests/*.rs.
- Delegated CALL intercept and overlay persistence in
- Validate:
- Intercept gating is correct (only
InvokeEVMto EthAccount with activedelegate_to). - Value transfer semantics and short‑circuit behavior.
- Storage overlay is mounted and persisted only on success.
- Event topic and ABI word match the Lotus receipt adjuster.
- Intercept gating is correct (only
- Focus on:
-
Lotus (
./lotus)- Focus on:
- 0x04 parsing and CBOR encoding in
chain/types/ethtypes/eth_7702_transactions.go:121. - Magic constants and
AuthorizationKeccakinchain/types/ethtypes/eth_7702_magic.go. - Receipt status override and
AuthorizationListcopying innode/impl/eth/utils.go:450. adjustReceiptForDelegationand wiring innode/impl/eth/receipt_7702_scaffold.go:19andnode/impl/eth/transaction.go:345.- Gas estimation scaffolding in
node/impl/eth/gas_7702_scaffold.go. - E2E tests in
itests/eth_7702_e2e_test.go.
- 0x04 parsing and CBOR encoding in
- Validate:
TxHash/AuthorizationKeccakparity with EthAccount’s internal recovery logic.EthTx/EthTxReceiptJSON surfaces match expectations (tooling should seeauthorizationListanddelegatedTo).- Receipt status mapping correctly reflects
ApplyAndCallReturn.status. - Gas estimation only depends on tuple count and does not bake in consensus constants.
- Focus on:
8. How to Run the Relevant Tests
-
ref-fvm+ builtin‑actors- Recommended:
../ref-fvm/scripts/run_eip7702_tests.sh(Docker bundle +cargo test -p fvm).
- Recommended:
-
builtin‑actors (local)
make checkcargo test -p fil_actor_evmcargo test -p fil_actor_ethaccount
-
Lotus
- Unit / parser tests:
go test ./chain/types/ethtypes -run 7702 -count=1go test ./node/impl/eth -run 7702 -count=1
- E2E (requires updated wasm bundle and
eip7702_enabledtag):go test ./itests -run Eth7702 -tags eip7702_enabled -count=1
- Unit / parser tests:
This 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).
Codecov Report
:x: Patch coverage is 30.20528% with 238 lines in your changes missing coverage. Please review.
:white_check_mark: Project coverage is 76.65%. Comparing base (8a9321f) to head (d13136b).
:warning: Report is 2 commits behind head on master.
Additional details and impacted files
@@ Coverage Diff @@
## master #2227 +/- ##
==========================================
- Coverage 77.58% 76.65% -0.94%
==========================================
Files 147 147
Lines 15789 16130 +341
==========================================
+ Hits 12250 12364 +114
- Misses 3539 3766 +227
| Files with missing lines | Coverage Δ | |
|---|---|---|
| fvm/src/syscalls/mod.rs | 97.15% <100.00%> (+0.01%) |
:arrow_up: |
| fvm/src/kernel/default.rs | 82.47% <94.11%> (+0.24%) |
:arrow_up: |
| sdk/src/actor.rs | 20.66% <71.42%> (+20.66%) |
:arrow_up: |
| fvm/src/syscalls/actor.rs | 79.47% <0.00%> (-11.44%) |
:arrow_down: |
| fvm/src/call_manager/default.rs | 71.42% <22.67%> (-18.63%) |
:arrow_down: |
:rocket: New features to boost your workflow:
- :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
@copilot open a new pull request to apply changes based on the comments in this thread
@copilot open a new pull request to apply changes based on the comments in this thread
@snissn : it doesn't look like @copilot will do the work because it's a "cross-repository" change. Here is the error/warning I see: