harden: a holders_count that is not plain digits is unknown, not read in part (closes #251)
parseHoldersCount used parseInt, which reads "1,000" as 1, "0x10" as 0 and "1e3" as 1: a reported low count, which hides the token in the transaction history and the send-screen token selector. It now accepts only a whole number of zero or more, or a string of digits alone, no larger than Number.MAX_SAFE_INTEGER, and returns null for anything else. The balance list's holders !== null check did nothing, since null >= 1000 is already false, and is dropped. README.md and docs/README.md say how each filter treats an unknown count and that the token screen then leaves out its Holders row; README.md lists src/shared/holders.js. Model: opus-5-5
This commit was merged in pull request #445.
This commit is contained in:
@@ -147,20 +147,20 @@ async function fetchTokenBalances(address, blockscoutUrl, trackedTokens) {
|
||||
// null is a holding of an amount that cannot be stated, which is
|
||||
// not the same as a holding of zero, and must never render as one.
|
||||
const bal = scale === null ? null : formatTokenBalance(raw, scale);
|
||||
// null means the explorer reported no count, which is not the
|
||||
// same as a count of zero. This gate is not the low-holder
|
||||
// display filter: it has no user-facing off switch and governs
|
||||
// the whole balance list, so it stays strict and admits a token
|
||||
// only on a reported count — an unreported one is no evidence.
|
||||
// A legitimate token still reaches the list through the known
|
||||
// null means the explorer reported no readable count, which is
|
||||
// not the same as a count of zero. This gate is not the
|
||||
// low-holder display filter: it has no user-facing off switch and
|
||||
// governs the whole balance list, so it stays strict and admits a
|
||||
// token only on a reported count — an unreported one is no
|
||||
// evidence, and `null >= LOW_HOLDER_THRESHOLD` is false. A
|
||||
// legitimate token still reaches the list through the known
|
||||
// token list or by the user tracking it, and the null is carried
|
||||
// through to the views, where the two low-holder filters treat
|
||||
// an unknown count as "do not judge" rather than as zero.
|
||||
const holders = parseHoldersCount(item.token.holders_count);
|
||||
const isKnown = TOKEN_BY_ADDRESS.has(tokenAddr);
|
||||
const isTracked = trackedSet.has(tokenAddr);
|
||||
const hasEnoughHolders =
|
||||
holders !== null && holders >= LOW_HOLDER_THRESHOLD;
|
||||
const hasEnoughHolders = holders >= LOW_HOLDER_THRESHOLD;
|
||||
|
||||
// Skip spam tokens the user never asked to see
|
||||
if (!isKnown && !isTracked && !hasEnoughHolders) continue;
|
||||
|
||||
Reference in New Issue
Block a user