The decoder read every command's type from the low five bits of its byte, so EXECUTE_SUB_PLAN (0x21) was listed as V3 Swap (Exact Out), with or without the allow-revert flag (0xa1).
In src/shared/uniswap.js:
Each router address in the list carries the mask that router reads a command's type with, and decode() uses the mask of the address the transaction is sent to. The comment above the list links each mask to its router release.
An EXECUTE_SUB_PLAN step is listed as Execute Sub-Plan (its steps are not shown). Its commands are still not read.
With such a step, wherever it stands, the summary names no swap direction, Token In and Token Out read Unknown (could not be decoded), and there is no Amount or Min. received line. Its commands may spend the user's tokens or pay the user before or after the other steps, and a permit among them would replace the input side.
README's Transaction Decoding text says the same.
Judgement call: one mask per address (0x1f for UniversalRouterV1, 0x3f for UniversalRouterV1_2_V2Support and UniversalRouterV2, 0x7f for UniversalRouterV2_1_1 and UniversalRouterV2_1_2) instead of the single 0x3f the issue names, since any single mask misnames commands on some of them.
Judgement call: beside a sub-plan all four lines are withheld, not only the side at its end of the step list.
Left as it was: the older routers' NFT commands, #592.
Model: opus-5-5
Fixes https://git.eeqj.de/sneak/AutistMask/issues/535.
The decoder read every command's type from the low five bits of its byte, so `EXECUTE_SUB_PLAN` (`0x21`) was listed as `V3 Swap (Exact Out)`, with or without the allow-revert flag (`0xa1`).
In `src/shared/uniswap.js`:
- Each router address in the list carries the mask that router reads a command's type with, and `decode()` uses the mask of the address the transaction is sent to. The comment above the list links each mask to its router release.
- An `EXECUTE_SUB_PLAN` step is listed as `Execute Sub-Plan (its steps are not shown)`. Its commands are still not read.
- With such a step, wherever it stands, the summary names no swap direction, `Token In` and `Token Out` read `Unknown (could not be decoded)`, and there is no `Amount` or `Min. received` line. Its commands may spend the user's tokens or pay the user before or after the other steps, and a permit among them would replace the input side.
README's Transaction Decoding text says the same.
- Judgement call: one mask per address (`0x1f` for `UniversalRouterV1`, `0x3f` for `UniversalRouterV1_2_V2Support` and `UniversalRouterV2`, `0x7f` for `UniversalRouterV2_1_1` and `UniversalRouterV2_1_2`) instead of the single `0x3f` the issue names, since any single mask misnames commands on some of them.
- Judgement call: beside a sub-plan all four lines are withheld, not only the side at its end of the step list.
- Left as it was: the older routers' NFT commands, https://git.eeqj.de/sneak/AutistMask/issues/592.
Model: opus-5-5
clawbot
self-assigned this 2026-10-19 05:47:11 +02:00
src/shared/uniswap.jsdecode() (lines 689 and 818–920): the second item of the definition of done in #535 is not met. When a sub-plan sits beside a swap step the decoder does read, the swap direction and the Token In, Amount, Token Out and Min. received lines come only from the steps outside the sub-plan, and they are shown as the whole swap. Only the Steps line mentions the sub-plan. Two examples:
A V3 swap of 2,000 USDT for at least 1 WETH, paid to the router, followed by a sub-plan that swaps that WETH for USDC, reads Swap USDT → WETH with Min. received 1.0000 WETH. None of that WETH reaches the user.
A sub-plan that buys WETH with the user's USDC, followed by a swap of 1 WETH for DAI, reads Token In WETH and Amount 1.0000 WETH, but the user pays USDC.
The new check changes only the wording of a side that no step named. Acceptable: while a sub-plan is not read, neither the swap direction nor any of those four lines presents the steps outside it as the whole swap. Each line that the sub-plan's steps can change either says that it leaves those steps out, or is withheld with the could-not-be-decoded wording. A V4 step whose swap action could not be read already does this for the output side. Add tests for a swap before a sub-plan and a swap after one. The test at tests/uniswap.test.js:965 expects an unqualified Amount beside a sub-plan and changes with this. So does the README sentence at line 2900, "what those commands spend or receive is missing from the other lines".
tests/uniswap.test.js:871: the comment contains a literal —. A comment does not decode escape sequences, so it shows those six characters. Acceptable: write the dash itself, as the file's other comments do.
PR body: it runs past 250 words. Acceptable: keep it under about 250 words when it is rewritten for the rework.
Judgement call: I accepted one mask per router address in place of the single 0x3f the issue names. Each mask matches the source verified at that address.
Model: opus-5-5
**FAIL: needs-rework**
1. **`src/shared/uniswap.js` `decode()` (lines 689 and 818–920): the second item of the definition of done in https://git.eeqj.de/sneak/AutistMask/issues/535 is not met.** When a sub-plan sits beside a swap step the decoder does read, the swap direction and the `Token In`, `Amount`, `Token Out` and `Min. received` lines come only from the steps outside the sub-plan, and they are shown as the whole swap. Only the `Steps` line mentions the sub-plan. Two examples:
- A V3 swap of 2,000 USDT for at least 1 WETH, paid to the router, followed by a sub-plan that swaps that WETH for USDC, reads `Swap USDT → WETH` with `Min. received 1.0000 WETH`. None of that WETH reaches the user.
- A sub-plan that buys WETH with the user's USDC, followed by a swap of 1 WETH for DAI, reads `Token In` WETH and `Amount 1.0000 WETH`, but the user pays USDC.
The new check changes only the wording of a side that no step named. Acceptable: while a sub-plan is not read, neither the swap direction nor any of those four lines presents the steps outside it as the whole swap. Each line that the sub-plan's steps can change either says that it leaves those steps out, or is withheld with the could-not-be-decoded wording. A V4 step whose swap action could not be read already does this for the output side. Add tests for a swap before a sub-plan and a swap after one. The test at `tests/uniswap.test.js:965` expects an unqualified `Amount` beside a sub-plan and changes with this. So does the README sentence at line 2900, "what those commands spend or receive is missing from the other lines".
2. **`tests/uniswap.test.js:871`: the comment contains a literal `—`.** A comment does not decode escape sequences, so it shows those six characters. Acceptable: write the dash itself, as the file's other comments do.
3. **PR body: it runs past 250 words.** Acceptable: keep it under about 250 words when it is rewritten for the rework.
Judgement call: I accepted one mask per router address in place of the single `0x3f` the issue names. Each mask matches the source verified at that address.
Model: opus-5-5
With an EXECUTE_SUB_PLAN step, wherever it stands, decode() now names no swap direction, Token In and Token Out read Unknown (could not be decoded), and there is no Amount or Min. received; tests cover a swap before and after a sub-plan, the permit test now expects the same, and the README sentence is rewritten.
The comment now has the dash itself.
PR body rewritten under 250 words.
Model: opus-5-5
1. With an `EXECUTE_SUB_PLAN` step, wherever it stands, `decode()` now names no swap direction, `Token In` and `Token Out` read `Unknown (could not be decoded)`, and there is no `Amount` or `Min. received`; tests cover a swap before and after a sub-plan, the permit test now expects the same, and the README sentence is rewritten.
2. The comment now has the dash itself.
3. PR body rewritten under 250 words.
Model: opus-5-5
tests/uniswap.test.js, the new EXECUTE_SUB_PLAN tests: nothing tests a sub-plan beside an UNWRAP_WETH step. In src/shared/uniswap.jsdecode(), the outputEstablished = true; line in the if (hasSubPlan) block is the only thing that keeps an unwrap step from making Token Out read ETH beside a sub-plan. No test covers that line, so it can be dropped with every test still passing, and the screen would then name ETH as what the user receives on the strength of a step outside the sub-plan. That is the case the definition of done in #535 and the first review's first finding rule out. Acceptable: a test of a sub-plan with an UNWRAP_WETH step that expects Token Out to read Unknown (could not be decoded).
Model: opus-5-5
**FAIL: needs-rework**
1. **`tests/uniswap.test.js`, the new `EXECUTE_SUB_PLAN` tests: nothing tests a sub-plan beside an `UNWRAP_WETH` step.** In `src/shared/uniswap.js` `decode()`, the `outputEstablished = true;` line in the `if (hasSubPlan)` block is the only thing that keeps an unwrap step from making `Token Out` read `ETH` beside a sub-plan. No test covers that line, so it can be dropped with every test still passing, and the screen would then name ETH as what the user receives on the strength of a step outside the sub-plan. That is the case the definition of done in https://git.eeqj.de/sneak/AutistMask/issues/535 and the first review's first finding rule out. Acceptable: a test of a sub-plan with an `UNWRAP_WETH` step that expects `Token Out` to read `Unknown (could not be decoded)`.
Model: opus-5-5
Each Universal Router address now carries the mask its own source reads a
command's type with: 0x1f for UniversalRouterV1, 0x3f for V1_2 and V2, 0x7f
for V2_1_1 and V2_1_2. The fixed 0x1f dropped the 0x20 bit, so
EXECUTE_SUB_PLAN (0x21) was listed as a V3 exact-out swap. A sub-plan step is
now listed as "Execute Sub-Plan (its steps are not shown)". Its commands are
not read and may spend from or pay the user wherever the step stands, so with
one the summary names no swap direction, Token In and Token Out read
"Unknown (could not be decoded)", and there is no Amount or Min. received.
Model: opus-5-5
Added a test of a sub-plan followed by an UNWRAP_WETH step that expects Token Out to read Unknown (could not be decoded); it fails when outputEstablished = true; is removed from the if (hasSubPlan) block, and each other line in that block was already covered by a test.
Model: opus-5-5
1. Added a test of a sub-plan followed by an `UNWRAP_WETH` step that expects `Token Out` to read `Unknown (could not be decoded)`; it fails when `outputEstablished = true;` is removed from the `if (hasSubPlan)` block, and each other line in that block was already covered by a test.
Model: opus-5-5
PASS: the new test of a sub-plan followed by an UNWRAP_WETH step closes the gap the second review found, so every line that resets the summary beside a sub-plan is now held by a test.
Scope: what changed since acb2d00 (one test, no source change), plus the full gate; the rest was passed by the second review.
Model: opus-5-5
**PASS**: the new test of a sub-plan followed by an `UNWRAP_WETH` step closes the gap the second review found, so every line that resets the summary beside a sub-plan is now held by a test.
Scope: what changed since `acb2d00` (one test, no source change), plus the full gate; the rest was passed by the second review.
Model: opus-5-5
clawbot
merged commit b5d2cedb57 into next2026-10-19 07:13:23 +02:00
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.
Fixes #535.
The decoder read every command's type from the low five bits of its byte, so
EXECUTE_SUB_PLAN(0x21) was listed asV3 Swap (Exact Out), with or without the allow-revert flag (0xa1).In
src/shared/uniswap.js:decode()uses the mask of the address the transaction is sent to. The comment above the list links each mask to its router release.EXECUTE_SUB_PLANstep is listed asExecute Sub-Plan (its steps are not shown). Its commands are still not read.Token InandToken OutreadUnknown (could not be decoded), and there is noAmountorMin. receivedline. Its commands may spend the user's tokens or pay the user before or after the other steps, and a permit among them would replace the input side.README's Transaction Decoding text says the same.
0x1fforUniversalRouterV1,0x3fforUniversalRouterV1_2_V2SupportandUniversalRouterV2,0x7fforUniversalRouterV2_1_1andUniversalRouterV2_1_2) instead of the single0x3fthe issue names, since any single mask misnames commands on some of them.Model: opus-5-5
clawbot referenced this pull request2026-10-19 05:48:32 +02:00
FAIL: needs-rework
src/shared/uniswap.jsdecode()(lines 689 and 818–920): the second item of the definition of done in #535 is not met. When a sub-plan sits beside a swap step the decoder does read, the swap direction and theToken In,Amount,Token OutandMin. receivedlines come only from the steps outside the sub-plan, and they are shown as the whole swap. Only theStepsline mentions the sub-plan. Two examples:Swap USDT → WETHwithMin. received 1.0000 WETH. None of that WETH reaches the user.Token InWETH andAmount 1.0000 WETH, but the user pays USDC.The new check changes only the wording of a side that no step named. Acceptable: while a sub-plan is not read, neither the swap direction nor any of those four lines presents the steps outside it as the whole swap. Each line that the sub-plan's steps can change either says that it leaves those steps out, or is withheld with the could-not-be-decoded wording. A V4 step whose swap action could not be read already does this for the output side. Add tests for a swap before a sub-plan and a swap after one. The test at
tests/uniswap.test.js:965expects an unqualifiedAmountbeside a sub-plan and changes with this. So does the README sentence at line 2900, "what those commands spend or receive is missing from the other lines".tests/uniswap.test.js:871: the comment contains a literal—. A comment does not decode escape sequences, so it shows those six characters. Acceptable: write the dash itself, as the file's other comments do.PR body: it runs past 250 words. Acceptable: keep it under about 250 words when it is rewritten for the rework.
Judgement call: I accepted one mask per router address in place of the single
0x3fthe issue names. Each mask matches the source verified at that address.Model: opus-5-5
da6ca45450toacb2d00b5aEXECUTE_SUB_PLANstep, wherever it stands,decode()now names no swap direction,Token InandToken OutreadUnknown (could not be decoded), and there is noAmountorMin. received; tests cover a swap before and after a sub-plan, the permit test now expects the same, and the README sentence is rewritten.Model: opus-5-5
FAIL: needs-rework
tests/uniswap.test.js, the newEXECUTE_SUB_PLANtests: nothing tests a sub-plan beside anUNWRAP_WETHstep. Insrc/shared/uniswap.jsdecode(), theoutputEstablished = true;line in theif (hasSubPlan)block is the only thing that keeps an unwrap step from makingToken OutreadETHbeside a sub-plan. No test covers that line, so it can be dropped with every test still passing, and the screen would then name ETH as what the user receives on the strength of a step outside the sub-plan. That is the case the definition of done in #535 and the first review's first finding rule out. Acceptable: a test of a sub-plan with anUNWRAP_WETHstep that expectsToken Outto readUnknown (could not be decoded).Model: opus-5-5
acb2d00b5ato5b8fc1e738UNWRAP_WETHstep that expectsToken Outto readUnknown (could not be decoded); it fails whenoutputEstablished = true;is removed from theif (hasSubPlan)block, and each other line in that block was already covered by a test.Model: opus-5-5
PASS: the new test of a sub-plan followed by an
UNWRAP_WETHstep closes the gap the second review found, so every line that resets the summary beside a sub-plan is now held by a test.Scope: what changed since
acb2d00(one test, no source change), plus the full gate; the rest was passed by the second review.Model: opus-5-5