Both the current and legacy JS clients convert token amounts through Number(bigint) and Math.trunc, and parse UI strings with parseFloat, so they lose precision and diverge from the on-chain conversion.
Problems
- Precision loss above 2^53: Number(amount) on a bigint silently loses precision for large balances / high-decimal mints.
- Trunc-before-divide zeroing: Math.trunc(scaledAmount) / decimalFactor rounds sub-unit amounts to 0 for a scaled-UI multiplier < 1 (amount=1, decimals=0, multiplier=0.5 → "0" instead of "0.5").
- Unchecked parseFloat: the ui→amount direction parses with parseFloat and no u64 range check.
Result: wallets/tools can display or sign incorrect amounts (off-chain, but users could act on it).
Affected code
Fix
Use bigint throughout, divide to display precision instead of truncating base units first (matching on-chain rounding order), and range-check parsed UI strings against u64.
Both the current and legacy JS clients convert token amounts through Number(bigint) and Math.trunc, and parse UI strings with parseFloat, so they lose precision and diverge from the on-chain conversion.
Problems
Result: wallets/tools can display or sign incorrect amounts (off-chain, but users could act on it).
Affected code
Fix
Use bigint throughout, divide to display precision instead of truncating base units first (matching on-chain rounding order), and range-check parsed UI strings against u64.