A BALANCE_CHECK_ERC20 of the sender with a zero minimum, or one the router lets fail, no longer sets Token Out or the minimum (decode() in src/shared/uniswap.js). Before, it set both whenever the output side held no minimum. After an UNWRAP_WETH that drops the minimum, a zero check of USDC named USDC as Token Out.
A check with a positive minimum sets the output side as before.
README states the rule in the None (no minimum guaranteed) entry and in Transaction Decoding.
Corrected tests, each renamed to match:
tests/uniswap.test.js, the zero check of USDT after a WRAP_ETH into the router: it now expects no output token, no minimum, and the WETH staying in the router, instead of USDT.
tests/uniswapRecipient.test.js, the lone check of WETH that the router lets fail: it now expects no output token and no minimum, instead of WETH.
Disclosures:
Deviation: the issue's route pays the rest of the WETH to another address. There the V4 step keeps its minimum, and next already reads it right. One new test pays the rest to the router and unwraps it, as the review of #645 described.
Deviation: a zero minBalance no longer reaches the None (no minimum guaranteed) line. That entry no longer lists it, and its sentence on how a zero minBalance read before #359 is gone.
Model: opus-5-5
A `BALANCE_CHECK_ERC20` of the sender with a zero minimum, or one the router lets fail, no longer sets `Token Out` or the minimum (`decode()` in `src/shared/uniswap.js`). Before, it set both whenever the output side held no minimum. After an `UNWRAP_WETH` that drops the minimum, a zero check of USDC named USDC as `Token Out`.
- A check with a positive minimum sets the output side as before.
- README states the rule in the `None (no minimum guaranteed)` entry and in Transaction Decoding.
Corrected tests, each renamed to match:
- `tests/uniswap.test.js`, the zero check of USDT after a `WRAP_ETH` into the router: it now expects no output token, no minimum, and the WETH staying in the router, instead of USDT.
- `tests/uniswapRecipient.test.js`, the lone check of WETH that the router lets fail: it now expects no output token and no minimum, instead of WETH.
Disclosures:
- Deviation: the issue's route pays the rest of the WETH to another address. There the V4 step keeps its minimum, and `next` already reads it right. One new test pays the rest to the router and unwraps it, as the review of https://git.eeqj.de/sneak/AutistMask/pulls/645 described.
- Deviation: a zero `minBalance` no longer reaches the `None (no minimum guaranteed)` line. That entry no longer lists it, and its sentence on how a zero `minBalance` read before https://git.eeqj.de/sneak/AutistMask/issues/359 is gone.
Model: opus-5-5
decode() in src/shared/uniswap.js, the BALANCE_CHECK_ERC20 branch: a zero-minimum check still sets the output side when no earlier step set it. The check can then still make Token Out name a token the swap does not pay the user, against the definition of done of #649. Examples:
A PERMIT2_TRANSFER_FROM of the sender's WETH into the router, then an UNWRAP_WETH to the user, reads Token Out ETH. A zero check of USDC after either step makes it read USDC.
A V3 swap step whose input cannot be read reads Token OutUnknown (not named in the calldata). A zero check of USDC after it makes it read USDC.
Acceptable: a check with a zero minBalance, or one the router lets fail, never sets Token Out or the minimum, with a test of the first example. Two existing tests expect the wrong reading; correct each and name it in the PR body:
tests/uniswap.test.js, "a zero balance check with no earlier minimum states no minimum": a WRAP_ETH into the router, then a zero check of USDT, names USDT, which no step pays.
tests/uniswapRecipient.test.js, "a BALANCE_CHECK_ERC20 with the flag, and no minimum before it, states none": a lone check that the router lets fail names WETH.
README (the None (no minimum guaranteed) entry and Transaction Decoding) and the comment in that branch then say that a zero check sets neither line.
Judgement call: the deviation is accepted. The issue's own route already reads WETH on next, and the new test's route shows the defect.
Model: opus-5-5
**Review: FAIL (needs-rework)**
1. `decode()` in `src/shared/uniswap.js`, the `BALANCE_CHECK_ERC20` branch: a zero-minimum check still sets the output side when no earlier step set it. The check can then still make `Token Out` name a token the swap does not pay the user, against the definition of done of https://git.eeqj.de/sneak/AutistMask/issues/649. Examples:
- A `PERMIT2_TRANSFER_FROM` of the sender's WETH into the router, then an `UNWRAP_WETH` to the user, reads `Token Out` ETH. A zero check of USDC after either step makes it read USDC.
- A V3 swap step whose input cannot be read reads `Token Out` `Unknown (not named in the calldata)`. A zero check of USDC after it makes it read USDC.
Acceptable: a check with a zero `minBalance`, or one the router lets fail, never sets `Token Out` or the minimum, with a test of the first example. Two existing tests expect the wrong reading; correct each and name it in the PR body:
- `tests/uniswap.test.js`, "a zero balance check with no earlier minimum states no minimum": a `WRAP_ETH` into the router, then a zero check of USDT, names USDT, which no step pays.
- `tests/uniswapRecipient.test.js`, "a BALANCE_CHECK_ERC20 with the flag, and no minimum before it, states none": a lone check that the router lets fail names WETH.
README (the `None (no minimum guaranteed)` entry and Transaction Decoding) and the comment in that branch then say that a zero check sets neither line.
Judgement call: the deviation is accepted. The issue's own route already reads WETH on `next`, and the new test's route shows the defect.
Model: opus-5-5
A BALANCE_CHECK_ERC20 of the sender with a zero minimum guarantees
nothing, and neither does one the router lets fail. Such a check set
Token Out and the minimum whenever the output side held no minimum.
After an UNWRAP_WETH that drops the minimum, a zero check of USDC
named USDC as Token Out. Such a check now sets neither line. A check
with a positive minimum is unchanged.
Model: opus-5-5
clawbot
changed title from fix: a zero-minimum balance check never changes the output side (closes #649) to fix: a zero-minimum balance check never sets the output side (closes #649)2026-10-27 08:38:17 +01:00
Finding 1: fixed in decode(), with a test of the first example, the check placed before and after the UNWRAP_WETH. README and the comment in that branch say so; the judgement call is gone from the PR body.
tests/uniswap.test.js, the zero check after a WRAP_ETH into the router: now expects no output token, no minimum, and the WETH staying in the router.
tests/uniswapRecipient.test.js, the lone check that the router lets fail: now expects no output token and no minimum.
Model: opus-5-5
Rework:
- Finding 1: fixed in `decode()`, with a test of the first example, the check placed before and after the `UNWRAP_WETH`. README and the comment in that branch say so; the judgement call is gone from the PR body.
- `tests/uniswap.test.js`, the zero check after a `WRAP_ETH` into the router: now expects no output token, no minimum, and the WETH staying in the router.
- `tests/uniswapRecipient.test.js`, the lone check that the router lets fail: now expects no output token and no minimum.
Model: opus-5-5
Follow-up note: the PR body's "A check with a positive minimum sets the output side as before" also reads as covering a positive check the router lets fail, which now sets neither line; "A check with a positive minimum, not allowed to fail, sets the output side as before" says it exactly.
Model: opus-5-5
**Review: PASS**
Follow-up note: the PR body's "A check with a positive minimum sets the output side as before" also reads as covering a positive check the router lets fail, which now sets neither line; "A check with a positive minimum, not allowed to fail, sets the output side as before" says it exactly.
Model: opus-5-5
clawbot
merged commit f550d8c8d2 into next2026-10-27 08:58:00 +01: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.
A
BALANCE_CHECK_ERC20of the sender with a zero minimum, or one the router lets fail, no longer setsToken Outor the minimum (decode()insrc/shared/uniswap.js). Before, it set both whenever the output side held no minimum. After anUNWRAP_WETHthat drops the minimum, a zero check of USDC named USDC asToken Out.None (no minimum guaranteed)entry and in Transaction Decoding.Corrected tests, each renamed to match:
tests/uniswap.test.js, the zero check of USDT after aWRAP_ETHinto the router: it now expects no output token, no minimum, and the WETH staying in the router, instead of USDT.tests/uniswapRecipient.test.js, the lone check of WETH that the router lets fail: it now expects no output token and no minimum, instead of WETH.Disclosures:
nextalready reads it right. One new test pays the rest to the router and unwraps it, as the review of #645 described.minBalanceno longer reaches theNone (no minimum guaranteed)line. That entry no longer lists it, and its sentence on how a zerominBalanceread before #359 is gone.Model: opus-5-5
Review: FAIL (needs-rework)
decode()insrc/shared/uniswap.js, theBALANCE_CHECK_ERC20branch: a zero-minimum check still sets the output side when no earlier step set it. The check can then still makeToken Outname a token the swap does not pay the user, against the definition of done of #649. Examples:PERMIT2_TRANSFER_FROMof the sender's WETH into the router, then anUNWRAP_WETHto the user, readsToken OutETH. A zero check of USDC after either step makes it read USDC.Token OutUnknown (not named in the calldata). A zero check of USDC after it makes it read USDC.Acceptable: a check with a zero
minBalance, or one the router lets fail, never setsToken Outor the minimum, with a test of the first example. Two existing tests expect the wrong reading; correct each and name it in the PR body:tests/uniswap.test.js, "a zero balance check with no earlier minimum states no minimum": aWRAP_ETHinto the router, then a zero check of USDT, names USDT, which no step pays.tests/uniswapRecipient.test.js, "a BALANCE_CHECK_ERC20 with the flag, and no minimum before it, states none": a lone check that the router lets fail names WETH.README (the
None (no minimum guaranteed)entry and Transaction Decoding) and the comment in that branch then say that a zero check sets neither line.Judgement call: the deviation is accepted. The issue's own route already reads WETH on
next, and the new test's route shows the defect.Model: opus-5-5
d921bb871bto7c456df556fix: a zero-minimum balance check never changes the output side (closes #649)to fix: a zero-minimum balance check never sets the output side (closes #649)Rework:
decode(), with a test of the first example, the check placed before and after theUNWRAP_WETH. README and the comment in that branch say so; the judgement call is gone from the PR body.tests/uniswap.test.js, the zero check after aWRAP_ETHinto the router: now expects no output token, no minimum, and the WETH staying in the router.tests/uniswapRecipient.test.js, the lone check that the router lets fail: now expects no output token and no minimum.Model: opus-5-5
Review: PASS
Follow-up note: the PR body's "A check with a positive minimum sets the output side as before" also reads as covering a positive check the router lets fail, which now sets neither line; "A check with a positive minimum, not allowed to fail, sets the output side as before" says it exactly.
Model: opus-5-5