Skip to content

feat(core,core/vm,core/types,params,internal/ethapi): implement EIP-7708 ETH transfer logs, close #2767 - #2842

Merged
gzliudan merged 2 commits into
XinFinOrg:dev-upgradefrom
gzliudan:eip-7708-transfer-logs
Oct 27, 2026
Merged

gzliudan merged 2 commits into
XinFinOrg:dev-upgradefrom
gzliudan:eip-7708-transfer-logs

Conversation

@gzliudan

@gzliudan gzliudan commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Implements EIP-7708 system logs from Amsterdam onwards: every value move made by EVM execution emits a Transfer(address,address,uint256) log from params.SystemAddress (0xfffffffffffffffffffffffffffffffffffffffe), covering the transaction value, the value moved by CALL/CREATE, and the value moved by SELFDESTRUCT. Ported from go-ethereum ethereum#33645, including the self-transfer guard from upstream commit 012efa11ab.

eth_simulateV1 synthesizes its own transfer logs; post-Amsterdam that would report every transfer twice. The synthetic log is suppressed for Amsterdam blocks in the same PR (geth ethereum#35617).

Changes

  • params: EthTransferLogEvent.
  • core/types: EthTransferLog.
  • core.Transfer: emits for Amsterdam when the amount is non-zero and sender != recipient. The fork rules are passed from the VM, the only caller.
  • core/vm: TransferFunc carries *params.Rules; opSelfdestruct6780 emits for a distinct beneficiary.
  • internal/ethapi: traceTransfers is disabled for Amsterdam blocks in processBlock.

No burn log is emitted: EIP-8246 (go-ethereum ethereum#35219) removes the SELFDESTRUCT burn entirely and is already on the base branch as #2834, so a SELFDESTRUCT that names a distinct beneficiary is the only value move the instruction makes, and a self-destruct to self logs nothing in every fork. Amsterdam is not scheduled on any network (amsterdamBlock is nil on mainnet and testnet), so the window stays dormant until it is. Value moved outside EVM execution is out of scope too: XDCx and XDCxlending order matching settles native XDC at block level (miner/worker.go) with statedb.AddBalance/SubBalance (XDCx/tradingstate/relayer_state.go), never through core.Transfer, so those moves emit no transfer log - the same treatment the specification gives withdrawals and fees.

Log ABI

  • emitter: params.SystemAddress
  • topics: Transfer(address,address,uint256), from, to
  • data: 32-byte amount

These logs become part of Amsterdam block receipts, so indexers that consume receipts will see them next to user logs.

Verification

  • make all clean.
  • gofmt clean.
  • golangci-lint --new-from-rev=f5492a96a7: 0 issues.
  • go test ./core/... ./internal/ethapi/... ./params/... ./tests/... ./log/... passes.
  • Mutation checks: removing the Amsterdam gate fails TestEIP7708PreAmsterdam and TestEIP7708TransferForkGate, removing the self-transfer guard fails TestEIP7708SelfTransfer, removing the SELFDESTRUCT beneficiary guard fails TestEIP7708SelfdestructToSelf, breaking the transfer attribution fails TestEIP7708DelegateCallAttribution, and removing the simulate suppression fails TestSimulateV1TransferLogs/post-amsterdam.
  • Boundary matrix, mirroring upstream core/eip7708_test.go: DELEGATECALL and CALLCODE (no log), the delegated-call attribution (a transfer made by delegated code belongs to the executing context), a SELFDESTRUCT to self vs. a distinct beneficiary, an inner revert that keeps the caller's own log, an outer revert that discards every log, every transaction type (legacy, access list, dynamic fee, set code) plus a delegated EOA, CREATE and CREATE2 endowments (including a failed CREATE rolling its log back), precompile, system-address and coinbase recipients, the priority-fee exclusion, and a direct core.Transfer fork-gate case pinning the 32-byte amount (core/eip7708_transfer_logs_test.go).

Closes #2767

@coderabbitai

coderabbitai Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: a960a1da-00e2-4735-95c5-5cb182afdf4f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gzliudan
gzliudan force-pushed the eip-7708-transfer-logs branch 3 times, most recently from d34363a to b9ead49 Compare October 22, 2026 09:05
@gzliudan
gzliudan force-pushed the eip-7708-transfer-logs branch 2 times, most recently from 66d914e to 181c723 Compare October 26, 2026 05:32
@gzliudan
gzliudan force-pushed the eip-7708-transfer-logs branch 2 times, most recently from 1ba586e to 0fa4e14 Compare October 27, 2026 10:35
@gzliudan
gzliudan force-pushed the eip-7708-transfer-logs branch from 0fa4e14 to f58a9ec Compare October 27, 2026 11:11
@gzliudan gzliudan changed the title feat(core,core/vm): implement EIP-7708 ETH transfer logs, close #2767 feat(core,core/vm,core/types,params,internal/ethapi): implement EIP-7708 ETH transfer logs, close #2767 Oct 27, 2026
@gzliudan
gzliudan requested a balanced review from Copilot October 27, 2026 11:21

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Consensus-visible receipt changes require protocol-maintainer validation of log ordering, fork activation, and indexer compatibility.

No open issues 🎉

What changed in this PR

Implements Amsterdam-gated EIP-7708 native-value transfer logs in EVM execution and receipts, addressing #2767. It follows the transfer-only design compatible with EIP-8246’s removal of SELFDESTRUCT burns.

Changes:

  • Adds the system-log event and constructor, emitting logs for non-zero transfers between distinct addresses.
  • Suppresses synthetic transfer logs in eth_simulateV1 after Amsterdam to avoid duplicates.
  • Adds coverage for fork gating, transfer attribution, reverted execution, creation, SELFDESTRUCT, and simulation.
File Description
tests/​vm_test_util.go Updates the VM test transfer callback signature.
params/​protocol_params.go Defines the transfer event topic.
internal/​ethapi/​simulate.go Disables synthetic transfer logs after Amsterdam.
internal/​ethapi/​logtracer.go Documents synthetic and protocol log emitters.
internal/​ethapi/​api_test.go Tests simulation logs before and after Amsterdam.
core/​vm/​interpreter_test.go Updates the interpreter test transfer callback.
core/​vm/​instructions.go Emits Amsterdam SELFDESTRUCT transfer logs.
core/​vm/​gas_table_test.go Updates gas-test transfer callbacks.
core/​vm/​evm.go Passes fork rules into CALL and CREATE transfers.
core/​vm/​eip8246_test.go Updates the SELFDESTRUCT test transfer callback.
core/​vm/​contracts_kzg_stub_test.go Updates the precompile test transfer callback.
core/​types/​log.go Adds the EIP-7708 log constructor.
core/​state/​statedb_log_test.go Tests log rollback and index restoration.
core/​evm.go Emits fork-gated logs for value transfers.
core/​eip7708_transfer_logs_test.go Adds execution and receipt-log regression coverage.

Review effort: Balanced

… logs ethereum#33645

EIP-7708 emits a system log for every value transfer from Amsterdam onwards:
the transaction value, the value moved by a CALL or CREATE, and the value
moved by SELFDESTRUCT. The log uses params.SystemAddress as emitter and the
ERC-20 Transfer ABI (Transfer(address,address,uint256) plus a 32-byte amount),
so indexers can consume it like a token transfer.

The gate sits where the fork rules are available: core.Transfer takes the
vm's params.Rules and emits after the balance move, while opSelfdestruct6780
emits when the beneficiary differs. Zero-value transfers and transfers to self
emit nothing.

No burn log is emitted: EIP-8246 (go-ethereum ethereum#35219) removes the SELFDESTRUCT
burn entirely and landed before this change as XinFinOrg#2834, so a self-destruct that
names a different beneficiary is the only value move the instruction makes. A
self-destruct to self moves nothing and therefore logs nothing, in every fork.

Amsterdam is not scheduled on any network (amsterdamBlock is nil), so the
window stays dormant until it is.

The log constructor takes *big.Int rather than upstream's *uint256.Int because
this tree's StateDB moves balances as big.Int.

Tests cover the upstream CALL/SELFDESTRUCT scenario through block processing
(three transfer logs interleaved with the contract's events), the zero-value
and pre-Amsterdam cases, a transfer to self, an inner revert that keeps the
caller's own log, an outer revert that discards every log, the delegated-call
attribution, and the upstream boundary matrix: DELEGATECALL and CALLCODE (no
log), a CREATE2 endowment, a failed CREATE rolling its log back, precompile and
system-address recipients, the priority-fee exclusion, and a direct
core.Transfer fork-gate case pinning the 32-byte amount. core/state
additionally pins that a log is reverted with its snapshot.

Ref: ethereum#33645
Ref: ethereum#35617
Closes XinFinOrg#2767
…ethereum#35617

eth_simulateV1 synthesizes an ERC-7528 transfer log for every value move when
traceTransfers is set. From Amsterdam the protocol emits the EIP-7708 log for
the same transfer, so every transfer was reported twice.

Disable the synthetic log for Amsterdam blocks, mirroring upstream ethereum#35617. The
tracer still captures the protocol log through the OnLog hook, so traceTransfers
keeps reporting exactly one log per transfer.

The new test pins both sides of the fork: the synthetic ERC-7528 log before
Amsterdam and the single protocol log at params.SystemAddress after it.

The tracer comment now says that from Amsterdam onwards the protocol emits
these logs itself (EIP-7708) and the synthesis is off, so the documented format
only describes the synthesized pre-fork log while protocol logs carry
params.SystemAddress as their emitter. Upstream still carries the older comment
(zero address, no EIP-7708 note), so this is a local correction with no geth PR
to mirror.

Ref: ethereum#35617
@gzliudan
gzliudan force-pushed the eip-7708-transfer-logs branch from f58a9ec to 6909a09 Compare October 27, 2026 11:34
@gzliudan
gzliudan merged commit c9d32fe into XinFinOrg:dev-upgrade Oct 27, 2026
16 checks passed
@gzliudan
gzliudan deleted the eip-7708-transfer-logs branch October 27, 2026 11:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants