|
| 1 | +import Big from "big.js"; |
| 2 | + |
| 3 | +/** |
| 4 | + * Formats raw token amount (bigint or string) to human-readable decimal string. |
| 5 | + * |
| 6 | + * - Handles arbitrarily large amounts safely (no Number conversion) |
| 7 | + * - Divides raw / 10^decimals using Big.js for precision |
| 8 | + * - Uses Intl.NumberFormat for locale-aware formatting |
| 9 | + * - Trims insignificant trailing zeros (except for amounts <1) |
| 10 | + * - Edge cases: 0, max safe integer * 10^decimals, overflow |
| 11 | + * |
| 12 | + * @param raw - Raw minor units (e.g. 1000000n for 1 USDC) |
| 13 | + * @param decimals - Token decimals (e.g. 6 for USDC, 7 for XLM/stroops) |
| 14 | + * @param locale - Optional locale (defaults to 'en-US') |
| 15 | + * @returns Formatted display string (e.g. '1.00', '0.00', '1,234.56') |
| 16 | + */ |
| 17 | +export function formatTokenAmount( |
| 18 | + raw: bigint | string | number, |
| 19 | + decimals: number, |
| 20 | + locale: string = "en-US" |
| 21 | +): string { |
| 22 | + if (raw === 0n || raw === "0" || raw === 0) return "0.00"; |
| 23 | + |
| 24 | + // Convert to BigInt safely |
| 25 | + const bigRaw = BigInt(raw.toString()); |
| 26 | + |
| 27 | + // Safe division using Big.js |
| 28 | + const divisor = 10n ** BigInt(decimals); |
| 29 | + const bigIntValue = Big(bigRaw.toString()).div(Big(divisor.toString())); |
| 30 | + |
| 31 | + // Get fixed decimal representation |
| 32 | + const fixed = bigIntValue.toFixed(decimals).replace(/\.?0+$/, ""); |
| 33 | + |
| 34 | + // Use Intl.NumberFormat for locale formatting |
| 35 | + return new Intl.NumberFormat(locale, { |
| 36 | + minimumFractionDigits: 0, |
| 37 | + maximumFractionDigits: decimals, |
| 38 | + }).format(parseFloat(fixed)); |
| 39 | +} |
| 40 | + |
| 41 | +// Convenience for XLM/stroops (7 decimals) |
| 42 | +export function formatXlm( |
| 43 | + raw: bigint | string | number, |
| 44 | + locale?: string |
| 45 | +): string { |
| 46 | + return formatTokenAmount(raw, 7, locale ?? "en-US"); |
| 47 | +} |
| 48 | + |
| 49 | +// Export types for use in components |
| 50 | +export type TokenFormatOptions = { |
| 51 | + decimals: number; |
| 52 | + locale?: string; |
| 53 | +}; |
0 commit comments