Skip to content

feat: EIP-7708 — synthetic ETH transfer/burn logs (Amsterdam)#13

Merged
garyschulte merged 4 commits intoConsensys:mainfrom
Gabriel-Trintinalia:eip-7708
Apr 1, 2026
Merged

feat: EIP-7708 — synthetic ETH transfer/burn logs (Amsterdam)#13
garyschulte merged 4 commits intoConsensys:mainfrom
Gabriel-Trintinalia:eip-7708

Conversation

@Gabriel-Trintinalia
Copy link
Copy Markdown

@Gabriel-Trintinalia Gabriel-Trintinalia commented Mar 20, 2026

Summary

Implements EIP-7708 for the Amsterdam hardfork.

Emits synthetic Transfer and Burn logs from the reserved address 0xff..fffffffffffffffe on all ETH movements, making ETH flows visible in the log stream without requiring ERC-20 wrapping.

Log types

  • Transfer(address indexed from, address indexed to, uint256 amount) — emitted for every ETH transfer (CALL, CREATE, TX value, SELFDESTRUCT to different address)
  • Burn(address indexed addr, uint256 amount) — emitted when ETH is destroyed (SELFDESTRUCT to self on a same-tx-created account or pre-Cancun)

Burn log emission — two-phase approach

Per the EELS reference (amsterdam/vm/instructions/system.py + fork.py):

  1. Opcode time: when SELFDESTRUCT executes, a Burn log is emitted immediately for the balance held at that moment.
  2. Finalization time: after coinbase priority-fee payment (postExecution), for every account in accounts_to_delete, the current evm_state balance is re-read. If non-zero (ETH arrived after the opcode — payer call or coinbase tip), a second Burn log is emitted.

This produces two separate Burn log entries for the same address when applicable, exactly matching the EELS spec.

Burn logs from the finalization pass are emitted in ascending address order, matching EELS.

Changes

  • src/primitives/main.zigEIP7708_LOG_ADDRESS, EIP7708_TRANSFER_TOPIC, EIP7708_BURN_TOPIC constants
  • src/context/journal.zigPendingBurn struct, pending_burns list on JournalInner, helper methods (addEip7708TransferLog, addEip7708BurnLog, addPendingBurn, emitBurnLogs), checkpoint/revert support, SELFDESTRUCT log emission
  • src/interpreter/host.zig — Transfer log emission on precompile calls, regular CALLs, and CREATE
  • src/handler/mainnet_builder.zig — Transfer log for TX-level value transfer; emitBurnLogs() call in postExecution

Part of Amsterdam hardfork

Related PRs: EIP-7843 (SLOTNUM), EIP-8024 (DUPN/SWAPN/EXCHANGE), EIP-7954 (max code size), EIP-8037 (state gas reservoir)


Note

Medium Risk
Changes EVM execution semantics around log emission for ETH movements (CALL/CREATE/TX value and SELFDESTRUCT) and adds a deferred finalization pass, so incorrect ordering/checkpointing could break spec compliance or log expectations.

Overview
Implements EIP-7708 synthetic ETH flow logs for Amsterdam by emitting Transfer logs on all value movements (tx value transfer, CALL/precompile calls, and CREATE) and Burn logs for qualifying SELFDESTRUCT cases.

Adds a deferred-burn mechanism in the journal (pending_burns with checkpoint/revert support) and a postExecution finalization step to sort addresses and emit any additional Burn logs after coinbase payment.

Also centralizes blob base fee update fraction resolution via CfgEnv.blobBaseFeeUpdateFraction() in the spec test runner and updates a create-path error return to CreateResult.failure().

Written by Cursor Bugbot for commit e1c0f99. This will update automatically on new commits. Configure here.

Copy link
Copy Markdown
Collaborator

@garyschulte garyschulte left a comment

Choose a reason for hiding this comment

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

LGTM, but cursor bot is on top of the topic error and burn log emission issue

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Gabriel-Trintinalia and others added 4 commits April 1, 2026 05:40
Emits Transfer and Burn logs from address 0xff..fe on all ETH movements
for Amsterdam+. Transfer logs are emitted immediately on CALL/CREATE
value transfers and SELFDESTRUCT-to-different-address. Burn logs are
emitted immediately for SELFDESTRUCT-to-self (same-tx-created or
pre-Cancun). Pending burns are checkpointed and reverted with call
frames.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The previous implementation had two bugs:

1. `addPendingBurn()` was never called — `pending_burns` was always empty,
   so `emitBurnLogs()` in postExecution was a no-op.  The only burn logs
   emitted were at SELFDESTRUCT opcode time via `addEip7708BurnLog` directly,
   missing any ETH that arrived at the selfdestructed address afterwards.

2. Accounts that SELFDESTRUCT to a *different* beneficiary (and are therefore
   in `accounts_to_delete`) were never registered for the finalization burn
   check, even though they can receive ETH after the opcode returns.

Per the EELS reference (amsterdam/vm/instructions/system.py and fork.py):

- At opcode time: emit a Burn log for the balance held *now* (self-to-self),
  or a Transfer log for the ETH moved to a different beneficiary.
- At finalization (after coinbase priority-fee payment): for every account in
  `accounts_to_delete`, re-read its current `evm_state` balance and emit a
  *second* Burn log if non-zero.  This captures ETH that arrives post-opcode:
  payer contracts calling into the destructed address, or the coinbase contract
  receiving its miner tip.

This produces the two separate Burn log entries that the spec tests expect for
cases like `test_selfdestruct_finalization_after_priority_fee` (coinbase SD +
priority fee) and `test_finalization_burn_logs` (post-SD payer funding).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The last 8 bytes of EIP7708_BURN_TOPIC were 717fce85f713ab57 instead of
71a0fdb75d397ca5.

keccak256("Burn(address,uint256)")
= 0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5

All Burn logs emitted with the wrong constant would be unrecognizable by
any conforming indexer or client.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: garyschulte <garyschulte@gmail.com>
Copy link
Copy Markdown
Collaborator

@garyschulte garyschulte left a comment

Choose a reason for hiding this comment

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

🚢

@garyschulte garyschulte merged commit 2e0ff16 into Consensys:main Apr 1, 2026
6 checks passed
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.

2 participants