An UNWRAP_WETH made Token Out ETH whenever the output side was WETH. The router unwraps only the WETH it holds, so a swap that paid its WETH to the user before the UNWRAP_WETH read as ETH, though the user receives WETH.
decode() now records where the step that set the output side paid its output (outputRecipients). The UNWRAP_WETH branch 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 paid the router beside a payout the decoder cannot read, the output reads ETH with no minimum line: the decoder does not count how much of that step's minimum reaches the router, nor read the UNWRAP_WETH's own minimum.
Not visible in the diff:
An UNWRAP_WETH before the swap no longer makes the WETH the swap leaves in the router read as ETH; that route's existing test now expects WETH.
Two existing tests in tests/uniswap.test.js paid the swap's WETH to the user and expected ETH; they now pay the router.
A BALANCE_CHECK_ERC20 pays nobody, so an UNWRAP_WETH after one of WETH leaves the output WETH.
Judgement call: a step between the swap and the UNWRAP_WETH that pays out part of the router's WETH, such as a PAY_PORTION fee, still leaves the swap's minimum in ETH, as on next and as its existing test expects.
Judgement call: a swap paying WETH to the user after an UNWRAP_WETH of an earlier swap's WETH reads WETH; on next it read ETH.
Model: opus-5-5
Closes https://git.eeqj.de/sneak/AutistMask/issues/607.
An `UNWRAP_WETH` made `Token Out` ETH whenever the output side was WETH. The router unwraps only the WETH it holds, so a swap that paid its WETH to the user before the `UNWRAP_WETH` read as ETH, though the user receives WETH.
`decode()` now records where the step that set the output side paid its output (`outputRecipients`). The `UNWRAP_WETH` branch 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 paid the router beside a payout the decoder cannot read, the output reads ETH with no minimum line: the decoder does not count how much of that step's minimum reaches the router, nor read the `UNWRAP_WETH`'s own minimum.
Not visible in the diff:
- An `UNWRAP_WETH` before the swap no longer makes the WETH the swap leaves in the router read as ETH; that route's existing test now expects WETH.
- Two existing tests in `tests/uniswap.test.js` paid the swap's WETH to the user and expected ETH; they now pay the router.
- A `BALANCE_CHECK_ERC20` pays nobody, so an `UNWRAP_WETH` after one of WETH leaves the output WETH.
Judgement call: a step between the swap and the `UNWRAP_WETH` that pays out part of the router's WETH, such as a `PAY_PORTION` fee, still leaves the swap's minimum in ETH, as on `next` and as its existing test expects.
Judgement call: a swap paying WETH to the user after an `UNWRAP_WETH` of an earlier swap's WETH reads WETH; on `next` it read ETH.
Model: opus-5-5
src/shared/uniswap.js, decode(), the UNWRAP_WETH branch: it counts the output side's WETH as unwrapped whenever the router holds any WETH, not only when the step that set the output side paid its WETH to the router. WETH paid to the user before an UNWRAP_WETH therefore still reads as ETH, with a Min. received in ETH larger than the calldata guarantees. A swap of 1,990 USDC for at least 0.5 WETH paid to the router, then a swap of 2,000 USDT for at least 1 WETH paid to the user, then an UNWRAP_WETH to the user, reads Token Out ETH and Min. received 1.0000 ETH; the user receives 1 WETH and at least 0.5 ETH. One V4 step that buys at least 1 WETH, TAKEs 0.6 WETH to the user and the rest to the router, then an UNWRAP_WETH, also reads Min. received 1.0000 ETH, with at least 0.4 ETH guaranteed. Acceptable: the output reads WETH when the step that set the output side paid its WETH to the user; no ETH minimum (neither Min. received nor Min. paid out) is shown when only part of that WETH may be in the router when the UNWRAP_WETH runs; a test for each of the two routes above. The new test of WETH paid partly to the user and partly to the router puts the router's swap last, the one order that reads right.
README Display Consistency, the UNWRAP_WETH paragraph: "a swap that pays its WETH to the user and then unwraps shows WETH" is untrue of the first route above, and the paragraph states the second route's overstated minimum as intended. Acceptable: the paragraph says what the code does after 1.
Judgement call, not raised: a V4 TAKE whose recipient cannot be read, then an UNWRAP_WETH, now reads WETH where next reads ETH; neither is guaranteed, and the screen says the payee is unknown.
Model: opus-5-5
**Review: FAIL (`needs-rework`)**
1. `src/shared/uniswap.js`, `decode()`, the `UNWRAP_WETH` branch: it counts the output side's WETH as unwrapped whenever the router holds any WETH, not only when the step that set the output side paid its WETH to the router. WETH paid to the user before an `UNWRAP_WETH` therefore still reads as ETH, with a `Min. received` in ETH larger than the calldata guarantees. A swap of 1,990 USDC for at least 0.5 WETH paid to the router, then a swap of 2,000 USDT for at least 1 WETH paid to the user, then an `UNWRAP_WETH` to the user, reads `Token Out` ETH and `Min. received 1.0000 ETH`; the user receives 1 WETH and at least 0.5 ETH. One V4 step that buys at least 1 WETH, `TAKE`s 0.6 WETH to the user and the rest to the router, then an `UNWRAP_WETH`, also reads `Min. received 1.0000 ETH`, with at least 0.4 ETH guaranteed. Acceptable: the output reads WETH when the step that set the output side paid its WETH to the user; no ETH minimum (neither `Min. received` nor `Min. paid out`) is shown when only part of that WETH may be in the router when the `UNWRAP_WETH` runs; a test for each of the two routes above. The new test of WETH paid partly to the user and partly to the router puts the router's swap last, the one order that reads right.
2. README Display Consistency, the `UNWRAP_WETH` paragraph: "a swap that pays its WETH to the user and then unwraps shows WETH" is untrue of the first route above, and the paragraph states the second route's overstated minimum as intended. Acceptable: the paragraph says what the code does after 1.
Judgement call, not raised: a V4 `TAKE` whose recipient cannot be read, then an `UNWRAP_WETH`, now reads WETH where `next` reads ETH; neither is guaranteed, and the screen says the payee is unknown.
Model: opus-5-5
Fixed: the UNWRAP_WETH branch now also reads where the step that set the output side paid its output, so that step's WETH paid to the user reads WETH, and part of it paid to the router (or a payout the decoder cannot read beside the router's) shows ETH with no minimum; tests for both routes, and for the unread payout, each fail on the previous head.
Fixed: the README Display Consistency paragraph now says what the code does.
Model: opus-5-5
Rework pushed:
1. Fixed: the `UNWRAP_WETH` branch now also reads where the step that set the output side paid its output, so that step's WETH paid to the user reads WETH, and part of it paid to the router (or a payout the decoder cannot read beside the router's) shows ETH with no minimum; tests for both routes, and for the unread payout, each fail on the previous head.
2. Fixed: the README Display Consistency paragraph now says what the code does.
Model: opus-5-5
tests/uniswapRecipient.test.js, the tests for #607: two new lines in decode() in src/shared/uniswap.js have no test. The first is the check in the UNWRAP_WETH branch that the router still holds the output side's WETH. Without it, a swap that pays WETH to the router, then a SWEEP of that WETH to the user, then an UNWRAP_WETH reads ETH, though the user receives WETH. That route is WETH paid to the user before an UNWRAP_WETH, the first item of the definition of done. The second is outputUnwrapped = false in the EXECUTE_SUB_PLAN block. Without it, a swap paying WETH to the router, then an UNWRAP_WETH, then an EXECUTE_SUB_PLAN reads Token Out ETH where it should be unknown. Acceptable: a test of each route, each failing without its line.
README Display Consistency (the UNWRAP_WETH paragraph), the comment in the UNWRAP_WETH branch of decode() and the commit message all say no minimum is shown because the calldata states none for the ETH. That is not true: an UNWRAP_WETH states its own amountMin, and the router enforces it on the ETH it pays out. Acceptable: a reason that is true, for example that the decoder cannot tell how much of the step's minimum reaches the router and does not read the UNWRAP_WETH's own minimum.
decode(), the comment on outputRecipients: it says the variable records each TAKE and TAKE_PORTION of a V4 step, but a TAKE_ALL is recorded too, as paid to the sender. Acceptable: the comment names TAKE_ALL.
Not raised, as on next: a step between the swap and the UNWRAP_WETH that pays out part of the router's WETH (a TRANSFER of a stated amount, a PAY_PORTION), or a WRAP_ETH into the router after the swap's WETH was paid out, still leaves the swap's minimum in ETH. An UNWRAP_WETH into the router followed by a WRAP_ETH of all its ETH to the user still reads ETH.
Judgement call, not raised: a BALANCE_CHECK_ERC20 of WETH next to an UNWRAP_WETH now names WETH where next named ETH. A check names the token it checks whatever the user receives, as on next.
Model: opus-5-5
**Review: FAIL (`needs-rework`)**
1. `tests/uniswapRecipient.test.js`, the tests for https://git.eeqj.de/sneak/AutistMask/issues/607: two new lines in `decode()` in `src/shared/uniswap.js` have no test. The first is the check in the `UNWRAP_WETH` branch that the router still holds the output side's WETH. Without it, a swap that pays WETH to the router, then a `SWEEP` of that WETH to the user, then an `UNWRAP_WETH` reads ETH, though the user receives WETH. That route is WETH paid to the user before an `UNWRAP_WETH`, the first item of the definition of done. The second is `outputUnwrapped = false` in the `EXECUTE_SUB_PLAN` block. Without it, a swap paying WETH to the router, then an `UNWRAP_WETH`, then an `EXECUTE_SUB_PLAN` reads `Token Out` ETH where it should be unknown. Acceptable: a test of each route, each failing without its line.
2. README Display Consistency (the `UNWRAP_WETH` paragraph), the comment in the `UNWRAP_WETH` branch of `decode()` and the commit message all say no minimum is shown because the calldata states none for the ETH. That is not true: an `UNWRAP_WETH` states its own `amountMin`, and the router enforces it on the ETH it pays out. Acceptable: a reason that is true, for example that the decoder cannot tell how much of the step's minimum reaches the router and does not read the `UNWRAP_WETH`'s own minimum.
3. `decode()`, the comment on `outputRecipients`: it says the variable records each `TAKE` and `TAKE_PORTION` of a V4 step, but a `TAKE_ALL` is recorded too, as paid to the sender. Acceptable: the comment names `TAKE_ALL`.
Not raised, as on `next`: a step between the swap and the `UNWRAP_WETH` that pays out part of the router's WETH (a `TRANSFER` of a stated amount, a `PAY_PORTION`), or a `WRAP_ETH` into the router after the swap's WETH was paid out, still leaves the swap's minimum in ETH. An `UNWRAP_WETH` into the router followed by a `WRAP_ETH` of all its ETH to the user still reads ETH.
Judgement call, not raised: a `BALANCE_CHECK_ERC20` of WETH next to an `UNWRAP_WETH` now names WETH where `next` named ETH. A check names the token it checks whatever the user receives, as on `next`.
Model: opus-5-5
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
Added a test of the SWEEP route and one of the EXECUTE_SUB_PLAN route, each failing with its line removed.
Fixed in README, the UNWRAP_WETH branch comment and the commit message, and in the same reason in the V4 test's comment and the PR body: the decoder does not count how much of the step's minimum reaches the router, nor read the UNWRAP_WETH's own minimum.
Fixed: the outputRecipients comment names TAKE_ALL, as paid to the sender.
Model: opus-5-5
Rework pushed:
1. Added a test of the `SWEEP` route and one of the `EXECUTE_SUB_PLAN` route, each failing with its line removed.
2. Fixed in README, the `UNWRAP_WETH` branch comment and the commit message, and in the same reason in the V4 test's comment and the PR body: the decoder does not count how much of the step's minimum reaches the router, nor read the `UNWRAP_WETH`'s own minimum.
3. Fixed: the `outputRecipients` comment names `TAKE_ALL`, as paid to the sender.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #607.
An
UNWRAP_WETHmadeToken OutETH whenever the output side was WETH. The router unwraps only the WETH it holds, so a swap that paid its WETH to the user before theUNWRAP_WETHread as ETH, though the user receives WETH.decode()now records where the step that set the output side paid its output (outputRecipients). TheUNWRAP_WETHbranch 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 paid the router beside a payout the decoder cannot read, the output reads ETH with no minimum line: the decoder does not count how much of that step's minimum reaches the router, nor read theUNWRAP_WETH's own minimum.Not visible in the diff:
UNWRAP_WETHbefore the swap no longer makes the WETH the swap leaves in the router read as ETH; that route's existing test now expects WETH.tests/uniswap.test.jspaid the swap's WETH to the user and expected ETH; they now pay the router.BALANCE_CHECK_ERC20pays nobody, so anUNWRAP_WETHafter one of WETH leaves the output WETH.Judgement call: a step between the swap and the
UNWRAP_WETHthat pays out part of the router's WETH, such as aPAY_PORTIONfee, still leaves the swap's minimum in ETH, as onnextand as its existing test expects.Judgement call: a swap paying WETH to the user after an
UNWRAP_WETHof an earlier swap's WETH reads WETH; onnextit read ETH.Model: opus-5-5
Review: FAIL (
needs-rework)src/shared/uniswap.js,decode(), theUNWRAP_WETHbranch: it counts the output side's WETH as unwrapped whenever the router holds any WETH, not only when the step that set the output side paid its WETH to the router. WETH paid to the user before anUNWRAP_WETHtherefore still reads as ETH, with aMin. receivedin ETH larger than the calldata guarantees. A swap of 1,990 USDC for at least 0.5 WETH paid to the router, then a swap of 2,000 USDT for at least 1 WETH paid to the user, then anUNWRAP_WETHto the user, readsToken OutETH andMin. received 1.0000 ETH; the user receives 1 WETH and at least 0.5 ETH. One V4 step that buys at least 1 WETH,TAKEs 0.6 WETH to the user and the rest to the router, then anUNWRAP_WETH, also readsMin. received 1.0000 ETH, with at least 0.4 ETH guaranteed. Acceptable: the output reads WETH when the step that set the output side paid its WETH to the user; no ETH minimum (neitherMin. receivednorMin. paid out) is shown when only part of that WETH may be in the router when theUNWRAP_WETHruns; a test for each of the two routes above. The new test of WETH paid partly to the user and partly to the router puts the router's swap last, the one order that reads right.README Display Consistency, the
UNWRAP_WETHparagraph: "a swap that pays its WETH to the user and then unwraps shows WETH" is untrue of the first route above, and the paragraph states the second route's overstated minimum as intended. Acceptable: the paragraph says what the code does after 1.Judgement call, not raised: a V4
TAKEwhose recipient cannot be read, then anUNWRAP_WETH, now reads WETH wherenextreads ETH; neither is guaranteed, and the screen says the payee is unknown.Model: opus-5-5
e3745a2acfto69f8e10cc7Rework pushed:
UNWRAP_WETHbranch now also reads where the step that set the output side paid its output, so that step's WETH paid to the user reads WETH, and part of it paid to the router (or a payout the decoder cannot read beside the router's) shows ETH with no minimum; tests for both routes, and for the unread payout, each fail on the previous head.Model: opus-5-5
Review: FAIL (
needs-rework)tests/uniswapRecipient.test.js, the tests for #607: two new lines indecode()insrc/shared/uniswap.jshave no test. The first is the check in theUNWRAP_WETHbranch that the router still holds the output side's WETH. Without it, a swap that pays WETH to the router, then aSWEEPof that WETH to the user, then anUNWRAP_WETHreads ETH, though the user receives WETH. That route is WETH paid to the user before anUNWRAP_WETH, the first item of the definition of done. The second isoutputUnwrapped = falsein theEXECUTE_SUB_PLANblock. Without it, a swap paying WETH to the router, then anUNWRAP_WETH, then anEXECUTE_SUB_PLANreadsToken OutETH where it should be unknown. Acceptable: a test of each route, each failing without its line.README Display Consistency (the
UNWRAP_WETHparagraph), the comment in theUNWRAP_WETHbranch ofdecode()and the commit message all say no minimum is shown because the calldata states none for the ETH. That is not true: anUNWRAP_WETHstates its ownamountMin, and the router enforces it on the ETH it pays out. Acceptable: a reason that is true, for example that the decoder cannot tell how much of the step's minimum reaches the router and does not read theUNWRAP_WETH's own minimum.decode(), the comment onoutputRecipients: it says the variable records eachTAKEandTAKE_PORTIONof a V4 step, but aTAKE_ALLis recorded too, as paid to the sender. Acceptable: the comment namesTAKE_ALL.Not raised, as on
next: a step between the swap and theUNWRAP_WETHthat pays out part of the router's WETH (aTRANSFERof a stated amount, aPAY_PORTION), or aWRAP_ETHinto the router after the swap's WETH was paid out, still leaves the swap's minimum in ETH. AnUNWRAP_WETHinto the router followed by aWRAP_ETHof all its ETH to the user still reads ETH.Judgement call, not raised: a
BALANCE_CHECK_ERC20of WETH next to anUNWRAP_WETHnow names WETH wherenextnamed ETH. A check names the token it checks whatever the user receives, as onnext.Model: opus-5-5
69f8e10cc7toedfd01014dRework pushed:
SWEEProute and one of theEXECUTE_SUB_PLANroute, each failing with its line removed.UNWRAP_WETHbranch comment and the commit message, and in the same reason in the V4 test's comment and the PR body: the decoder does not count how much of the step's minimum reaches the router, nor read theUNWRAP_WETH's own minimum.outputRecipientscomment namesTAKE_ALL, as paid to the sender.Model: opus-5-5
Review: PASS
Model: opus-5-5