Skip to content

fix(app): cap holder counts - #1609

Merged
andrewklau merged 4 commits into
mainfrom
fix/cap-holder-counts
Aug 28, 2026
Merged

fix(app): cap holder counts#1609
andrewklau merged 4 commits into
mainfrom
fix/cap-holder-counts

Conversation

@andrewklau

Copy link
Copy Markdown
Contributor

No description provided.

SELECT COUNT(*) FROM ft_holders WHERE contract=... AND amount>0 was the
single heaviest statement on the read replica: 15.9 million buffer
accesses per call, 2.3s mean, and 289 billion buffer hits in total for
one popular contract alone. That is 213x the next statement, and the
replica is 99.6% cached, so it is CPU rather than disk.

Count inside a LIMIT and run the result through cappedCount, matching
what the transaction counts already do. Beyond maxQueryCount the
response reads "10000+" instead of an exact figure; the schemas already
type these as strings, so no schema change is needed.

Applies to the FT, NFT and MT holder counts, which share the shape.
Note mts/holderCount.sql is registered but currently unreferenced; it
is capped for consistency, so any future caller must pass a limit.
Capping the API response meant the token overview cards and the FT FAQ
received "10000+", and both passed it straight to numberFormat, which
returns the literal string "NaN". The overview sits in the token layout,
so that would have appeared on every tab of every FT, NFT and MT page
whose holder set exceeds the cap: exactly the popular tokens the capping
was aimed at.

The holders tables were already correct, switching between holders.total
and holders.totalExact via isApproxCount.

approxCountFormat formats the number and re-appends the "+", so a capped
count never reads as an exact figure. Using countFormat alone would have
rendered "10,000" and stated a total we do not know to be true. Keeping
the suffix in the value rather than the sentence avoids adding an approx
variant to three namespaces across fourteen locales, and reads correctly
in all of them.
The previous commit added an approxCountFormat helper that baked a "+"
into the value. Every other capped count in the app instead switches
translation keys on isApproxCount and formats with countFormat, so the
wording carries the approximation and the number stays a number:

  t(isApproxCount(count) ? 'x.total' : 'x.totalExact',
    { count: countFormat(count) })

Used in eleven places including txns, receipts, keys, staking and the
holders tables themselves. Follow it rather than introduce a twelfth
style.

Adds holdersApprox ('More than {{count}}') to the FT, NFT and MT
overview namespaces and supplySplitApprox to the FT FAQ, across all
fourteen locales, matching how the existing total/totalExact pairs are
populated.
/v3/mts/{contract}/tokens/count has been capped since before this
branch (services/v3/mts/index.ts:220), but the contract overview passed
the value straight to numberFormat, which returns the literal string
"NaN" for "10000+". The row sits in the contract layout, so any MT
contract with more than 10000 tokens showed "Tokens: NaN" on both the
main page and the inventory tab.

Pre-existing on main and unrelated to the holder-count capping; found
while reviewing it. Same treatment as the holder counts, with a
tokensApprox key across all fourteen locales.

Swept the rest of the frontend for the same shape: the only other
numberFormat calls on a count field read block aggregates, which are
never capped.
@andrewklau
andrewklau merged commit eee3921 into main Aug 28, 2026
1 check passed
@andrewklau
andrewklau deleted the fix/cap-holder-counts branch August 28, 2026 04:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant