Skip to content

amountToUiAmount / uiAmountToAmount helpers are lossy in both JS clients #1325

Description

@cfkelly18

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

  • clients/js/src/amountToUiAmount.ts — Number(amount) + Math.trunc at :137,140 (interest-bearing) and :211,213 (scaled-UI); parseFloat / Math.trunc in the ui→amount path (:180,194).
  • clients/js-legacy/src/actions/amountToUiAmount.ts — same pattern at :148,154,169,171,207; parseFloat at :94 and Math.trunc at :280.

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions