FORENSIAWeb3 forensicsOpen workspace

Reading a direct ETH to WETH wrap or unwrap

Forensia explains one narrow kind of transaction in plain words: a direct wrap or unwrap at the Ethereum WETH contract. It is not a swap interpreter, and it does not replay execution.

· Forensia · 7 min read · Transactions

A lot of Ethereum transactions do something very ordinary that looks strange on the page. Someone sends ETH to a contract and gets nothing visible back, or calls a contract with zero value and ETH appears. Very often this is wrapping: turning ETH into WETH, a token that stands for the same ETH, or turning it back.

Forensia now says so in one sentence when it can support the sentence from the records. On a matching transaction, Overview shows a short explanation such as "ETH wrapping recorded" with the exact amount, and a disclosure that lists what the explanation rests on.

This is deliberately narrow. It covers a direct call to the WETH contract on Ethereum mainnet and nothing else. Router calls, swaps, other networks and other wrapped-token contracts are not interpreted. If the transaction is outside that scope, no explanation is shown and the ordinary records stay as they are.

#Plain languageWrapping is a change of form, not a trade

Think of a coat check. You hand over a coat and receive a ticket. The ticket is not a new coat and nobody sold you anything. Later you hand the ticket back and get the coat. Wrapping works the same way: ETH goes into the WETH contract and the same amount of WETH is credited. Unwrapping is the return trip.

That matters for an investigation because a wrap is easy to misread as a payment to a contract, or as a market swap with a price. It is neither. Forensia labels it as a wrap or an unwrap, shows the amount on both sides as equal, and says in the text that it is not a market swap.

The explanation is only shown when two separate records agree: what the sender asked for, and what the contract reported in its receipt. If they disagree, or if anything about the transaction is ambiguous, the workspace stays silent instead of guessing.

#How it worksWhere the explanation appears and what to open

  1. Look up an Ethereum transaction hash. The explanation only applies to transaction lookups, not wallet lookups.
  2. On Overview, below the main summary, look for a block titled "ETH wrapping recorded" or "WETH unwrapping recorded". It shows the exact amount on both sides, ETH to WETH or WETH to ETH.
  3. Open "How this explanation is supported". It lists the Ethereum contract, the Explanation version, the Account in receipt event, the Receipt log index (zero-based) and the Exact amount in raw units with 18 decimal places.
  4. Use the three buttons, Transaction source, Receipt source and Block source, to open the exact saved response each claim came from.
  5. Read the code section below those buttons. It says whether recorded contract code matches a pinned WETH reference, and at which moment. Open "Code reference and sources" for the exact hashes.

A review example from the local review guide is the unwrap transaction 0x0de474225252d8358663646b01084bb0c5f25f5408a53b01b00bbc3b9f974a20. A fresh lookup of any example can differ from an earlier one, because providers do not always return the same optional records.

#Technical detailWhat the interpreter checks before it speaks

The interpreter is versioned. Fresh lookups use ethereum-weth9-direct.v2. The earlier ethereum-weth9-direct.v1 is kept only so that older saved results read the same as when they were captured. A saved v1 explanation is never upgraded in place, and the disclosure says which version produced it.

The three source records

Every explanation is bound to three distinct captured JSON-RPC records: eth_getTransactionByHash, eth_getTransactionReceipt and eth_getBlockByNumber (called with the block number and false, so the block lists transaction hashes only). The three record IDs must be different, each must resolve to exactly one captured record, and each stored request must match its method and parameters.

Request and event correspondence

CheckWrapUnwrap
Network and targetChain ID 1, transaction to 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2Same
CalldataEmpty (0x) or exactly the selector 0xd0e30db0Selector 0x2e1a7d4d followed by one 32-byte amount
Amount taken fromThe transaction value fieldThe 32-byte calldata argument
Transaction valueEquals the amountMust be zero
Receipt eventExactly one Deposit(address,uint256) log from the WETH addressExactly one Withdrawal(address,uint256) log from the WETH address
Event accountTopic 1 is the transaction sender, left-padded to 32 bytesSame
Event amount32-byte data word equals the amountSame

The transaction hash, block hash and block number in the transaction must equal the captured receipt context. The receipt must report success and its logs must agree with that context. The event must have exactly two topics. A second Deposit or Withdrawal log from WETH anywhere in the receipt makes the account ambiguous and the interpreter returns nothing. A receipt with more than 256 logs is not interpreted. Amounts are handled as exact integers, so values above 2^53 are not rounded.

The v2 applicability gate

Recognizing calldata is not enough for v2. The transaction and the receipt must each carry an explicit type from 0 to 4, and the two must be equal (the typed-envelope model of EIP-2718). The block must resolve against a pinned Ethereum mainnet activation reference, forensia.ethereum-mainnet-schedule.v1, which checks the block number, timestamp and difficulty against the recorded fork boundaries and refuses a transaction format that appears before its activation. Blocks at or after the reference’s review horizon (7 October 2026, 00:00 UTC) are treated as unknown, not assumed. Finally the explanation must cite the same three source IDs as the captured execution context.

Following EIP-7702, authorization processing is treated as separate from execution, so a type 4 transaction passing this gate says nothing about its authorization list. The gate applies to this interpreter only.

Consistency with the captured root call

When the result is displayed or imported, the workspace checks again that there is exactly one root transaction step, that it succeeded, that its destination is the WETH address, its sender is the account in the event, its selector matches the stored calldata and its value matches the amount (or zero for an unwrap). Any mismatch removes the explanation.

The code reference comparison

The pinned reference is a 3,124-byte runtime with Keccak-256 0xd0a06b12ac47863b5c7be4185c2deaad1c61557033f56c7d4ea74429cbb25e23, reviewed against the public Sourcify record. Forensia compares it with whatever code observations the capture holds for the WETH address at up to three moments: Transaction start, Transaction end and Containing-block end. An observation matches only if it is ordinary bytecode with the same length and hash. Explicitly empty code and delegation pointers never count as a match.

StatusShown asMeaning
entry-matchStart-of-transaction code matches the WETH referenceAll available observations match, including Transaction start
later-matchOnly later code could be comparedMatches exist, but none at Transaction start
differentRecorded code differs from the WETH referenceAt least one observation does not match; this takes priority over any matches
unavailableContract code could not be comparedNo usable observation was captured

The comparison is derived each time from the saved observations. No verdict is stored in the capture, and opening the disclosure makes no request. The Sourcify link opens only when you click it.

Rechecking a saved result

Under Sources, Capture integrity & local evidence, the Check local evidence action re-reads the three saved response bodies in your browser and reinterprets them. It reports matched only when all three are present and agree on account, amount, input, event position, successful receipt, block identity and a single occurrence of the transaction in the block at the recorded index. Limits in the code: 8 MiB per body, 256 receipt logs and 100,000 block transactions. A contradiction in any available body wins over a missing body. A missing body is reported as unavailable and is never fetched again or reconstructed.

#LimitsWhat a wrapping explanation does not establish

  • It is request and receipt correspondence. It is not an execution replay, and Forensia does not run the EVM independently.
  • It does not prove final balances. The explanation says the request and the event carry the same amount, not that an account ended up holding it.
  • It does not cover routers, aggregators, swaps, WETH on other networks or other wrapped-token deployments. A wrap that happens inside a larger contract call is not labelled.
  • The code comparison is provider-reported code at recorded boundaries. It does not prove which bytes an individual call executed, or that code was unchanged between boundaries.
  • The pinned reference is a reviewed public record whose recompiled runtime differs in compiler metadata. It is not an exact full-bytecode source rebuild or an audit.
  • The format and fork gate does not verify signatures, authorization effects or finality.
  • A "different" code result is not evidence of malicious activity on its own. It means the request and receipt explanation should not be treated as checked contract execution.
  • The local check confirms consistency with saved provider responses. It is not a receipt-trie proof or independent consensus verification.
  • No owner is identified. The account in the event is an address.