fix: a V4 swap action not in the deployed shape is shown as not decoded (closes #358) #537

Merged
clawbot merged 1 commits from issue-358-v4-undecoded-step into next 2026-10-16 03:00:33 +02:00
Collaborator

Fixes #358, as settled there: the V4 swap actions stay pinned to the parameter structs deployed on mainnet and Sepolia.

The issue expected the newer v4-periphery structs, which add minHopPriceX36, to fail to decode. ethers read them as the deployed ones instead, and the newer multi-hop exact-in struct showed its hop-price array's offset as Amount.

The four swap-action decodes in src/shared/uniswap.js now go through decodeExactly(), which accepts a decode only when encoding it again gives back the same bytes. A swap action that fails is listed as V4 Swap (could not be decoded) with no amounts, and a side its SETTLE or TAKE did not name reads Unknown (could not be decoded), never another step's token or figure, nor ETH from an UNWRAP_WETH.

The wait and error screens showed the transaction's ETH value as the amount of a swap with no Amount line, such as 0.0000 WETH. They now say Unknown (could not be decoded), with no currency. This also covers a V4 exact-out step, which did the same on next. A swap whose Token In is ETH (native) still shows that ETH value, since it is what the swap pays.

The README records the pinned shape and the wordings.

Judgement call: the strict decode goes beyond marking the fallthrough; without it the marker never fires for the shape the issue is about.
Not done: an unreadable V4_SWAP input as a whole, and failed V2, V3, SETTLE or TAKE decodes, are still skipped silently.

Model: opus-5-5

Fixes https://git.eeqj.de/sneak/AutistMask/issues/358, as settled there: the V4 swap actions stay pinned to the parameter structs deployed on mainnet and Sepolia. The issue expected the newer `v4-periphery` structs, which add `minHopPriceX36`, to fail to decode. ethers read them as the deployed ones instead, and the newer multi-hop exact-in struct showed its hop-price array's offset as `Amount`. The four swap-action decodes in `src/shared/uniswap.js` now go through `decodeExactly()`, which accepts a decode only when encoding it again gives back the same bytes. A swap action that fails is listed as `V4 Swap (could not be decoded)` with no amounts, and a side its `SETTLE` or `TAKE` did not name reads `Unknown (could not be decoded)`, never another step's token or figure, nor ETH from an `UNWRAP_WETH`. The wait and error screens showed the transaction's ETH value as the amount of a swap with no `Amount` line, such as `0.0000 WETH`. They now say `Unknown (could not be decoded)`, with no currency. This also covers a V4 exact-out step, which did the same on `next`. A swap whose `Token In` is `ETH (native)` still shows that ETH value, since it is what the swap pays. The README records the pinned shape and the wordings. Judgement call: the strict decode goes beyond marking the fallthrough; without it the marker never fires for the shape the issue is about. Not done: an unreadable `V4_SWAP` input as a whole, and failed V2, V3, `SETTLE` or `TAKE` decodes, are still skipped silently. Model: opus-5-5
clawbot added the needs-review label 2026-10-14 05:52:27 +02:00
clawbot self-assigned this 2026-10-14 05:52:27 +02:00
clawbot force-pushed issue-358-v4-undecoded-step from 6e00d52f89 to 0c88dcbda9 2026-10-14 06:27:51 +02:00 Compare
Author
Collaborator

FAIL (needs-rework)

  1. src/shared/uniswap.js, the Token In and Token Out fallbacks in decode() (lines 671 and 734), next to the new step marker (line 596). When a V4 swap action is not in the deployed shape and no SETTLE/TAKE names the currencies, for example a swap action followed by SETTLE_ALL and TAKE_ALL, the screen shows V4 Swap (could not be decoded) and also says both tokens are "Unknown (not named in the calldata)". The calldata did name them, in the action that was not read, so those two lines present "could not decode" as "nothing there", which #358 rules out. For the newer single-pool structs this is new: on next they showed the right tokens. Acceptable: when a swap action went unread and a side is left without a token, that line says the currency could not be read, not that the calldata did not name it, with a test for a newer-shape swap action followed by SETTLE_ALL and TAKE_ALL.

Judgement call: the cases the PR lists as not done (an unreadable V4_SWAP input as a whole; failed V2, V3, SETTLE or TAKE decodes) are outside the issue's definition of done, since none of them is a V4 swap struct whose shape changed upstream.
Judgement call: a deployed-shape swap action with extra bytes appended is now shown as not decoded, although the router would run it; taken as the intended effect of pinning the shape.

Model: opus-5-5

**FAIL** (`needs-rework`) 1. `src/shared/uniswap.js`, the Token In and Token Out fallbacks in `decode()` (lines 671 and 734), next to the new step marker (line 596). When a V4 swap action is not in the deployed shape and no `SETTLE`/`TAKE` names the currencies, for example a swap action followed by `SETTLE_ALL` and `TAKE_ALL`, the screen shows `V4 Swap (could not be decoded)` and also says both tokens are "Unknown (not named in the calldata)". The calldata did name them, in the action that was not read, so those two lines present "could not decode" as "nothing there", which https://git.eeqj.de/sneak/AutistMask/issues/358 rules out. For the newer single-pool structs this is new: on `next` they showed the right tokens. Acceptable: when a swap action went unread and a side is left without a token, that line says the currency could not be read, not that the calldata did not name it, with a test for a newer-shape swap action followed by `SETTLE_ALL` and `TAKE_ALL`. Judgement call: the cases the PR lists as not done (an unreadable `V4_SWAP` input as a whole; failed V2, V3, `SETTLE` or `TAKE` decodes) are outside the issue's definition of done, since none of them is a V4 swap struct whose shape changed upstream. Judgement call: a deployed-shape swap action with extra bytes appended is now shown as not decoded, although the router would run it; taken as the intended effect of pinning the shape. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-14 09:14:51 +02:00
clawbot force-pushed issue-358-v4-undecoded-step from 0c88dcbda9 to ec1254204c 2026-10-14 11:27:27 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-10-14 11:27:33 +02:00
Author
Collaborator
  1. A token line left without a currency after a swap action went unread now reads Unknown (could not be decoded), not Unknown (not named in the calldata). A new test runs each newer-shape swap action followed by SETTLE_ALL and TAKE_ALL, and the existing unreadable-action test in tests/uniswapUndeterminedTokenIn.test.js now expects the new wording.

Model: opus-5-5

1. A token line left without a currency after a swap action went unread now reads `Unknown (could not be decoded)`, not `Unknown (not named in the calldata)`. A new test runs each newer-shape swap action followed by `SETTLE_ALL` and `TAKE_ALL`, and the existing unreadable-action test in `tests/uniswapUndeterminedTokenIn.test.js` now expects the new wording. Model: opus-5-5
Author
Collaborator

FAIL (needs-rework)

The earlier finding is resolved.

  1. src/shared/uniswap.js, the V4 swap branch of decode() (lines 606 and 617). A V4 step whose swap action could not be read, and which has no TAKE (or no SETTLE), sets nothing on that side, so a neighbouring step's token and figure take its place. A V3 swap of USDT to WETH followed by a newer-shape V4 swap of WETH to USDC that ends in TAKE_ALL is titled Swap USDT → WETH, with Token Out WETH and the V3 step's Min. received, although the user receives USDC. The mirror case, a newer-shape V4 step with SETTLE_ALL and then a V3 step, names the V3 step's input token and amount as what is paid. On next both transactions showed the right tokens. The screen now names a wrong asset in the very shape #358 is about. Acceptable: a V4 step with an unread swap action leaves a side it did not name undetermined, so that line reads Unknown (could not be decoded) and no other step's figure is shown beside it, with tests for a V3 step before and after such a V4 step.

Judgement call: this is in scope although the PR lists an unreadable V4_SWAP input as not done, because here only the swap action, in the changed upstream shape, is unread.

Model: opus-5-5

**FAIL** (`needs-rework`) The earlier finding is resolved. 1. `src/shared/uniswap.js`, the V4 swap branch of `decode()` (lines 606 and 617). A V4 step whose swap action could not be read, and which has no `TAKE` (or no `SETTLE`), sets nothing on that side, so a neighbouring step's token and figure take its place. A V3 swap of USDT to WETH followed by a newer-shape V4 swap of WETH to USDC that ends in `TAKE_ALL` is titled `Swap USDT → WETH`, with `Token Out` WETH and the V3 step's `Min. received`, although the user receives USDC. The mirror case, a newer-shape V4 step with `SETTLE_ALL` and then a V3 step, names the V3 step's input token and amount as what is paid. On `next` both transactions showed the right tokens. The screen now names a wrong asset in the very shape https://git.eeqj.de/sneak/AutistMask/issues/358 is about. Acceptable: a V4 step with an unread swap action leaves a side it did not name undetermined, so that line reads `Unknown (could not be decoded)` and no other step's figure is shown beside it, with tests for a V3 step before and after such a V4 step. Judgement call: this is in scope although the PR lists an unreadable `V4_SWAP` input as not done, because here only the swap action, in the changed upstream shape, is unread. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-14 17:49:06 +02:00
clawbot force-pushed issue-358-v4-undecoded-step from ec1254204c to f938950161 2026-10-14 20:42:12 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-10-14 20:42:35 +02:00
Author
Collaborator
  1. A V4 step whose swap action could not be read now sets both sides itself: a side its SETTLE or TAKE did not name reads Unknown (could not be decoded), and no other step's token or figure is shown for it. Tests run each newer-shape swap action after a V3 step (ending in TAKE_ALL) and before one (with SETTLE_ALL).

Judgement call: an UNWRAP_WETH after such a step no longer turns its unknown Token Out into ETH, with a test.

Model: opus-5-5

1. A V4 step whose swap action could not be read now sets both sides itself: a side its `SETTLE` or `TAKE` did not name reads `Unknown (could not be decoded)`, and no other step's token or figure is shown for it. Tests run each newer-shape swap action after a V3 step (ending in `TAKE_ALL`) and before one (with `SETTLE_ALL`). Judgement call: an `UNWRAP_WETH` after such a step no longer turns its unknown `Token Out` into ETH, with a test. Model: opus-5-5
Author
Collaborator

FAIL (needs-rework)

  1. src/popup/views/approval.js, the details showTxApproval() builds for the later screens (lines 262 to 299), reached through the new branch in decode() in src/shared/uniswap.js (line 599). When a V4 swap action is not read and its SETTLE names the token paid, the approval screen rightly drops the Amount line, but the wait, success and error screens then show the transaction's ETH value in that token: a swap of 1 WETH in the newer single-pool exact-in shape reads 0.0000 WETH there. On next the same transaction read 1.0000 WETH on those screens. That is a figure the decoder refused to state, shown as "nothing paid", which #358 rules out, and it contradicts the PR body's "its amounts are not shown". Acceptable: when a swap's amount was not read, those screens show no figure in the swap's input token (for example, they say the amount could not be decoded), with a test. A V4 exact-out step already reaches the same fallback on next; fixing it in the same change is not scope creep.

  2. PR body: 274 words, over the limit of about 250. Acceptable: about 250 words or fewer, including whatever the fix for item 1 adds.

Model: opus-5-5

**FAIL** (`needs-rework`) 1. `src/popup/views/approval.js`, the details `showTxApproval()` builds for the later screens (lines 262 to 299), reached through the new branch in `decode()` in `src/shared/uniswap.js` (line 599). When a V4 swap action is not read and its `SETTLE` names the token paid, the approval screen rightly drops the `Amount` line, but the wait, success and error screens then show the transaction's ETH value in that token: a swap of 1 WETH in the newer single-pool exact-in shape reads `0.0000 WETH` there. On `next` the same transaction read `1.0000 WETH` on those screens. That is a figure the decoder refused to state, shown as "nothing paid", which https://git.eeqj.de/sneak/AutistMask/issues/358 rules out, and it contradicts the PR body's "its amounts are not shown". Acceptable: when a swap's amount was not read, those screens show no figure in the swap's input token (for example, they say the amount could not be decoded), with a test. A V4 exact-out step already reaches the same fallback on `next`; fixing it in the same change is not scope creep. 2. PR body: 274 words, over the limit of about 250. Acceptable: about 250 words or fewer, including whatever the fix for item 1 adds. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-16 01:22:20 +02:00
clawbot force-pushed issue-358-v4-undecoded-step from f938950161 to 08fa969cd6 2026-10-16 01:55:44 +02:00 Compare
clawbot changed title from fix: a V4 swap action not in the deployed shape is shown as not decoded to fix: a V4 swap action not in the deployed shape is shown as not decoded (closes #358) 2026-10-16 01:56:25 +02:00
clawbot added needs-review and removed needs-rework labels 2026-10-16 01:56:26 +02:00
Author
Collaborator
  1. The wait and error screens now read Unknown (could not be decoded), with no currency, for any swap the approval screen showed no Amount for, V4 exact-out steps included. tests/swapStatusAmount.test.js drives each case through Confirm to those screens and to the success screen, which already showed the decoded lines in place of an amount.
  2. The PR body is now under 250 words.

Judgement call: a swap whose input token is also unknown, such as a newer-shape swap action with SETTLE_ALL, showed 0.0000 ETH there; it gets the same wording, which is why no currency follows it.
Judgement call: a swap paid in native ETH with no Amount line now reads the same instead of the transaction's ETH value.

Model: opus-5-5

1. The wait and error screens now read `Unknown (could not be decoded)`, with no currency, for any swap the approval screen showed no `Amount` for, V4 exact-out steps included. `tests/swapStatusAmount.test.js` drives each case through Confirm to those screens and to the success screen, which already showed the decoded lines in place of an amount. 2. The PR body is now under 250 words. Judgement call: a swap whose input token is also unknown, such as a newer-shape swap action with `SETTLE_ALL`, showed `0.0000 ETH` there; it gets the same wording, which is why no currency follows it. Judgement call: a swap paid in native ETH with no `Amount` line now reads the same instead of the transaction's ETH value. Model: opus-5-5
Author
Collaborator

FAIL (needs-rework)

The findings of the three earlier reviews stay resolved.

  1. src/popup/views/approval.js, the new check in showTxApproval() (lines 301 to 312). For a swap paid in native ETH that has no Amount line, the wait and error screens now read Unknown (could not be decoded) where they used to show the ETH the transaction sends. That figure is not read from the calldata. It is the transaction's own value, the same one the approval screen's value line shows, and for a swap paid in ETH it is what the user pays (for an exact-out swap, the most they pay). The change also reaches a transaction where nothing failed to decode: a V4 exact-out swap in the deployed shape, paid in ETH, whose steps read V4 Swap, showed 1.0000 ETH on those screens on next and now says its amount could not be decoded. Acceptable: when the swap's Token In line is ETH (native), those screens keep showing the transaction's ETH value in the network's currency, as on next. Unknown (could not be decoded) stays for a swap paid in a token, or in a currency the decoder could not establish. The README's WaitTx and ErrorTx entries say so, and a test covers a swap paid in ETH.

Judgement call: a swap whose input currency is unknown keeps the new wording even when the transaction sends ETH, because that ETH is not known to be what the swap pays.

Model: opus-5-5

**FAIL** (`needs-rework`) The findings of the three earlier reviews stay resolved. 1. `src/popup/views/approval.js`, the new check in `showTxApproval()` (lines 301 to 312). For a swap paid in native ETH that has no `Amount` line, the wait and error screens now read `Unknown (could not be decoded)` where they used to show the ETH the transaction sends. That figure is not read from the calldata. It is the transaction's own value, the same one the approval screen's value line shows, and for a swap paid in ETH it is what the user pays (for an exact-out swap, the most they pay). The change also reaches a transaction where nothing failed to decode: a V4 exact-out swap in the deployed shape, paid in ETH, whose steps read `V4 Swap`, showed `1.0000 ETH` on those screens on `next` and now says its amount could not be decoded. Acceptable: when the swap's `Token In` line is `ETH (native)`, those screens keep showing the transaction's ETH value in the network's currency, as on `next`. `Unknown (could not be decoded)` stays for a swap paid in a token, or in a currency the decoder could not establish. The README's WaitTx and ErrorTx entries say so, and a test covers a swap paid in ETH. Judgement call: a swap whose input currency is unknown keeps the new wording even when the transaction sends ETH, because that ETH is not known to be what the swap pays. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-16 02:11:41 +02:00
clawbot added 1 commit 2026-10-16 02:31:39 +02:00
fix: a V4 swap action not in the deployed shape is shown as not decoded (closes #358)
check / check (push) Canceled after 0s
e2e / e2e-chrome (push) Canceled after 0s
e2e / e2e-firefox (push) Canceled after 0s
130ecd9bbe
The four V4 swap actions are read only as the structs deployed on mainnet
and Sepolia. ethers read the newer v4-periphery structs, which add
minHopPriceX36, as the deployed ones, and the newer multi-hop exact-in
struct showed the offset of its hop-price array as the swap amount. A
decode now counts only when encoding it again gives back the same bytes.
A swap action that fails that marks its step "V4 Swap (could not be
decoded)", and a side its SETTLE or TAKE did not name reads "Unknown
(could not be decoded)". The wait and error screens no longer show the
ETH value as the amount of a swap whose amount was not read, unless the
swap is paid in native ETH.

Model: opus-5-5
clawbot force-pushed issue-358-v4-undecoded-step from 08fa969cd6 to 130ecd9bbe 2026-10-16 02:31:39 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-10-16 02:39:15 +02:00
Author
Collaborator
  1. When the swap's Token In is ETH (native), the wait and error screens again show the transaction's ETH value in the network's currency. The README's WaitTx and ErrorTx entries say so, and tests/swapStatusAmount.test.js covers a deployed-shape exact-out swap and a newer-shape swap action, each paid in ETH.

The PR body no longer has the judgement call about swaps paid in native ETH losing their ETH value.

Model: opus-5-5

1. When the swap's `Token In` is `ETH (native)`, the wait and error screens again show the transaction's ETH value in the network's currency. The README's WaitTx and ErrorTx entries say so, and `tests/swapStatusAmount.test.js` covers a deployed-shape exact-out swap and a newer-shape swap action, each paid in ETH. The PR body no longer has the judgement call about swaps paid in native ETH losing their ETH value. Model: opus-5-5
Author
Collaborator

PASS: the change meets the definition of done in #358, and the findings of the four earlier reviews stay resolved.

Judgement call: a BALANCE_CHECK_ERC20 with a zero minBalance after a V4 step whose swap action could not be read shows None (no minimum guaranteed), as the README's balance-check rule says. I did not raise it: it understates what the swap guarantees rather than overstating it, and a V4 exact-out step already gives the same result on next.

Model: opus-5-5

**PASS**: the change meets the definition of done in https://git.eeqj.de/sneak/AutistMask/issues/358, and the findings of the four earlier reviews stay resolved. Judgement call: a `BALANCE_CHECK_ERC20` with a zero `minBalance` after a V4 step whose swap action could not be read shows `None (no minimum guaranteed)`, as the README's balance-check rule says. I did not raise it: it understates what the swap guarantees rather than overstating it, and a V4 exact-out step already gives the same result on `next`. Model: opus-5-5
clawbot merged commit bad6494e43 into next 2026-10-16 03:00:33 +02:00
clawbot deleted branch issue-358-v4-undecoded-step 2026-10-16 03:00:34 +02:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/AutistMask#537