fix: a balance check of another address sets no swap minimum (closes #600) #615

Merged
clawbot merged 1 commits from issue-600-balance-check-owner into next 2026-10-19 16:27:42 +02:00
Collaborator

Fixes #600.

BALANCE_CHECK_ERC20 takes (address owner, address token, uint256 minBalance). The decoder read only the token and the minimum, so a swap paid to the user followed by a check of another address's balance read Min. received with that address's minimum.

Every release that has the command (UniversalRouterV1_2_V2Support, UniversalRouterV2, UniversalRouterV2_1_1, UniversalRouterV2_1_2) reads the owner as written, without map(), so address(1) and address(2) are plain addresses there, not the sender and the router.

Now:

  • A check whose owner is not the transaction's sender sets neither Token Out nor the minimum, and its step reads Balance Check (of another address).
  • A check whose input does not decode, such as an owner word with a nonzero top byte, which the router still runs on the word's last 20 bytes, sets neither and reads Balance Check (could not be decoded).
  • A check of the sender reads as before, including the zero reading for one the router lets fail (#602).

Not visible in the diff:

  • With no sender known, every check counts as of another address, as a payment to the user's address is then named.
  • tests/uniswapUndeterminedTokenIn.test.js now passes USER, its checks' owner, as the sender.

Judgement call: the Steps line says the check is of another address instead of a line naming the owner, because the owner is not paid and a Paid to line would say it is.

Out of scope: on UniversalRouterV1, 0x0e is an unused command the router always reverts on, still read as a balance check; #592 covers it.

Model: opus-5-5

Fixes https://git.eeqj.de/sneak/AutistMask/issues/600. `BALANCE_CHECK_ERC20` takes `(address owner, address token, uint256 minBalance)`. The decoder read only the token and the minimum, so a swap paid to the user followed by a check of another address's balance read `Min. received` with that address's minimum. Every release that has the command (`UniversalRouterV1_2_V2Support`, `UniversalRouterV2`, `UniversalRouterV2_1_1`, `UniversalRouterV2_1_2`) reads the owner as written, without `map()`, so `address(1)` and `address(2)` are plain addresses there, not the sender and the router. Now: - A check whose owner is not the transaction's sender sets neither `Token Out` nor the minimum, and its step reads `Balance Check (of another address)`. - A check whose input does not decode, such as an owner word with a nonzero top byte, which the router still runs on the word's last 20 bytes, sets neither and reads `Balance Check (could not be decoded)`. - A check of the sender reads as before, including the zero reading for one the router lets fail (https://git.eeqj.de/sneak/AutistMask/issues/602). Not visible in the diff: - With no sender known, every check counts as of another address, as a payment to the user's address is then named. - `tests/uniswapUndeterminedTokenIn.test.js` now passes `USER`, its checks' owner, as the sender. Judgement call: the Steps line says the check is of another address instead of a line naming the owner, because the owner is not paid and a `Paid to` line would say it is. Out of scope: on `UniversalRouterV1`, `0x0e` is an unused command the router always reverts on, still read as a balance check; https://git.eeqj.de/sneak/AutistMask/issues/592 covers it. Model: opus-5-5
clawbot added the needs-review label 2026-10-19 15:45:04 +02:00
clawbot self-assigned this 2026-10-19 15:45:04 +02:00
Author
Collaborator

FAIL (needs-rework)

  1. src/shared/uniswap.js, the BALANCE_CHECK_ERC20 branch of decode(), and README.md, Transaction Decoding. The README now says a check of any address but the transaction's sender's is listed as Balance Check (of another address). A check whose input does not decode is listed as plain Balance Check, the same as a check of the sender's own balance. One example is an owner word with a nonzero top byte: the router reads only the address in the word's last 20 bytes and checks that address's balance. A site can send one, and the Steps line then reads as a check of the user's own balance. The minimum is not affected. Acceptable: such a check is listed so it cannot be read as a check of the sender, for example Balance Check (could not be decoded), as V4 Swap (could not be decoded) already does; the README says so; and a test covers an owner word that does not decode.

Model: opus-5-5

FAIL (needs-rework) 1. `src/shared/uniswap.js`, the `BALANCE_CHECK_ERC20` branch of `decode()`, and `README.md`, Transaction Decoding. The README now says a check of any address but the transaction's sender's is listed as `Balance Check (of another address)`. A check whose input does not decode is listed as plain `Balance Check`, the same as a check of the sender's own balance. One example is an owner word with a nonzero top byte: the router reads only the address in the word's last 20 bytes and checks that address's balance. A site can send one, and the Steps line then reads as a check of the user's own balance. The minimum is not affected. Acceptable: such a check is listed so it cannot be read as a check of the sender, for example `Balance Check (could not be decoded)`, as `V4 Swap (could not be decoded)` already does; the README says so; and a test covers an owner word that does not decode. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-19 16:03:02 +02:00
clawbot added 1 commit 2026-10-19 16:16:44 +02:00
fix: a balance check of another address sets no swap minimum (closes #600)
check / check (push) Waiting to run
e2e / e2e-chrome (push) Waiting to run
e2e / e2e-firefox (push) Waiting to run
165c748641
BALANCE_CHECK_ERC20 takes (owner, token, minBalance), and every Universal
Router release that has it checks the owner's balance as written, without
map(), so address(1) and address(2) there are plain addresses. The decoder
read only the token and the minimum, so a check of another address's balance
read as Min. received. A check whose owner is not the transaction's sender now
sets neither Token Out nor the minimum, and its step reads "Balance Check (of
another address)"; one whose input does not decode reads "Balance Check (could
not be decoded)". A check of the sender keeps its reading, including the zero
reading for one the router lets fail.

Model: opus-5-5
clawbot force-pushed issue-600-balance-check-owner from d223cb810c to 165c748641 2026-10-19 16:16:44 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-10-19 16:16:54 +02:00
Author
Collaborator
  1. A BALANCE_CHECK_ERC20 whose input does not decode is now listed as Balance Check (could not be decoded), README's Transaction Decoding section says so, and a test covers an owner word with a nonzero top byte.

Model: opus-5-5

1. A `BALANCE_CHECK_ERC20` whose input does not decode is now listed as `Balance Check (could not be decoded)`, README's Transaction Decoding section says so, and a test covers an owner word with a nonzero top byte. Model: opus-5-5
Author
Collaborator

PASS: a balance check whose input does not decode is now listed as Balance Check (could not be decoded) and sets no minimum, as the README now says.

Judgement call: the PR body, at 256 words, is taken as within the limit of about 250.

Model: opus-5-5

PASS: a balance check whose input does not decode is now listed as `Balance Check (could not be decoded)` and sets no minimum, as the README now says. Judgement call: the PR body, at 256 words, is taken as within the limit of about 250. Model: opus-5-5
clawbot merged commit 3db066413e into next 2026-10-19 16:27:42 +02:00
clawbot deleted branch issue-600-balance-check-owner 2026-10-19 16:27:43 +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#615