fix: store an absent explorer decimals as unknown instead of fabricating 18 (closes #349)
parseInt(decimals || "18") ran before writing stored tokenBalances[].decimals, so an explorer reporting no decimals produced a fabricated 18 indistinguishable from a real one at read time. That defeated the resolve-or-refuse guarantees of #306 and #340: their refusal paths were intact but never fired, because the guess was laundered upstream of them. An absent scale is now stored as unknown, and a holding whose scale nothing knows carries a null balance -- unknown, never zero -- with six reader sites saying so rather than printing 0.0000. The Send screen resolves the display scale rather than reading the stored one, so a bundled token whose explorer row omits decimals still sends; when the scale cannot be resolved the stored quantity is withdrawn too, so the user is told the balance is unknown rather than only that the fee failed. Existing fabricated 18s cannot be told apart retroactively and are replaced wholesale on the next balance refresh. An explorer-sourced scale stays trusted -- only fabrication is removed; the reasoning is recorded on the issue.
This commit was merged in pull request #367.
This commit is contained in:
21
README.md
21
README.md
@@ -902,6 +902,27 @@ the swap's `Amount` and `Min. received` lines (`src/shared/uniswap.js`). An
|
||||
unbounded allowance or permit needs no scale to describe and is still shown as
|
||||
`Unlimited`.
|
||||
|
||||
The rule holds only if nothing invents a scale UPSTREAM of it. Those three
|
||||
sources are read as authoritative, so a value written into one of them cannot be
|
||||
recognized as a guess afterwards: a fabricated `18` reads exactly like a real
|
||||
`18`, and the refusal above then never fires. So `fetchTokenBalances()` in
|
||||
`src/shared/balances.js` stores what the explorer reported or `null`, never a
|
||||
default, and the same holds for the history list's token transfers in
|
||||
`src/shared/transactions.js`. A token whose `decimals()` reverts has no scale
|
||||
anywhere, and a holding of it carries no quantity either: its balance is `null`
|
||||
— read as unknown, never as zero — and the balance list says so rather than
|
||||
printing `0.0000` for money that is really there. `0` is a real scale and is
|
||||
never treated as absent.
|
||||
|
||||
`tokenBalances[].decimals` is therefore the explorer's own answer and nothing
|
||||
else, which is not the same question as the scale a screen should render at.
|
||||
Anything that needs the second one calls `resolveTokenDecimals()` — the balance
|
||||
list, the approval and swap lines, and the Send screen, which carries the
|
||||
resolved scale onto the pending transaction for `transferAmount.js` to encode
|
||||
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
|
||||
refusal the wallet has any reason to make.
|
||||
|
||||
#### Partial USD totals
|
||||
|
||||
Prices are fetched for the top 25 tokens only, so an address can hold assets the
|
||||
|
||||
Reference in New Issue
Block a user