Files
zeekay 3849ae2407 fix(lux): nLUX is 10^9, not 10^6 — every LUX figure was 1000x too large
LUX_DECIMALS was 6 in four separate files, each dividing a value the code
itself names nanoLux. Nano is 10^-9. Every staking and balance figure the Lux
explorer rendered was inflated by 1000.

The validators page reported 2,500,000,000,000 LUX staked — against a total
supply of ~2T. An impossible number, and it is reached from lux.cloud's own
"View on explorer" link: an investor reads 2.5B on the dashboard, clicks
through, and sees 2.5T. lux.cloud was right; this was wrong.

Verified against live chain state (platform.getCurrentValidators):
  500000000000000000  nLUX -> 500,000,000 LUX   per validator
  2500000000000000000 nLUX -> 2,500,000,000 LUX total across 5

Four copies of one constant, so the bug shipped four times:
  ui/validators/lux/utils.ts · ui/chains/ChainDetailPage.tsx
  ui/pages/NetworkOverview.tsx · ui/stats/lux/NetworkStats.tsx
Each still owns its own copy; they should share one, which is the follow-up.

Typecheck shows no new errors in these files (the existing _app.tsx and *.pw.tsx
failures predate this change).
2026-07-26 20:11:27 -07:00

32 lines
1.3 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Formatting helpers for Lux P-chain validator data.
// nLUX is NANO-LUX: 10^9 nLUX = 1 LUX. This was 6, which multiplied every
// staking figure on the page by 1000 — the validators page reported
// 2,500,000,000,000 LUX staked against a ~2T total supply, i.e. an
// arithmetically impossible number, reached from lux.cloud's own
// "View on explorer" link. The parameter below is named nanoLux; trust it.
const LUX_DECIMALS = 9;
const TRUNCATE_PREFIX_LEN = 12;
const TRUNCATE_SUFFIX_LEN = 6;
const UPTIME_FRACTION_DIGITS = 2;
const STAKE_FRACTION_DIGITS = 2;
export function formatStake(nanoLux: bigint | string): string {
const raw = typeof nanoLux === 'string' ? nanoLux : String(nanoLux);
const lux = Number(BigInt(raw)) / Math.pow(10, LUX_DECIMALS);
return lux.toLocaleString(undefined, { maximumFractionDigits: STAKE_FRACTION_DIGITS });
}
export function formatUptime(uptime: string): string {
// uptime is already in percentage format (0–100), no scaling needed
return `${ parseFloat(uptime).toFixed(UPTIME_FRACTION_DIGITS) }%`;
}
export function truncateNodeId(nodeId: string): string {
const minLength = TRUNCATE_PREFIX_LEN + TRUNCATE_SUFFIX_LEN + 3;
if (nodeId.length <= minLength) {
return nodeId;
}
return `${ nodeId.slice(0, TRUNCATE_PREFIX_LEN) }...${ nodeId.slice(-TRUNCATE_SUFFIX_LEN) }`;
}