fix: never render a nonzero approval amount as zero (closes #322)
All checks were successful
check / check (push) Successful in 30s
e2e / e2e-chrome (push) Successful in 1m12s
e2e / e2e-firefox (push) Successful in 24s

formatTxValue() truncates to 4 decimal places, per README.md's Display
Consistency rule. With the token's true scale resolved, an amount below 0.0001
still printed as 0.0000: 1 base unit of an 18-decimal token, 500 base units of
an 8-decimal one. On the dApp approval screen — and on the wait/success/error
screens, which carry that same string forward as txInfo.amount — a real
transfer or allowance was therefore stated as nothing.

The copy of formatTxValue() in src/popup/views/approval.js now extends to the
first significant digit when the first 4 decimals would all be zero and the
value is not: 0.000000000000000001 DAI, not 0.0000 DAI. Extra precision was
chosen over falling back to base units so the number stays in token units, the
same unit as the symbol printed beside it; the base-unit rendering already on
this screen means "the scale is unknown", and reusing it for a known scale
would blur the two. A genuine zero still renders 0.0000, and an amount at or
above the floor is untouched.

The 4-decimal rule stays. The separate copy of formatTxValue() in
src/shared/transactions.js, which serves the history list, is deliberately not
changed: the history detail view already shows exact precision, and balance
lists and history are out of scope here.

tests/approvalDisplayFloor.test.js drives decodeCalldata() and asserts both the
displayed line and the rawValue the confirmation screens carry, at 6, 8 and 18
decimals and across every scale from 0 to 30, plus four cases pinning the
unchanged truncation. Against this tree with the source change reverted, 4 of
its cases fail — 1 base unit at 18 decimals gives "0.0000 DAI" where
"0.000000000000000001 DAI" is expected, 500 base units at 8 decimals gives
"0.0000" where "0.000005" is expected.

make check green: 42 suites, 844 tests; verify-build 39 cases; check-censored
152 files; eslint and prettier clean in the pinned container.
This commit is contained in:
2026-08-23 13:18:20 +00:00
parent cef6aaab11
commit 3fb6a53f77
4 changed files with 151 additions and 2 deletions

View File

@@ -689,6 +689,18 @@ Both are click-copyable. Truncating to 4 decimals in summary views is acceptable
for scannability, but the detail view must never discard precision — it is the
one place the user can always use to verify exact details.
**Specific Exception — nonzero floor on the approval screens:** A nonzero amount
must never render as zero. Truncating to 4 decimals does exactly that to an
amount below 0.0001 — 1 base unit of an 18-decimal token, 500 base units of an
8-decimal one — and on the dApp approval screen and the wait/success/error
screens that carry its amount forward, a real transfer or allowance then reads
as "nothing is being moved". On those screens (`formatTxValue()` in
`src/popup/views/approval.js`), when the first 4 decimals would all be zero and
the value is not, the amount is extended to its first significant digit instead:
`0.000000000000000001 DAI`, not `0.0000 DAI`. It stays in token units, the same
unit as the symbol beside it. The 4-decimal rule is unchanged everywhere else,
including for amounts at or above the floor on these same screens.
#### Partial USD totals
Prices are fetched for the top 25 tokens only, so an address can hold assets the