0xMiden / 0xMiden/guardian-dashboard
Aggregate asset totals lose precision for large raw amounts (Number() instead of BigInt)
- 主要语言
- TypeScript
- 星标
- 0
- 派生
- 6
- 平均合并
- 18 小时 25 分钟
- 30 天内合并 PR
- 6
描述
### Packages versions
guardian-dashboard v0.1.0, commit 85929c0 (main, 2026-08-21)
### Bug description
`normalizeAmount()` in lib/token-registry.ts converts the raw on-chain amount
string with `Number(rawAmount)` before dividing by 10**decimals:
export function normalizeAmount(faucetId: string, rawAmount: string): number {
const n = Number(rawAmount);
...
return n / Math.pow(10, decimals);
}
`Number()` silently rounds any integer string above
Number.MAX_SAFE_INTEGER (2^53 - 1 = 9,007,199,254,740,992). A realistic raw
balance is well past that threshold for common decimal counts (e.g. 10,000
units of an 18-decimal token is "10000000000000000000000"), so aggregate
totals can be silently wrong by a non-trivial amount with no error, no
warning, and no test catching it.
This function is the sole totalizer for the dashboard-wide asset sums
(overview/stats) and for the "Total assets (USD)" column in the CSV export
(lib/format.ts, accountsToCsv) — both derive from
lib/account-cache.ts:260, which calls normalizeAmount() per asset and sums
the results with plain floating-point `+`.
The codebase already has the correct pattern one file away:
components/accounts/AccountDetail.tsx:357 renders the same raw amount field
via `BigInt(asset.amount).toLocaleString()`, which does not lose precision.
So a single account's detail page can show the exact figure while the
dashboard-wide total / CSV export derived from the same underlying data is
silently off.
### How can this be reproduced?
1. In a Node/TS REPL, import normalizeAmount (or inline the function) and
call it with a raw amount at or above 2^53 in base units, e.g.:
normalizeAmount("faucetX", "9007199254740993") // decimals default 6
Compare the internal `Number("9007199254740993")` step against the input:
it silently becomes 9007199254740992 before any division happens.
2. In the running app: seed/mock a Guardian account whose fungible asset
`amount` field is a large base-unit integer (e.g. "10000000000000000000000"
for a token registered with 18 decimals in GUARDIAN_TOKEN_DECIMALS), load
the Accounts overview or export the CSV, and compare the displayed/exported
total against the account's own detail page (which uses BigInt and is
correct).
### Relevant log output
```shell
No exception/log is produced — that's the bug. The failure is a silently
wrong number, not a crash. The only observable signal is the discrepancy
between AccountDetail.tsx's BigInt-based per-account figure and the
Number()-based aggregate/CSV total for the same account.
```
贡献指南
调研方向
The bug is in `lib/token-registry.ts` in the `normalizeAmount` function, which uses `Number(rawAmount)`. The fix is to replace `Number` with `BigInt` for the integer parsing and handle the division precisely. Check the existing correct pattern in `components/accounts/AccountDetail.tsx:357`. After making the change, run any existing tests for the token registry or asset totals, and verify the CSV export in `lib/format.ts` and the aggregate sums in `lib/account-cache.ts:260` now match the per-account detail display.
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- typescript
- 领域
- backend
- Issue 类型
- 缺陷
- 难度
- 2/5
- 预计耗时
- 1-3 小时
- 活跃度
- 活跃
- 描述清晰度
- 描述清楚
- 新手友好度
- 75/100