A V3_SWAP_EXACT_OUT step was named in the Steps line but never read (#601), so it showed neither its tokens nor its amounts. Also fixes #637.
In src/shared/uniswap.js:
decodeV3SwapExactOut() reads (recipient, amountOut, amountInMax, path, payerIsUser). The router reads an exact-out path from the token it buys to the token it spends, so Token In is the path's last token and Token Out its first.
decode() reads the step in the V2_SWAP_EXACT_OUT branch, so it counts as that step does: amountInMax as its amount (Up to), amountOut as the minimum, its recipient named, and, when the user pays a later one, its take added to the total from #626.
decodeV3Path() returns the path's first and last token, which the two V3 readers take in opposite order, or null for a path that is not one token followed by whole 23-byte hops: the router ignores bytes after the last hop, so the last 20 bytes need not be a token it reads. Either V3 swap step with such a path goes unread.
README Display Consistency and Transaction Decoding describe this.
Disclosures:
Judgement call: an exact-out step paid from the router, V2 or V3, is not counted against what the router holds, as on next for V2, because the calldata does not state what it spends. I read the plan's "counts against the router's balance" as "takes nothing from the user's wallet".
The test with a path shorter than one token also passes on next; it checks that such a step leaves no figure.
Model: opus-5-5
A `V3_SWAP_EXACT_OUT` step was named in the Steps line but never read (https://git.eeqj.de/sneak/AutistMask/issues/601), so it showed neither its tokens nor its amounts. Also fixes https://git.eeqj.de/sneak/AutistMask/issues/637.
In `src/shared/uniswap.js`:
- `decodeV3SwapExactOut()` reads `(recipient, amountOut, amountInMax, path, payerIsUser)`. The router reads an exact-out path from the token it buys to the token it spends, so `Token In` is the path's last token and `Token Out` its first.
- `decode()` reads the step in the `V2_SWAP_EXACT_OUT` branch, so it counts as that step does: `amountInMax` as its amount (`Up to`), `amountOut` as the minimum, its recipient named, and, when the user pays a later one, its take added to the total from https://git.eeqj.de/sneak/AutistMask/pulls/626.
- `decodeV3Path()` returns the path's `first` and `last` token, which the two V3 readers take in opposite order, or null for a path that is not one token followed by whole 23-byte hops: the router ignores bytes after the last hop, so the last 20 bytes need not be a token it reads. Either V3 swap step with such a path goes unread.
README Display Consistency and Transaction Decoding describe this.
Disclosures:
- Judgement call: an exact-out step paid from the router, V2 or V3, is not counted against what the router holds, as on `next` for V2, because the calldata does not state what it spends. I read the plan's "counts against the router's balance" as "takes nothing from the user's wallet".
- The test with a path shorter than one token also passes on `next`; it checks that such a step leaves no figure.
Model: opus-5-5
clawbot
self-assigned this 2026-10-20 08:52:42 +02:00
src/shared/uniswap.js, decodeV3SwapExactOut(): the token spent is taken from the last 20 bytes of the path, but the router pays the token that ends the path's last whole hop and ignores any bytes after it. A path of USDC, a fee, WETH and 19 more bytes spends WETH, yet the screen names as Token In, and gives the Amount in, the address formed by WETH's last byte and those 19 bytes, which can be a bundled token. Followed by a PERMIT2_PERMIT of WETH and a swap of it, the Amount reads the permit's figure alone, although the exact-out step also takes WETH. On next this step left no Amount figure. Acceptable: for a V3_SWAP_EXACT_OUT, read the token spent where the router reads it, or treat a path whose length is not 20 bytes plus a whole number of 23-byte hops as unread, as a path shorter than one token is; a test with such a path; the README sentence that the path is read as the router reads it kept true.
README.md, Transaction Decoding: "spends at most its amountInMax, an amount the calldata does not state" says the calldata does not state amountInMax, which it does. Acceptable: the step spends an amount the calldata does not state, at most its amountInMax.
Not raised (on next too): V3_SWAP_EXACT_IN with a path that has bytes after its last whole hop names those last 20 bytes as Token Out, which is not the token the router pays out.
Model: opus-5-5
**Review: FAIL (`needs-rework`)**
1. `src/shared/uniswap.js`, `decodeV3SwapExactOut()`: the token spent is taken from the last 20 bytes of the path, but the router pays the token that ends the path's last whole hop and ignores any bytes after it. A path of USDC, a fee, WETH and 19 more bytes spends WETH, yet the screen names as `Token In`, and gives the `Amount` in, the address formed by WETH's last byte and those 19 bytes, which can be a bundled token. Followed by a `PERMIT2_PERMIT` of WETH and a swap of it, the `Amount` reads the permit's figure alone, although the exact-out step also takes WETH. On `next` this step left no `Amount` figure. Acceptable: for a `V3_SWAP_EXACT_OUT`, read the token spent where the router reads it, or treat a path whose length is not 20 bytes plus a whole number of 23-byte hops as unread, as a path shorter than one token is; a test with such a path; the README sentence that the path is read as the router reads it kept true.
2. `README.md`, Transaction Decoding: "spends at most its `amountInMax`, an amount the calldata does not state" says the calldata does not state `amountInMax`, which it does. Acceptable: the step spends an amount the calldata does not state, at most its `amountInMax`.
Not raised (on `next` too): `V3_SWAP_EXACT_IN` with a path that has bytes after its last whole hop names those last 20 bytes as `Token Out`, which is not the token the router pays out.
Model: opus-5-5
A V3_SWAP_EXACT_OUT step was named in the Steps line but never read, so
its tokens read as not named in the calldata and it gave no amounts. It
is now read as a V2_SWAP_EXACT_OUT is: its path from the token it buys
to the token it spends, as the router reads it, its amountInMax as the
most it spends, its amountOut as the minimum, and its recipient as the
address it pays. One the user pays for after the step that sets the
input side joins the Amount total. A V3 path with bytes after its last
whole hop, which the router ignores, leaves either V3 swap step unread.
Also closes#637.
Model: opus-5-5
decodeV3Path() leaves a path that is not one token followed by whole 23-byte hops unread, for both V3 swap steps; tests use the review's route, permit included, and the route in #637.
README Transaction Decoding now reads "spends an amount the calldata does not state, at most its amountInMax".
#637 is folded in; the commit and PR body say this PR closes it too.
Model: opus-5-5
Rework:
1. `decodeV3Path()` leaves a path that is not one token followed by whole 23-byte hops unread, for both V3 swap steps; tests use the review's route, permit included, and the route in https://git.eeqj.de/sneak/AutistMask/issues/637.
2. README Transaction Decoding now reads "spends an amount the calldata does not state, at most its `amountInMax`".
3. https://git.eeqj.de/sneak/AutistMask/issues/637 is folded in; the commit and PR body say this PR closes it too.
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.
A
V3_SWAP_EXACT_OUTstep was named in the Steps line but never read (#601), so it showed neither its tokens nor its amounts. Also fixes #637.In
src/shared/uniswap.js:decodeV3SwapExactOut()reads(recipient, amountOut, amountInMax, path, payerIsUser). The router reads an exact-out path from the token it buys to the token it spends, soToken Inis the path's last token andToken Outits first.decode()reads the step in theV2_SWAP_EXACT_OUTbranch, so it counts as that step does:amountInMaxas its amount (Up to),amountOutas the minimum, its recipient named, and, when the user pays a later one, its take added to the total from #626.decodeV3Path()returns the path'sfirstandlasttoken, which the two V3 readers take in opposite order, or null for a path that is not one token followed by whole 23-byte hops: the router ignores bytes after the last hop, so the last 20 bytes need not be a token it reads. Either V3 swap step with such a path goes unread.README Display Consistency and Transaction Decoding describe this.
Disclosures:
nextfor V2, because the calldata does not state what it spends. I read the plan's "counts against the router's balance" as "takes nothing from the user's wallet".next; it checks that such a step leaves no figure.Model: opus-5-5
Review: FAIL (
needs-rework)src/shared/uniswap.js,decodeV3SwapExactOut(): the token spent is taken from the last 20 bytes of the path, but the router pays the token that ends the path's last whole hop and ignores any bytes after it. A path of USDC, a fee, WETH and 19 more bytes spends WETH, yet the screen names asToken In, and gives theAmountin, the address formed by WETH's last byte and those 19 bytes, which can be a bundled token. Followed by aPERMIT2_PERMITof WETH and a swap of it, theAmountreads the permit's figure alone, although the exact-out step also takes WETH. Onnextthis step left noAmountfigure. Acceptable: for aV3_SWAP_EXACT_OUT, read the token spent where the router reads it, or treat a path whose length is not 20 bytes plus a whole number of 23-byte hops as unread, as a path shorter than one token is; a test with such a path; the README sentence that the path is read as the router reads it kept true.README.md, Transaction Decoding: "spends at most itsamountInMax, an amount the calldata does not state" says the calldata does not stateamountInMax, which it does. Acceptable: the step spends an amount the calldata does not state, at most itsamountInMax.Not raised (on
nexttoo):V3_SWAP_EXACT_INwith a path that has bytes after its last whole hop names those last 20 bytes asToken Out, which is not the token the router pays out.Model: opus-5-5
4adc65c2bbto68aafc6c4d68aafc6c4dto52ed4cf5f4Rework:
decodeV3Path()leaves a path that is not one token followed by whole 23-byte hops unread, for both V3 swap steps; tests use the review's route, permit included, and the route in #637.amountInMax".Model: opus-5-5
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.