toDecimals() accepted any uint8 scale, but formatUnits() and parseUnits()
refuse more than 80 decimal places. A token reporting 81 to 255 made the
formatter throw, and the catch in the swap decoder and in the ERC-20 decoder
turned that into an undecoded approval screen with nothing saying why.
MAX_DECIMALS is now 80, the formatter's own limit, so such a scale is
treated exactly like an unknown one: both approval paths show the base-unit
amount with the scale stated as unknown. The balance list, the history list
and the Send screen use the same check.
Model: opus-5-5
The approval and transaction-status screens read a token's scale from the
bundled list, the tokens the user tracks, then the block explorer, but read
its symbol from the bundled list alone. A token the user added by hand was
scaled correctly yet labelled "Unknown token", and a non-bundled ERC-20 was
carried onto the wait screen as ETH.
resolveTokenSymbol() now draws the symbol through the same sources and
precedence as the scale, and the ERC-20 and Uniswap swap lines both use it. A
tracked or explorer-reported name stays subject to the spoof rule, so it
cannot claim a bundled or native ticker.
Folds in #354.
Model: opus-4-8
Co-authored-by: clawbot <clawbot@noreply.example.org>
decodeCalldata consulted only the 512-entry bundled list and defaulted to 18
decimals, so a transfer of 5,000 units of a 6-decimal token rendered
"Amount 0.0000" and the user confirmed a drain reading zero. The same
understatement applied to approve, where an unbounded allowance also rendered
0.0000.
Decimals now resolve from the bundled list, then trackedTokens, then the
address's explorer-reported entry, with uint8 validation and a refusal when
sources for one contract disagree. When no source knows the scale, no
formatUnits call is reached at all: the line renders raw base units with an
explicit "decimals unknown" warning, and the same string reaches
pendingTxDetails.amount so the status screens carry no formatted figure either.
Verified failing first two independent ways: restoring the old
`token ? token.decimals : 18` fails 6 of 15 new tests with the unknown case
reporting "0.0000"; making the resolver return 18 rather than null on the
unknown path fails a different 6, spanning resolver and render levels.