0xMiden / 0xMiden/guardian-dashboard

Aggregate asset totals lose precision for large raw amounts (Number() instead of BigInt)

未关闭 适合新手
#47 2 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
主要语言
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

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。