The swap decoder, decode() in src/shared/uniswap.js: the Amount figure when a PERMIT2_PERMIT stands (the plain shape of Uniswap's own routes) and a PERMIT2_TRANSFER_FROM of the same token also runs.
What happens
A PERMIT2_TRANSFER_FROM that runs before the standing permit uses whatever allowance the router already had, so it can move more of the token than the permit's amount. The Amount figure is the permit's amount; the transfer's figure appears only on its own lines. The Amount line can then read lower than what leaves the wallet.
What should happen
The approval screen never shows a figure for what leaves the wallet that may be too low: a permit's amount stands as the Amount figure only when no other step can take that token from the sender under an allowance the permit does not set; otherwise the figure is the total of the takes, or none.
Severity: major
Definition of done
A PERMIT2_TRANSFER_FROM of the permit's token before the permit ends the permit's standing, so the Amount figure is not lower than what may leave.
A test with that route, failing on next.
Model: opus-5-5
Seen by the review of https://git.eeqj.de/sneak/AutistMask/pulls/651.
## Where
The swap decoder, `decode()` in `src/shared/uniswap.js`: the `Amount` figure when a `PERMIT2_PERMIT` stands (the plain shape of Uniswap's own routes) and a `PERMIT2_TRANSFER_FROM` of the same token also runs.
## What happens
A `PERMIT2_TRANSFER_FROM` that runs before the standing permit uses whatever allowance the router already had, so it can move more of the token than the permit's amount. The `Amount` figure is the permit's amount; the transfer's figure appears only on its own lines. The `Amount` line can then read lower than what leaves the wallet.
## What should happen
The approval screen never shows a figure for what leaves the wallet that may be too low: a permit's amount stands as the `Amount` figure only when no other step can take that token from the sender under an allowance the permit does not set; otherwise the figure is the total of the takes, or none.
Severity: major
## Definition of done
- [ ] A `PERMIT2_TRANSFER_FROM` of the permit's token before the permit ends the permit's standing, so the `Amount` figure is not lower than what may leave.
- [ ] A test with that route, failing on `next`.
Model: opus-5-5
clawbot
self-assigned this 2026-10-21 00:13:07 +02:00
Plan: one PR to next, in permitStands in decode() (src/shared/uniswap.js). Any step before the permit that may take the permit's token from the sender (a PERMIT2_TRANSFER_FROM of that token, a swap step the user pays in it, or a step the decoder does not read) ends the permit's standing, as a later one already does; the Amount figure is then the total of the takes, or none. Tests with a PERMIT2_TRANSFER_FROM and with a user-paid swap step before the permit, each failing on next; Uniswap's own routes read as on next.
Model: opus-5-5
Plan: one PR to `next`, in `permitStands` in `decode()` (`src/shared/uniswap.js`). Any step before the permit that may take the permit's token from the sender (a `PERMIT2_TRANSFER_FROM` of that token, a swap step the user pays in it, or a step the decoder does not read) ends the permit's standing, as a later one already does; the `Amount` figure is then the total of the takes, or none. Tests with a `PERMIT2_TRANSFER_FROM` and with a user-paid swap step before the permit, each failing on `next`; Uniswap's own routes read as on `next`.
Model: opus-5-5
Built in #661: a PERMIT2_TRANSFER_FROM of the permit's token before the permit now keeps the permit's amount from standing as the Amount figure. The plan's second test, a user-paid swap step before the permit, was not added: that route already reads as the total on next (reason on the PR).
Model: opus-5-5
Built in https://git.eeqj.de/sneak/AutistMask/pulls/661: a `PERMIT2_TRANSFER_FROM` of the permit's token before the permit now keeps the permit's amount from standing as the `Amount` figure. The plan's second test, a user-paid swap step before the permit, was not added: that route already reads as the total on `next` (reason on the PR).
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.
Seen by the review of #651.
Where
The swap decoder,
decode()insrc/shared/uniswap.js: theAmountfigure when aPERMIT2_PERMITstands (the plain shape of Uniswap's own routes) and aPERMIT2_TRANSFER_FROMof the same token also runs.What happens
A
PERMIT2_TRANSFER_FROMthat runs before the standing permit uses whatever allowance the router already had, so it can move more of the token than the permit's amount. TheAmountfigure is the permit's amount; the transfer's figure appears only on its own lines. TheAmountline can then read lower than what leaves the wallet.What should happen
The approval screen never shows a figure for what leaves the wallet that may be too low: a permit's amount stands as the
Amountfigure only when no other step can take that token from the sender under an allowance the permit does not set; otherwise the figure is the total of the takes, or none.Severity: major
Definition of done
PERMIT2_TRANSFER_FROMof the permit's token before the permit ends the permit's standing, so theAmountfigure is not lower than what may leave.next.Model: opus-5-5
Plan: one PR to
next, inpermitStandsindecode()(src/shared/uniswap.js). Any step before the permit that may take the permit's token from the sender (aPERMIT2_TRANSFER_FROMof that token, a swap step the user pays in it, or a step the decoder does not read) ends the permit's standing, as a later one already does; theAmountfigure is then the total of the takes, or none. Tests with aPERMIT2_TRANSFER_FROMand with a user-paid swap step before the permit, each failing onnext; Uniswap's own routes read as onnext.Model: opus-5-5
Built in #661: a
PERMIT2_TRANSFER_FROMof the permit's token before the permit now keeps the permit's amount from standing as theAmountfigure. The plan's second test, a user-paid swap step before the permit, was not added: that route already reads as the total onnext(reason on the PR).Model: opus-5-5