Token Amount
A balance formatted from base units without ever touching a float. 1 ETH is 10¹⁸ wei, which exceeds Number.MAX_SAFE_INTEGER by two orders of magnitude — a balance that passes through a JavaScript number is silently wrong.
src/components/ui/token-amount.tsxAbout
From the component's own source, where it was written.
A token balance, formatted from base units without ever touching a float.
This is the one that has to be right. On-chain amounts are integers in the token's smallest unit — 18 decimals for most ERC-20s — and 1 ETH is 1000000000000000000 wei. That exceeds Number.MAX_SAFE_INTEGER by two orders of magnitude, so the moment a balance passes through a JavaScript number it is silently wrong. Every value here stays a bigint or a decimal string, and the split into whole and fractional parts is done on the digit string.
Display is deliberately lossy in one direction only: it rounds *down*. A balance shown as more than the wallet holds produces a failed transaction, which is a worse outcome than showing slightly less.
Install
npx astralyx-ui add token-amount
Usage
import { TokenAmount } from '@/components/ui/token-amount'
<TokenAmount value="1234567890123456789" decimals={18} symbol="ETH" />
<TokenAmount value={usdcBalance} decimals={6} symbol="USDC" fiat={2500} />Composer
Change the props and the source below follows.
<TokenAmount
value="1234567890123456789"
decimals={18}
precision={4}
symbol="ETH"
/>Examples
Precision at scale
<TokenAmount value="999999999999999999" decimals={18} precision={18} symbol="ETH" />
<TokenAmount value="123456789012345678901234" decimals={18} symbol="ETH" />API
Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.
TokenAmount
A token balance, formatted from base units without ever touching a float.
Extends Omit<ComponentProps<'span'>, 'children'>.
| Prop | Type | Default | Description |
|---|---|---|---|
| value | bigint | string | required | Base units. A string keeps it exact — never a number, which loses precision above 2^53. |
| decimals | number | 18 | 18 for most ERC-20s, 8 for BTC, 6 for USDC. |
| symbol | string | — | — |
| precision | number | 4 | Fraction digits shown. Truncated, never rounded up — displaying more than is held produces a failed transaction. |
| trim | boolean | true | Fraction digits shown. Truncated, never rounded up — displaying more than is held produces a failed transaction. |
| fiat | number | — | Converted value, shown alongside. |
| fiatCurrency | string | 'USD' | Converted value, shown alongside. |
| locale | string | 'en-GB' | Grouping and the decimal mark both follow it, so a German amount reads 1.234,5 rather than a mix of the two conventions. |
| signed | boolean | false | Colour and sign by direction, for a delta rather than a balance. |
| size | 'sm' | 'default' | 'lg' | 'default' | — |
Functions
| Function | Signature | Description |
|---|---|---|
| splitUnits | (value: bigint, decimals: number) => { negative: boolean; whole: string; fraction: string; } | Exported. The split is done on the digit string — padding and slicing is exact at any magnitude. |
| parseUnits | (value: string, decimals: number) => bigint | A decimal string from an API — "12.5" — as base units, for value. Digits past decimals are cut, never rounded up; anything that is not a plain decimal throws. |
| formatUnits | (value: bigint, decimals: number, precision: number, trim: boolean, locale: string) => string | Exported. The split is done on the digit string — padding and slicing is exact at any magnitude. |