fix: a zero-minimum balance check never changes the output side (closes #649)
check / check (push) Canceled after 0s
e2e / e2e-chrome (push) Canceled after 0s
e2e / e2e-firefox (push) Canceled after 0s

A BALANCE_CHECK_ERC20 of the sender with a zero minimum guarantees
nothing. It replaced the output side whenever that side held no
minimum, so after an UNWRAP_WETH that drops the minimum, a zero check
of USDC named USDC as Token Out. Such a check now leaves alone an
output side that an earlier step set. It still sets the output side
when no earlier step did. A check with a positive minimum is unchanged.

Model: opus-5-5
This commit is contained in:
2026-10-27 06:57:57 +00:00
parent fc6cffcaba
commit d921bb871b
3 changed files with 44 additions and 15 deletions
+9 -9
View File
@@ -1283,9 +1283,8 @@ see Transaction Decoding), do not always read as a number. They can read:
[#359](https://git.eeqj.de/sneak/AutistMask/issues/359), a zero `minBalance`
read `0.0000` when the token's scale was known. The router passes a balance
check whenever the balance is at least `minBalance`, so a zero `minBalance`
guarantees nothing: it sets `Token Out` and `Min. received` only when the
output side holds no minimum, not even a zero one, at the point the check is
reached, and otherwise leaves the current token and figure in place. A nonzero
guarantees nothing. A check with a zero `minBalance` sets `Token Out` and
`Min. received` only when no earlier step set the output side. A nonzero
`minBalance` sets both lines, as a swap step does. Only a check of the
transaction's sender's own balance sets either line; a check of any other
address sets neither (see Transaction Decoding). A `BALANCE_CHECK_ERC20` step
@@ -3397,12 +3396,13 @@ Currently supported:
`Balance Check (of another address)`. A check whose input does not decode,
such as one whose owner word has a nonzero top byte (the router reads the
owner from the word's last 20 bytes), likewise sets neither, and it is listed
as `Balance Check (could not be decoded)`. When a swap step, `TAKE` or
`TAKE_PORTION` pays the router any token, the swap's output or another, a
`WRAP_ETH` pays it WETH, or an `UNWRAP_WETH` into the router turns WETH a step
paid it into ETH, that token stays in the router unless a later step pays out
or spends all the router holds of it: a `SWEEP` of that token to anyone but
the router, an `UNWRAP_WETH` when it is WETH, a `WRAP_ETH` of
as `Balance Check (could not be decoded)`. A check with a zero `minBalance`
never changes an output side that an earlier step set. When a swap step,
`TAKE` or `TAKE_PORTION` pays the router any token, the swap's output or
another, a `WRAP_ETH` pays it WETH, or an `UNWRAP_WETH` into the router turns
WETH a step paid it into ETH, that token stays in the router unless a later
step pays out or spends all the router holds of it: a `SWEEP` of that token to
anyone but the router, an `UNWRAP_WETH` when it is WETH, a `WRAP_ETH` of
`CONTRACT_BALANCE` when it is ETH, a `TRANSFER` of `CONTRACT_BALANCE`, a
`PAY_PORTION` of 10,000 bips or a `PAY_PORTION_FULL_PRECISION` of 1e18 of that
token to anyone but the router, an `ACROSS_V4_DEPOSIT_V3` of