Repository navigation
implement EIP-7708 transfer and burn system logs (amsterdam) #2767
Description
Summary
EIP-7708 emits system logs when value moves: an ETH transfer log is produced for the moved balance, and with EIP-8246 removing the SELFDESTRUCT burn there is no burn log left to emit.
Why it is not implemented here
grep -rn 'EthTransferLog' --include='*.go'returns nothing:core/types/log.gohas no such constructor.core/vm/instructions.gohas no Amsterdam branch that emits a log on the self-destruct transfer path.
Upstream reference
go-ethereum master 7c5069001, checked 2026-10-21.
core/types/log.go:68(EthTransferLog).core/vm/instructions.go:962-965(if evm.chainRules.IsAmsterdam && !balance.IsZero() && this != beneficiaryemits the transfer log).params/protocol_params.go:278(the EIP-7708 constant block).internal/ethapi/simulate.go:381-383(geth internal/ethapi: avoid duplicate transfer logs in eth_simulateV1 post-Amsterdam ethereum/go-ethereum#35617): post-Amsterdam the protocol emits the transfer log, so the synthetic one is suppressed withtraceTransfers = sim.traceTransfers && !sim.chainConfig.IsAmsterdam(...).
The synthetic transfer log has to land in the same PR
eth_simulateV1 synthesizes its own transfer logs, and once the protocol emits them as well every transfer is reported twice. Upstream fixed that separately in ethereum#35617 only because of timing (EIP-7708 landed in March, the simulation fix in October); here the two belong in one PR, because a tree that has EIP-7708 without the suppression reports every transfer twice and has no use of its own.
- Here:
internal/ethapi/logtracer.go:130-140builds the same ERC-20-shaped log (transferAddress+transferTopic,from/totopics and a 32-byte amount), gated only ontraceTransfers(:131). - The flag reaches the tracer from
internal/ethapi/simulate.go:199andinternal/ethapi/api.go:1257. internal/ethapihas noIsAmsterdamreference at all today, so there is no existing fork gate to hang the suppression on; the simulator has to read the fork from its chain config, as upstream does.
Upstream PRs
EIP-7708 landed in two shapes: the first implementation carried transfer logs and burn logs, and EIP-8246 deleted the burn-log half three months later. Port the current shape (transfer log only) and do not copy the burn-log machinery.
| Role | PR | What it does |
|---|---|---|
| Prerequisite | none | ethereum#33645 introduces everything it needs itself: types.EthTransferLog, the rules parameter on core.Transfer, and the vm.StateDB log accessor. It only relies on params.SystemAddress, which Prague already has. |
| Main | ethereum#33645 (2026-03-23) | The implementation: transfer logs and burn logs (EmitLogsForBurnAccounts). |
| Follow-up | ethereum#34688 (2026-04-09) | Changes the burn-log hook shape: EmitLogsForBurnAccounts() becomes LogsForBurnAccounts(), returning the logs for the caller to emit. |
| Follow-up, supersedes | ethereum#35219 (2026-06-30, EIP-8246) | Deletes the burn-log half: EthBurnLog, LogsForBurnAccounts and the vm.StateDB method are removed, leaving the EIP with the transfer log only. This is the shape to port. |
| Follow-up | ethereum#35364 (2026-07-21) | Adds core/eip7708_test.go (413 lines), the behaviour reference for this port. |
| Follow-up | ethereum#35617 (2026-10-07) | Suppresses the synthetic transfer log in eth_simulateV1, which otherwise reports every transfer twice. In scope here, see above. |
| Adjacent | ethereum#35668 (2026-10-07) | Simulated headers carry slotNumber (EIP-7843, #2760) and the coinbase tip is zeroed so that it enters the BAL (EIP-7928, #2761). Not this EIP. |
Two consequences for this port:
- Do not port the burn-log machinery. It existed in core, core/vm: implement EIP-7708 ethereum/go-ethereum#33645 and was reshaped by core/state: fix tracer hook for EIP-7708 burn logs ethereum/go-ethereum#34688, then deleted by core: implement EIP-8246 ethereum/go-ethereum#35219. Here EIP-8246 (feat(core/vm,core/state): EIP-8246 selfdestruct burn removal #35219, close #2766 #2834) removes the burn in the same fork, so a transfer-only log is both the upstream shape and the self-consistent one.
- The self-destruct transfer log mirrors EIP-8246's condition:
IsAmsterdam && !balance.IsZero() && this != beneficiary, in the block feat(core/vm,core/state): EIP-8246 selfdestruct burn removal #35219, close #2766 #2834 rewrote.
Scope
core/types (log shape), core/vm (transfer and self-destruct paths), core/state if the log has to be emitted from the state layer, and the RPC/filter surface because logs become part of block receipts. internal/ethapi is in scope as well: the synthetic transfer log has to be suppressed post-Amsterdam, or eth_simulateV1 reports every transfer twice.
Applicability
The log ABI (sender, recipient, amount, system flag) has to be confirmed for XDC, since these logs land in receipts and are consumed by indexers. EIP-8246 changes the same code path and should be decided with it.
Split out of #2730, the Amsterdam umbrella - this EIP is not mentioned there. Sibling per-EIP issues for the other unimplemented Amsterdam EIPs exist alongside this one.
Activity
feat(core,core/vm): implement EIP-7708 ETH transfer logs ethereum#33645
feat(core,core/vm,params): implement EIP-7708 ETH transfer logs ether…
feat(core,core/vm,params): implement EIP-7708 ETH transfer logs ether…
feat(core,core/vm,params): implement EIP-7708 ETH transfer logs ether…
feat(core,core/vm,params): implement EIP-7708 ETH transfer logs ether…
feat(core,core/vm,params): implement EIP-7708 ETH transfer logs ether…
feat(core,core/vm,params): implement EIP-7708 ETH transfer logs ether…
feat(core,core/vm,core/types,params): implement EIP-7708 ETH transfer…
feat(core,core/vm,core/types,params): implement EIP-7708 ETH transfer…
feat(core,core/vm,core/types,params,internal/ethapi): implement EIP-7…
gzliudan commentedon Oct 28, 2026
Implemented by #2842, merged into
dev-upgradeasc9d32fe183.types.EthTransferLogandparams.EthTransferLogEventare added,core/vm/instructions.go:948-949emits the log on the Amsterdam transfer path, andeth_simulateV1suppresses its synthetic transfer log once Amsterdam is active (internal/ethapi/simulate.go:203), so transfers are not reported twice. Coverage is incore/eip7708_transfer_logs_test.go; the burn-log half is intentionally not ported, as this issue asks. Closing manually: #2842 targetsdev-upgrade, not the default branch, so itsCloses #2767keyword did not take effect.[-]core/types,core/vm: implement EIP-7708 transfer and burn system logs (amsterdam)[/-][+]implement EIP-7708 transfer and burn system logs (amsterdam)[/+]