fix: WETH paid to the user before an UNWRAP_WETH reads as WETH (closes #607)
check / check (push) Canceled after 0s
e2e / e2e-chrome (push) Canceled after 0s
e2e / e2e-firefox (push) Canceled after 0s

An UNWRAP_WETH made Token Out ETH whenever the output side was WETH,
though the router unwraps only the WETH it holds. decode() now records
where the step that set the output side paid its output, and an
UNWRAP_WETH makes the output ETH only when that step paid WETH to the
router and the router still holds WETH. When that step paid only part
of its WETH to the router, or made a payout the decoder cannot read,
the output reads ETH with no minimum: the decoder does not count how
much of that step's minimum reaches the router, nor read the
UNWRAP_WETH's own minimum. A BALANCE_CHECK_ERC20 pays nobody, so it is
never read as unwrapped. README Display Consistency says the same.

Model: opus-5-5
This commit was merged in pull request #640.
This commit is contained in:
2026-10-20 16:09:45 +02:00
parent 7b9821b06f
commit 4109c4d44a
4 changed files with 261 additions and 30 deletions
+18 -8
View File
@@ -1253,14 +1253,24 @@ Decoding). So a step whose USDT-for-USDC swap action could not be read, with a
A V4 step with no swap action sets only the sides its `SETTLE`, `SETTLE_ALL`,
`TAKE` or `TAKE_ALL` names.
An `UNWRAP_WETH` step makes `Token Out` ETH only when the output side is WETH,
on mainnet or Sepolia, or when no step set the output side; a WETH
`Min. received` figure then reads in ETH. Otherwise `Token Out` and
`Min. received` keep the output side's own token and figure, whether the swap
was paid in ETH or in a token: a V2 exact-out swap that buys USDC and then
unwraps the WETH it did not spend shows USDC. The token permission warning on
the signature screen has its own amount wording, including `Unknown`; the
SignApproval section below describes it.
An `UNWRAP_WETH` step makes `Token Out` ETH only when no step set the output
side, or when the output side is WETH, on mainnet or Sepolia, that the step that
set it paid to the router and that the router still holds when the `UNWRAP_WETH`
runs (Transaction Decoding below gives what the router holds). The router
unwraps only the WETH it holds, so WETH that step paid to the user, or to anyone
else, stays WETH: a swap that pays the router WETH, then a swap that pays the
user WETH, then an unwrap, shows WETH with the second swap's minimum. The
minimum reads in ETH when that step paid all its WETH to the router. When it
paid only part of it to the router, as a V4 step does that `TAKE`s some of its
WETH to the user and the rest to the router, or paid the router WETH beside a
payout the decoder cannot read, the swap shows ETH with no minimum: the decoder
does not count how much of that step's minimum reaches the router, nor read the
`UNWRAP_WETH`'s own minimum. A later step that sets the output side sets it
anew. Otherwise `Token Out` and `Min. received` keep the output side's own token
and figure, whether the swap was paid in ETH or in a token: a V2 exact-out swap
that buys USDC and then unwraps the WETH it did not spend shows USDC. The token
permission warning on the signature screen has its own amount wording, including
`Unknown`; the SignApproval section below describes it.
The swap's `Deadline` line is the router's deadline as a UTC date and time, e.g.
`2026-02-27 08:25:51`. A JavaScript date reaches only to 275760-09-13 00:00:00