docs: name every approval-screen amount string, fix stale zero claim (closes #369)
check / check (push) Successful in 3m37s
e2e / e2e-chrome (push) Successful in 4m19s
e2e / e2e-firefox (push) Successful in 4m7s

The README said a genuine zero always renders `0.0000`, beside a
`Min. received` example that now reads `None (no minimum guaranteed)`.
It now names the two zeros stated in words: any zero `Min. received`,
and an `Amount` line showing a V4 exact-in `amountIn` of zero. That
line shows the amount of the last `PERMIT2_PERMIT` step if there is
any, otherwise of the first V2/V3 exact-in, `WRAP_ETH` or V4 swap step,
where a V4 swap step uses its first exact-in action.

A new list names every string an amount slot can show, including a
known-scale zero as `0.0000` and `Unlimited` for the router's
whole-balance value. A zero `BALANCE_CHECK_ERC20` `minBalance` is noted
as now reading the no-minimum wording.

Model: opus-5-5
This commit is contained in:
2026-10-04 00:29:02 +00:00
parent 6c70a82de8
commit d84e53a1b1
2 changed files with 74 additions and 3 deletions
+56 -3
View File
@@ -882,9 +882,19 @@ On those screens, when the truncated string would contain no digit from 1 to 9
and the value does, the amount is extended to its first significant digit and the value does, the amount is extended to its first significant digit
instead: `0.000000000000000001 DAI`, not `0.0000 DAI`. The test is on the whole instead: `0.000000000000000001 DAI`, not `0.0000 DAI`. The test is on the whole
truncated string, integer part included, so `1.00005` still shows as `1.0000` — truncated string, integer part included, so `1.00005` still shows as `1.0000` —
the exception only fires where the entire displayed figure would read as zero. A the exception only fires where the entire displayed figure would read as zero.
genuine zero still renders `0.0000`, and truncation stays truncation: `0.99999` Truncation stays truncation: `0.99999` shows as `0.9999`, never rounded up. A
shows as `0.9999`, never rounded up. genuine zero reaching this rule renders `0.0000`. The swap screen states a zero
in words before it gets here in only two places. Its `Min. received` line reads
`None (no minimum guaranteed)` for any zero minimum. Its `Amount` line reads
`All available (V4 open delta)` when the amount it shows is a V4 exact-in
`amountIn` of zero, which V4 treats as the whole open credit rather than a
quantity. That line shows the amount of one step: the last `PERMIT2_PERMIT` step
if there is any (a `Permit2 Permit Batch` step does not count), otherwise the
first V2 or V3 exact-in, `WRAP_ETH` or V4 swap step, where a V4 swap step gives
the `amountIn` of its first exact-in action. Every other zero amount with a
known scale renders `0.0000`, the swap's `Amount` line included; the list of
amount-slot strings below says where.
The rule and its exception live in `src/shared/amountDisplay.js` as The rule and its exception live in `src/shared/amountDisplay.js` as
`truncateAmount()` and `truncateAmountNeverZero()`. Everything the approval and `truncateAmount()` and `truncateAmountNeverZero()`. Everything the approval and
@@ -937,6 +947,49 @@ and compare against. Reading the stored field directly instead answers `null`
for a bundled or tracked token the explorer merely omitted, which is not a for a bundled or tracked token the explorer merely omitted, which is not a
refusal the wallet has any reason to make. refusal the wallet has any reason to make.
**Every string an amount slot can show:** taken together, the exceptions above
mean an amount line on the dApp approval screen (and the wait/success/error
screens that carry a figure forward) shows one of a fixed set of strings, not
always a number:
- A formatted quantity, e.g. `17.1900 USDT`: the token's scale is known. A
figure at or above the floor is truncated to four decimals, one below it is
extended to its first significant digit, and a genuine zero renders `0.0000`,
e.g. `0.0000 USDT`. That zero reaches the ERC-20 `approve`/`transfer` line for
an amount of zero, and the swap's `Amount` line when the step that sets it
states zero: a `PERMIT2_PERMIT` step, a V2 or V3 exact-in `amountIn`, or a
`WRAP_ETH` (`0.0000 ETH`). This is `truncateAmountNeverZero()`
(`src/shared/amountDisplay.js`).
- `Unlimited`: named rather than formatted, since it needs no scale to describe.
On the ERC-20 line it is an `approve` of the `uint256` maximum, an unbounded
allowance (`src/popup/views/approval.js`); `transfer` has no such case. On a
swap's `Amount` line it is any input amount at or above the `uint160` maximum,
whichever step set the line (`src/shared/uniswap.js`): a `PERMIT2_PERMIT`
amount at that maximum, which is an unbounded permit, or a V2 or V3 exact-in
`amountIn` or `WRAP_ETH` amount that large. That includes the router's
whole-balance value (`2^255`), which tells the router to use all it holds of
the token — a quantity decided at execution, not an allowance.
- `All available (V4 open delta)`: a V4 exact-in swap whose `amountIn` is zero.
V4 reads that zero as "use the whole open delta", not as a literal zero, so
the calldata states no quantity at all. Swap `Amount` line only, and only when
the swap has no `PERMIT2_PERMIT` step and its first V2 or V3 exact-in,
`WRAP_ETH` or V4 swap step is a V4 swap step whose first exact-in action has
an `amountIn` of zero (`src/shared/uniswap.js`).
- `None (no minimum guaranteed)`: a zero minimum — the swap guarantees nothing
back. It is a literal zero slippage floor on a V2/V3/V4 swap, and it also
reaches a `BALANCE_CHECK_ERC20` step: a zero `minBalance`, which once rendered
`0.0000` beside the token symbol, now reads this. Swap `Min. received` line
(`src/shared/uniswap.js`).
- `<amount> base units (decimals unknown)`: the token's scale could not be
resolved, so the base-unit integer is shown with that caveat rather than
formatted (see Unknown token scale above). Reaches both the ERC-20 amount line
and the swap's `Amount` and `Min. received` (`unknownDecimalsAmount()` in
`src/shared/approvalAmount.js`).
- `Unknown (not named in the calldata)`: not an amount but the currency itself —
the `Token In` or `Token Out` line when nothing in the calldata established
which token, shown beside the amount and, like the strings above, a sentence
rather than a value (`src/shared/uniswap.js`).
#### Partial USD totals #### Partial USD totals
Prices are fetched for the top 25 tokens only, so an address can hold assets the Prices are fetched for the top 25 tokens only, so an address can hold assets the
+18
View File
@@ -173,6 +173,24 @@ but the review is broader than any of them.
standalone storage entry, never part of the versioned `autistmask` profile, so standalone storage entry, never part of the versioned `autistmask` profile, so
the state schema is untouched and no existing profile is affected. the state schema is untouched and no existing profile is affected.
- 2026-09-21: `README.md` now documents the approval screen's amount-slot
vocabulary and no longer contradicts itself
([#369](https://git.eeqj.de/sneak/AutistMask/issues/369)). The stale claim
that a genuine zero always renders `0.0000` is corrected: a zero with a known
scale does, except where the swap screen states it in words first —
`Min. received` always, and the `Amount` line when the amount it shows is a V4
exact-in `amountIn` of zero. That line shows the amount of the last
`PERMIT2_PERMIT` step if there is any, otherwise of the first V2/V3 exact-in,
`WRAP_ETH` or V4 swap step, where a V4 swap step uses its first exact-in
action; any other known-scale zero there reads `0.0000`. The amount-display
section now names every string a slot can show and when — a formatted quantity
(a known-scale zero included), `Unlimited` (on a swap also the router's
whole-balance value), `All available (V4 open delta)`,
`None (no minimum guaranteed)`, base units with decimals unknown, and
`Unknown (not named in the calldata)` — and records that a zero `minBalance`
on a `BALANCE_CHECK_ERC20` step now reads `None (no minimum guaranteed)` where
it once read `0.0000`. Docs only.
- 2026-08-30: An address no longer wraps, or is shortened to fit, in any of the - 2026-08-30: An address no longer wraps, or is shortened to fit, in any of the
common views ([#380](https://git.eeqj.de/sneak/AutistMask/issues/380)). The common views ([#380](https://git.eeqj.de/sneak/AutistMask/issues/380)). The
wallet list was the reported case: the address shared one row with the wallet list was the reported case: the address shared one row with the