fix: a PERMIT2_TRANSFER_FROM before a permit keeps its amount from standing as the Amount figure (closes #655) #661

Merged
clawbot merged 1 commits from issue-655-transfer-before-permit into next 2026-10-21 03:16:52 +02:00
Collaborator

Fixes #655.

A PERMIT2_TRANSFER_FROM before a PERMIT2_PERMIT of the same token moves it under whatever allowance the router already had, so it can move more than the permit's amount, yet the permit's amount stood as the Amount figure: 2,000 USDT moved into the router, a permit of 600 USDT and a swap of 2,000 USDT from the router read Amount 600.0000 USDT.

In decode(), the permitStands condition that no step before the permit took its token now also counts each PERMIT2_TRANSFER_FROM of that token, wherever it moves it. The permit then does not stand: Token In and Amount read as with no permit, and the permit gets its own Permit2 allowance lines. README Transaction Decoding states the condition and why.

What a reader may trip over:

  • A PERMIT2_TRANSFER_FROM after the permit, as in Uniswap's own V2 routes, still lets it stand: Permit2 caps it at the permit's amount.
  • Most of the README diff is the formatter rewrapping the rest of that paragraph.

Disclosures:

  • Deviation from the plan: no new test for a user-paid swap step before the permit. That step sets the input side, so the permit already never stands on next; an existing test covers it ("a V3_SWAP_EXACT_OUT of at most 9,400 USDT, then a PERMIT2_PERMIT…").
  • Judgement call: an unread step before the permit ends its standing only when it may take from the sender, as on next.
  • Not run: the browser suites; no popup or browser-test file changed.

Model: opus-5-5

Fixes https://git.eeqj.de/sneak/AutistMask/issues/655. A `PERMIT2_TRANSFER_FROM` before a `PERMIT2_PERMIT` of the same token moves it under whatever allowance the router already had, so it can move more than the permit's amount, yet the permit's amount stood as the `Amount` figure: 2,000 USDT moved into the router, a permit of 600 USDT and a swap of 2,000 USDT from the router read `Amount 600.0000 USDT`. In `decode()`, the `permitStands` condition that no step before the permit took its token now also counts each `PERMIT2_TRANSFER_FROM` of that token, wherever it moves it. The permit then does not stand: `Token In` and `Amount` read as with no permit, and the permit gets its own `Permit2 allowance` lines. README Transaction Decoding states the condition and why. What a reader may trip over: - A `PERMIT2_TRANSFER_FROM` after the permit, as in Uniswap's own V2 routes, still lets it stand: Permit2 caps it at the permit's amount. - Most of the README diff is the formatter rewrapping the rest of that paragraph. Disclosures: - Deviation from the plan: no new test for a user-paid swap step before the permit. That step sets the input side, so the permit already never stands on `next`; an existing test covers it ("a V3_SWAP_EXACT_OUT of at most 9,400 USDT, then a PERMIT2_PERMIT…"). - Judgement call: an unread step before the permit ends its standing only when it may take from the sender, as on `next`. - Not run: the browser suites; no popup or browser-test file changed. Model: opus-5-5
clawbot added the needs-review label 2026-10-21 01:55:23 +02:00
clawbot self-assigned this 2026-10-21 01:55:24 +02:00
Author
Collaborator

Review: FAIL (needs-rework)

  1. tests/uniswap.test.js, the new test.each for #655: only one side of the new condition is tested. No test shows that a PERMIT2_TRANSFER_FROM of the permit's token after the permit still lets the permit's amount stand (the shape of Uniswap's own V2 routes), or that one of another token before the permit does. A change that counted every PERMIT2_TRANSFER_FROM of the token wherever it runs, or one of any token before the permit, would go unnoticed, and Uniswap's own routes would stop reading as on next, which the plan requires. Acceptable: two more rows in which the permit stands (Amount is the permit's, no Permit2 allowance lines): a PERMIT2_PERMIT of 1 WETH, a PERMIT2_TRANSFER_FROM of 1 WETH to the V2 pair and a V2 exact-in of ALREADY_PAID; and a PERMIT2_TRANSFER_FROM of 400 DAI to another address, then a PERMIT2_PERMIT of 600 USDT and a V3 exact-in of 600 USDT.

Not run: the browser suites; no popup or browser-test file changed.

Model: opus-5-5

**Review: FAIL (`needs-rework`)** 1. `tests/uniswap.test.js`, the new `test.each` for https://git.eeqj.de/sneak/AutistMask/issues/655: only one side of the new condition is tested. No test shows that a `PERMIT2_TRANSFER_FROM` of the permit's token after the permit still lets the permit's amount stand (the shape of Uniswap's own V2 routes), or that one of another token before the permit does. A change that counted every `PERMIT2_TRANSFER_FROM` of the token wherever it runs, or one of any token before the permit, would go unnoticed, and Uniswap's own routes would stop reading as on `next`, which the plan requires. Acceptable: two more rows in which the permit stands (`Amount` is the permit's, no `Permit2 allowance` lines): a `PERMIT2_PERMIT` of 1 WETH, a `PERMIT2_TRANSFER_FROM` of 1 WETH to the V2 pair and a V2 exact-in of `ALREADY_PAID`; and a `PERMIT2_TRANSFER_FROM` of 400 DAI to another address, then a `PERMIT2_PERMIT` of 600 USDT and a V3 exact-in of 600 USDT. Not run: the browser suites; no popup or browser-test file changed. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-21 02:36:27 +02:00
clawbot added 1 commit 2026-10-21 02:47:06 +02:00
fix: a PERMIT2_TRANSFER_FROM before a permit keeps its amount from standing as the Amount figure (closes #655)
check / check (push) Waiting to run
e2e / e2e-chrome (push) Waiting to run
e2e / e2e-firefox (push) Waiting to run
c9b6cebbf8
A PERMIT2_TRANSFER_FROM that runs before a PERMIT2_PERMIT of the same
token moves it under whatever allowance the router already had, so it
can move more than the permit's amount. The permit's amount still stood
as the Amount figure, which could then read lower than what leaves the
wallet.

decode() now counts such a transfer, into the router or anywhere else,
among the steps before the permit that took its token, so the permit no
longer stands: the Amount line gives the total the steps take, as with
no permit, and the permit gets its own lines. A transfer after the
permit, or of another token before it, still lets it stand; tests cover
both. README Transaction Decoding states the condition.

Model: opus-5-5
clawbot force-pushed issue-655-transfer-before-permit from e729331055 to c9b6cebbf8 2026-10-21 02:47:06 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-10-21 02:50:57 +02:00
Author
Collaborator

Added the two rows to the new test.each in tests/uniswap.test.js in which the permit's amount stands: a PERMIT2_PERMIT of 1 WETH, then a PERMIT2_TRANSFER_FROM of 1 WETH to the V2 pair and a V2 exact-in of ALREADY_PAID; and a PERMIT2_TRANSFER_FROM of 400 DAI to another address, then a PERMIT2_PERMIT of 600 USDT and a V3 exact-in of 600 USDT.

Model: opus-5-5

Added the two rows to the new `test.each` in `tests/uniswap.test.js` in which the permit's amount stands: a `PERMIT2_PERMIT` of 1 WETH, then a `PERMIT2_TRANSFER_FROM` of 1 WETH to the V2 pair and a V2 exact-in of `ALREADY_PAID`; and a `PERMIT2_TRANSFER_FROM` of 400 DAI to another address, then a `PERMIT2_PERMIT` of 600 USDT and a V3 exact-in of 600 USDT. Model: opus-5-5
Author
Collaborator

Review: PASS

Model: opus-5-5

**Review: PASS** Model: opus-5-5
clawbot merged commit 5f2b606754 into next 2026-10-21 03:16:52 +02:00
clawbot deleted branch issue-655-transfer-before-permit 2026-10-21 03:16:52 +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#661