The block explorer's holders_count is optional. Reading it as
`holders_count || "0"` recorded a token the explorer said nothing about
as a token with no holders at all, which is the strongest spam signal the
wallet has: the low-holder rule then hid a legitimate transfer from the
history and withheld a token the user actually holds from the Send
selector. It also made the `tx.holders !== null` guard in
filterTransactions unreachable for token transfers, since the coercion
guaranteed a number.
The null-versus-zero rule and the 1,000-holder threshold now live in one
place, src/shared/holders.js, because the rule was open-coded at three
call sites and got it wrong at all three.
An unknown count is shown rather than hidden in both user-facing
filters: hiding an asset the user owns costs more than showing a spam row
they can see is unusual, and both filters have a setting behind them.
The balance-list spam gate in fetchTokenBalances keeps its strict
behaviour — it has no off switch and governs the whole balance list, so
an unreported count is no evidence for admission — but it now records the
unknown as null, so a token that reaches the list by being known or
tracked is no longer hidden downstream by a zero it never reported.
A reported count of zero still parses to 0 and is still filtered
everywhere; that is covered by tests alongside the unknown-count ones.