feat(evm-simulation): capture internal native ETH via traceTransfers on eth_simulateV1#803
Merged
Conversation
…on eth_simulateV1 Enable `traceTransfers` on the `eth_simulateV1` backend so the node synthesizes native-ETH moves (top-level value *and* ETH moved through internal calls, e.g. a `WETH.withdraw` refund) as `Transfer` logs from the native sentinel. `parseTransfers` normalizes that sentinel to viem's `ethAddress`, and `assetChanges` now derives native ETH entirely from these logs instead of top-level transaction `value` — closing the coverage gap where the eth_simulateV1 path missed internally-moved ETH (Tenderly already reported it) while avoiding double-counting the top-level value. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Foulks-Plb
added a commit
that referenced
this pull request
Jun 17, 2026
Apply PR #795 review resolutions: allowlist (GeneralAdapter1 + Permit2) instead of trust-list with dispatcher; spender-only signature check (amount/expiration out of model); per-asset conformance instead of cross-asset net value; standard ERC-20 only; EIP-7702 out of scope; native-ETH gap closed via #803; inflation-attack robustness likely out of scope. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
Author
|
@codex review |
|
Codex Review: Didn't find any major issues. Swish! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Rubilmax
previously approved these changes
Jun 24, 2026
The merge of main into albuquerque-v1 left a stale vitest resolution in pnpm-lock.yaml, breaking `pnpm install --frozen-lockfile` (no entry for vitest@4.1.8...). Re-aligned the entry with main's resolved versions (vitest@4.1.9, @types/node@26.0.1, vite@8.1.0). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s not overflow The sender ETH balance state override was pinned at maxUint256 on both the eth_simulateV1 and Tenderly backends. When a simulated call paid native ETH back to the sender (e.g. a WETH.withdraw refund), the recipient balance overflowed uint256 and the EVM reverted the value transfer — surfacing as a SimulationRevertedError. This is exactly the internal-refund case the traceTransfers work added a fork test for. Use maxUint256 / 2n instead: still astronomically larger than the total ETH supply (so it still dodges false insufficient-gas reverts) while leaving room for any realistic inbound native ETH. Updates both backends and their unit tests; folds the note into the existing eth-simulate-trace-transfers changeset. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rubilmax
approved these changes
Jun 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Enable
traceTransferson theeth_simulateV1simulation backend so native-ETH moves are captured inassetChanges— including ETH moved through internal calls (e.g. aWETH.withdrawrefund, a swap that pays out ETH), which previously emitted no log and was invisible on this path.Why
The
eth_simulateV1backend derived native ETH only from each transaction's top-levelvalue. ETH moved internally was silently dropped, soassetChangeswas less complete than the Tenderly backend (the old JSDoc spelled this out as a known caveat: "For full native-ETH accounting use Tenderly"). This closes that gap — both backends now report the full net native-ETH delta.How
eth-simulate-v1.ts— passtraceTransfers: truetosimulateCalls. The node then synthesizes every native-ETH move (top-level and internal) as aTransferevent emitted from the native sentinel.assetChangesis now derived entirely from parsed transfer logs; the top-levelvalueaccounting is removed becausetraceTransfersalready logs it and keeping both would double-count.parsing/transfers.ts— newnormalizeTransferTokenhelper collapses the native sentinel (0xeee…eee, lowercase) to viem'sethAddressconstant rather than its checksummed form, so native deltas key consistently across backends (groupAssetChangeskeys tokens by exact string). Real ERC20 tokens stay checksummed. Tenderly emits no such logs, so the path is inert there.Validation
Verified empirically against a local anvil 1.7.1 devnet that
eth_simulateV1+traceTransfersemits native moves asTransferlogs at the0xeee…sentinel (= viem'sethAddress), confirming the address-normalization choice. Anvil is what the fork suite runs against.traceTransfersflag is set; native ETH accounted from synthetic logs; no double-count when a tx hasvaluebut no native log; parser normalizes the sentinel toethAddress.WETH.withdrawnets sender −1 WETH / +1 ETH — the internal refund the old path missed.tsc --noEmit, Biome, and the fullevm-simulationunit suite (226 tests) pass.🤖 Generated with Claude Code