numbers
This module provides comprehensive utilities for handling numeric operations, formatting, and conversions in the GMX protocol. It includes functions for working with BigInt values, formatting currencies and percentages, handling decimal precision, and converting between different numeric representations.
Types
The numbers module exports union types used throughout the SDK for accepting flexible numeric input.
| Type | Definition | Description |
|---|---|---|
Numeric | number | bigint | A value that is either a JavaScript number or a bigint. |
BigNumberish | string | Numeric | A value convertible to bigint — accepts a string, number, or bigint. |
NonZero<T> | T & { readonly [__nonZero]: true } | A branded type asserting a number or bigint is not zero. Use with isNonZero() to narrow the type and safeDivide() to perform safe division. |
import type { Numeric, BigNumberish } from "@gmx-io/sdk/utils/numbers";
import { isNonZero, safeDivide } from "@gmx-io/sdk/utils/numbers";
// Numeric accepts number or bigint
const a: Numeric = 42;
const b: Numeric = 42n;
// BigNumberish also accepts strings — useful for user input or serialized values
const c: BigNumberish = "1000000000000000000";
const d: BigNumberish = 100n;
// NonZero<T> expresses divide-by-zero safety at the type level
function computeShare(amount: bigint, total: bigint): bigint {
if (!isNonZero(total)) {
throw new Error("Total must be non-zero");
}
return safeDivide(amount, total); // total is NonZero<bigint>
}
Most functions that accept BigNumberish call BigInt(value) internally. Passing a decimal string like "1.5" to a function that expects an integer will throw a runtime error. Convert floats to bigint first using numberToBigint or expandDecimals.
Constants
The numbers module exports constants for precision, basis points, and display thresholds used throughout the SDK and GMX smart contracts.
Precision and decimals
| Constant | Value | Description |
|---|---|---|
USD_DECIMALS | 30 | Decimal precision for USD values. All USD amounts are stored as bigint scaled by 10^30. |
PRECISION_DECIMALS | 30 | The number of decimal places in the PRECISION scaling factor. |
PRECISION | 10n ** 30n | Scaling factor used in multiplications before division to preserve decimal precision. |
PERCENT_PRECISION_DECIMALS | 28 | Decimal precision for percentage values (PRECISION_DECIMALS - 2). |
Float precision
| Constant | Value | Description |
|---|---|---|
FLOAT_PRECISION_SQRT_DECIMALS | 15 | Decimal precision for square-root-scaled float values. |
FLOAT_PRECISION_SQRT | 10n ** 15n | Square root of PRECISION, used in intermediate calculations that require reduced-precision float arithmetic. |
Basis points
| Constant | Value | Description |
|---|---|---|
BASIS_POINTS_DIVISOR | 10000 | Divisor for basis point calculations as a number. |
BASIS_POINTS_DIVISOR_BIGINT | 10000n | Same divisor as a bigint, for use in bigint arithmetic. |
BASIS_POINTS_DECIMALS | 4 | Number of decimal places represented by basis points (1 bps = 0.0001). |
BigInt sentinel values
| Constant | Value | Description |
|---|---|---|
BN_ZERO | 0n | Reusable bigint zero. |
BN_ONE | 1n | Reusable bigint one. |
BN_NEGATIVE_ONE | -1n | Reusable bigint negative one. |
MaxUint256 | 2n ** 256n - 1n | Maximum value of a 256-bit unsigned integer. |
MaxInt256 | 2n ** 255n - 1n | Maximum value of a 256-bit signed integer. |
Display threshold prefixes
| Constant | Value | Description |
|---|---|---|
TRIGGER_PREFIX_ABOVE | ">" | Prefix displayed when a value exceeds the maximum display threshold. |
TRIGGER_PREFIX_BELOW | "<" | Prefix displayed when a value is below the minimum display threshold. |
import {
USD_DECIMALS,
PRECISION,
BASIS_POINTS_DIVISOR_BIGINT,
BN_ZERO,
expandDecimals,
} from "@gmx-io/sdk/utils/numbers";
// Represent $1,000 as a bigint with 30 decimal places
const oneThousandUsd = expandDecimals(1000, USD_DECIMALS);
// oneThousandUsd === 1000n * 10n ** 30n
// Apply a 0.5% fee (50 basis points) using precision-safe arithmetic
const feeRate = (50n * PRECISION) / BASIS_POINTS_DIVISOR_BIGINT;
const fee = (oneThousandUsd * feeRate) / PRECISION;
// fee === 5n * 10n ** 30n ($5.00)
// Guard against an uninitialized value
const balance = BN_ZERO;
Methods
The numbers module exports methods in four categories: arithmetic and conversion, string-to-bigint parsing, display formatting, and object serialization. Each method operates on bigint values scaled by the appropriate decimal precision.
Arithmetic and conversion
expandDecimals
expandDecimals(n: BigNumberish, decimals: number): bigint
Multiplies n by 10^decimals, converting a human-readable value into its fixed-point bigint representation. This is the standard way to create a scaled value for use with SDK calculations.
import { expandDecimals, USD_DECIMALS } from "@gmx-io/sdk/utils/numbers";
const oneEth = expandDecimals(1, 18); // 1000000000000000000n
const oneUsd = expandDecimals(1, USD_DECIMALS); // 1000000000000000000000000000000n
basisPointsToFloat
basisPointsToFloat(basisPoints: bigint): bigint
Converts a basis point value into a PRECISION-scaled bigint float. The result is (basisPoints * PRECISION) / 10000. Use this when you need to represent a percentage as a precision-scaled factor.
import { basisPointsToFloat, PRECISION } from "@gmx-io/sdk/utils/numbers";
// 250 bps = 2.5%
const factor = basisPointsToFloat(250n); // (250n * PRECISION) / 10000n
getBasisPoints
getBasisPoints(numerator: bigint, denominator: bigint, shouldRoundUp?: boolean): bigint
Computes (numerator * 10000) / denominator as basis points. When shouldRoundUp is true, the result rounds away from zero if there is any remainder.
import { getBasisPoints } from "@gmx-io/sdk/utils/numbers";
// Fee of 25 out of 1000 = 2.5% = 250 bps
const fee = getBasisPoints(25n, 1000n); // 250n
const feeRoundedUp = getBasisPoints(7n, 3n, true); // 23334n (rounds up)
roundUpMagnitudeDivision
roundUpMagnitudeDivision(a: bigint, b: bigint): bigint
Divides a by b, rounding the result away from zero regardless of sign. Positive results round up; negative results round toward negative infinity.
import { roundUpMagnitudeDivision } from "@gmx-io/sdk/utils/numbers";
roundUpMagnitudeDivision(100n, 3n); // 34n (positive: rounds up)
roundUpMagnitudeDivision(-100n, 3n); // -34n (negative: rounds toward -∞)
The original docs stated that roundUpMagnitudeDivision(-100n, 3n) returns -33n. The source code at line 64–70 of utils.ts computes (a - b + 1n) / b for negative a, which gives (-100 - 3 + 1) / 3 = -102 / 3 = -34. This is rounding away from zero (increasing magnitude), not toward zero.
applyFactor
applyFactor(value: bigint, factor: bigint): bigint
Multiplies value by factor and divides by PRECISION (10^30). Use this to apply a precision-scaled multiplier — for example, a fee rate returned by basisPointsToFloat.
import { applyFactor, basisPointsToFloat, expandDecimals, USD_DECIMALS } from "@gmx-io/sdk/utils/numbers";
const positionSize = expandDecimals(10000, USD_DECIMALS); // $10,000
const feeRate = basisPointsToFloat(50n); // 0.5% as PRECISION-scaled factor
const fee = applyFactor(positionSize, feeRate); // $50 (as USD bigint)
numberToBigint
numberToBigint(value: number, decimals: number): bigint
Converts a JavaScript number (including floats) to a bigint with the specified decimal places. This avoids floating-point rounding by performing the conversion digit by digit.
import { numberToBigint } from "@gmx-io/sdk/utils/numbers";
numberToBigint(123.456, 18); // 123456000000000000000n
numberToBigint(-50.25, 6); // -50250000n
bigintToNumber
bigintToNumber(value: bigint, decimals: number): number
Converts a scaled bigint back to a JavaScript number. The result may lose precision for very large values due to JavaScript's floating-point representation.
import { bigintToNumber, expandDecimals } from "@gmx-io/sdk/utils/numbers";
const scaled = expandDecimals(123456, 18);
bigintToNumber(scaled, 18); // 123456.0 (as number)
const fractional = expandDecimals(1, 18) / 2n; // 5 * 10^17n
bigintToNumber(fractional, 18); // 0.5
adjustForDecimals
adjustForDecimals(amount: bigint, divDecimals: number, mulDecimals: number): bigint
Converts amount from divDecimals precision to mulDecimals precision. Useful when bridging between token decimals and USD decimals.
import { adjustForDecimals, expandDecimals } from "@gmx-io/sdk/utils/numbers";
// Convert a USDC amount (6 decimals) to USD precision (30 decimals)
const usdcAmount = expandDecimals(100, 6); // 100 USDC
const asUsd = adjustForDecimals(usdcAmount, 6, 30);
roundUpDivision
roundUpDivision(a: bigint, b: bigint): bigint
Performs ceiling(a / b) for positive values using (a + b - 1) / b. Use this when you need to ensure you never underestimate a result (for example, fee calculations).
import { roundUpDivision } from "@gmx-io/sdk/utils/numbers";
roundUpDivision(100n, 3n); // 34n (ceiling of 33.33...)
roundUpDivision(99n, 3n); // 33n (exact)
roundToTwoDecimals
roundToTwoDecimals(n: number): number
Rounds a JavaScript number to two decimal places using Math.round(n * 100) / 100.
import { roundToTwoDecimals } from "@gmx-io/sdk/utils/numbers";
roundToTwoDecimals(123.456789); // 123.46
roundToTwoDecimals(1.005); // 1.01
roundToOrder
roundToOrder(n: bigint, significantDigits?: number): bigint
Rounds a bigint to the specified number of significant digits (default: 1). Useful for estimating large numbers with reduced precision.
import { roundToOrder } from "@gmx-io/sdk/utils/numbers";
roundToOrder(123456789n, 3); // 123000000n
roundToOrder(987654321n, 1); // 900000000n
roundBigIntToDecimals
roundBigIntToDecimals(value: bigint, tokenDecimals: number, roundToDecimals: number): bigint
Rounds a scaled bigint to a coarser decimal precision while preserving the original scaling. For example, round an 18-decimal value to 6 significant decimal places.
import { roundBigIntToDecimals, expandDecimals } from "@gmx-io/sdk/utils/numbers";
// Round an 18-decimal value to 6 decimal places
const precise = expandDecimals(123456789, 12); // 123456789000000000000n
const rounded = roundBigIntToDecimals(precise, 18, 6);
roundWithDecimals
roundWithDecimals(value: BigNumberish, opts: { displayDecimals: number; decimals: number }): bigint
Rounds value (with decimals precision) to displayDecimals decimal places. This is the internal rounding function used by formatAmount.
import { roundWithDecimals } from "@gmx-io/sdk/utils/numbers";
// Round 8-decimal value to 4 display decimals
roundWithDecimals(123456789n, { displayDecimals: 4, decimals: 8 }); // 123460000n
clamp
clamp(value: number, min: number, max: number): number
Constrains a number to the [min, max] range, returning min if below or max if above.
import { clamp } from "@gmx-io/sdk/utils/numbers";
clamp(150, 0, 100); // 100
clamp(-5, 0, 100); // 0
clamp(50, 0, 100); // 50
minBigNumber
minBigNumber(...args: bigint[]): bigint | undefined
Returns the smallest value from a list of bigint arguments. Returns undefined if called with no arguments.
import { minBigNumber } from "@gmx-io/sdk/utils/numbers";
minBigNumber(100n, 50n, 200n); // 50n
minBigNumber(); // undefined
maxbigint
maxbigint(...args: bigint[]): bigint | undefined
Returns the largest value from a list of bigint arguments. Returns undefined if called with no arguments.
import { maxbigint } from "@gmx-io/sdk/utils/numbers";
maxbigint(100n, 50n, 200n); // 200n
absDiffBps
absDiffBps(value: bigint, base: bigint): bigint
Calculates the absolute difference between value and base expressed in basis points: |value - base| * 10000 / base.
import { absDiffBps } from "@gmx-io/sdk/utils/numbers";
absDiffBps(1050n, 1000n); // 500n (5% difference)
absDiffBps(900n, 1000n); // 1000n (10% difference)
Edge cases: if value is zero and base is non-zero (or vice versa), absDiffBps returns 10000n (100%). If both are zero, it returns 0n.
String parsing and conversion
parseValue
parseValue(value: string, tokenDecimals: number): bigint | undefined
Parses a user-input string (for example, "1.5") into a scaled bigint with tokenDecimals precision. Returns undefined if the string is not a valid number or if the parsed value exceeds an internal safety cap of 10^62.
import { parseValue } from "@gmx-io/sdk/utils/numbers";
parseValue("1.5", 18); // 1500000000000000000n
parseValue("0.001", 6); // 1000n
parseValue("invalid", 18); // undefined
parseValue("", 18); // undefined
parseValue caps the result at 10^62 to prevent downstream bigint overflow. Values above this threshold return undefined.
toBigNumberWithDecimals
This function is scheduled for removal. Use parseValue or numberToBigint instead.
toBigNumberWithDecimals(value: string, decimals: number): bigint
Converts a decimal string to a bigint with the specified number of decimal places. Unlike parseValue, it does not validate input or apply a safety cap, and it returns 0n for empty strings instead of undefined.
import { toBigNumberWithDecimals } from "@gmx-io/sdk/utils/numbers";
toBigNumberWithDecimals("123.456", 18); // 123456000000000000000n
toBigNumberWithDecimals("", 18); // 0n
bigNumberify
bigNumberify is deprecated. Use native BigInt() directly. The function logs a console error and returns undefined on invalid input rather than throwing.
bigNumberify(n?: BigNumberish | null | undefined): bigint | undefined
Wraps BigInt() in a try/catch, returning undefined instead of throwing on invalid input.
import { bigNumberify } from "@gmx-io/sdk/utils/numbers";
bigNumberify("123"); // 123n
bigNumberify("invalid"); // undefined (logs console.error)
bigNumberify(null); // undefined
trimZeroDecimals
trimZeroDecimals(amount: string): string
Removes trailing zeros and unnecessary decimal points from a numeric string.
import { trimZeroDecimals } from "@gmx-io/sdk/utils/numbers";
trimZeroDecimals("123.000"); // "123"
trimZeroDecimals("123.456"); // "123.456"
trimZeroDecimals("0.00"); // "0"
limitDecimals
limitDecimals(amount: BigNumberish, maxDecimals?: number): string
Truncates a numeric string to at most maxDecimals decimal places. Does not round — it truncates. If maxDecimals is omitted, returns the string as-is.
import { limitDecimals } from "@gmx-io/sdk/utils/numbers";
limitDecimals("123.456789", 4); // "123.4567" (truncated, not rounded)
limitDecimals("123.456789"); // "123.456789"
limitDecimals("123.456789", 0); // "123"
padDecimals
padDecimals(amount: BigNumberish, minDecimals: number): string
Pads a numeric string with trailing zeros to ensure at least minDecimals decimal places.
import { padDecimals } from "@gmx-io/sdk/utils/numbers";
padDecimals("123.4", 4); // "123.4000"
padDecimals("123", 2); // "123.00"
padDecimals("1.50", 2); // "1.50" (already has enough decimals)
removeTrailingZeros
removeTrailingZeros(amount: string | number): string | number
Converts amount to a number and returns it (which removes trailing zeros). Returns the original value unchanged if the conversion yields 0 or NaN.
import { removeTrailingZeros } from "@gmx-io/sdk/utils/numbers";
removeTrailingZeros("123.000"); // 123 (as number)
removeTrailingZeros("0.500"); // 0.5 (as number)
removeTrailingZeros(0); // 0 (unchanged)
Display formatting
formatAmount
formatAmount(
amount: BigNumberish | undefined,
tokenDecimals: number,
displayDecimals?: number,
useCommas?: boolean,
defaultValue?: string,
visualMultiplier?: number
): string
Core formatting function. Divides amount by 10^tokenDecimals, rounds to displayDecimals (default: 4), and optionally adds comma separators. Returns defaultValue (default: "...") when amount is undefined, null, or empty.
import { formatAmount, expandDecimals } from "@gmx-io/sdk/utils/numbers";
const amount = expandDecimals(1234567, 18);
formatAmount(amount, 18, 4, true); // "1.2346"
formatAmount(amount, 18, 2, true); // "1.23"
formatAmount(undefined, 18, 2); // "..."
formatAmount(undefined, 18, 2, false, "-"); // "-"
formatAmountFree
formatAmountFree(amount: BigNumberish, tokenDecimals: number, displayDecimals?: number): string
Formats an amount without padding zeros after the decimal point. Unlike formatAmount, it calls trimZeroDecimals on the result.
import { formatAmountFree, expandDecimals } from "@gmx-io/sdk/utils/numbers";
formatAmountFree(expandDecimals(123, 18), 18, 6); // "0.000123"
formatAmountFree(expandDecimals(1, 18), 18, 4); // "1" (not "1.0000")
formatKeyAmount
formatKeyAmount<T>(map: T | undefined, key: keyof T, tokenDecimals: number, displayDecimals: number, useCommas?: boolean): string
Formats a bigint value read from a property of an object. Returns "..." if the map or key is missing.
import { formatKeyAmount } from "@gmx-io/sdk/utils/numbers";
const market = { longOpenInterest: 1234567890000000000n };
formatKeyAmount(market, "longOpenInterest", 18, 4); // "1.2346"
formatKeyAmount(undefined, "longOpenInterest", 18, 4); // "..."
formatArrayAmount
formatArrayAmount(arr: any[], index: number, tokenDecimals: number, displayDecimals?: number, useCommas?: boolean): string
Formats a bigint value at a specific index in an array. Returns "..." if the array or index is missing.
import { formatArrayAmount } from "@gmx-io/sdk/utils/numbers";
const amounts = [expandDecimals(1, 18), expandDecimals(2, 18)];
formatArrayAmount(amounts, 0, 18, 4); // "1.0000"
getLimitedDisplay
getLimitedDisplay(
amount: bigint,
tokenDecimals: number,
opts?: { maxThreshold?: BigNumberish | null; minThreshold?: BigNumberish }
): { symbol: string; value: bigint }
Returns a display object with a threshold symbol (">" or "<") and a clamped value when amount falls outside the display range. The default thresholds are a maximum of 1,000,000,000 and a minimum of 0.01. Pass maxThreshold: null to disable the upper cap.
import { getLimitedDisplay, expandDecimals } from "@gmx-io/sdk/utils/numbers";
// Amount below minimum threshold
const tiny = expandDecimals(1, 15); // 0.001 ETH
getLimitedDisplay(tiny, 18);
// { symbol: "<", value: <min threshold value> }
// Amount above maximum threshold
const huge = expandDecimals(2_000_000_000, 18);
getLimitedDisplay(huge, 18);
// { symbol: ">", value: <max threshold value> }
// Amount in range
const normal = expandDecimals(100, 18);
getLimitedDisplay(normal, 18);
// { symbol: "", value: 100000000000000000000n }
formatUsd
formatUsd(
usd?: bigint,
opts?: {
fallbackToZero?: boolean;
displayDecimals?: number;
maxThreshold?: string | null;
minThreshold?: string;
displayPlus?: boolean;
visualMultiplier?: number;
}
): string | undefined
Formats a bigint USD amount (30-decimal precision) into a display string. Returns undefined if usd is not a bigint and fallbackToZero is not set. Default displayDecimals is 2.
import { formatUsd, expandDecimals, USD_DECIMALS } from "@gmx-io/sdk/utils/numbers";
const amount = expandDecimals(1234, USD_DECIMALS);
formatUsd(amount); // "$1,234.00"
formatUsd(amount, { displayPlus: true }); // "+$1,234.00"
formatUsd(-amount); // "-$1,234.00"
formatUsd(undefined); // undefined
formatUsd(undefined, { fallbackToZero: true }); // "$0.00"
formatBigUsd
formatBigUsd(amount: bigint, opts?: { displayDecimals?: number }): string
Formats a USD bigint using a very high upper threshold (9999999999999999999999999) so that the > prefix is effectively suppressed for all practical values. Defaults to zero decimal places, making it suitable for displaying large round numbers like total liquidity.
import { formatBigUsd, expandDecimals, USD_DECIMALS } from "@gmx-io/sdk/utils/numbers";
formatBigUsd(expandDecimals(999_999_999_999, USD_DECIMALS)); // "$999,999,999,999"
formatDeltaUsd
formatDeltaUsd(
deltaUsd?: bigint,
percentage?: bigint,
opts?: { fallbackToZero?: boolean; showPlusForZero?: boolean; hidePercentage?: boolean }
): string | undefined
Formats a signed USD change with an optional percentage label. Returns undefined if deltaUsd is not a bigint and fallbackToZero is not set.
import { formatDeltaUsd, expandDecimals, USD_DECIMALS } from "@gmx-io/sdk/utils/numbers";
const delta = expandDecimals(150, USD_DECIMALS);
const pct = expandDecimals(5, 2); // 5% expressed in basis points
formatDeltaUsd(delta, pct); // "+$150.00 (+5.00%)"
formatDeltaUsd(-delta, pct); // "-$150.00 (+5.00%)"
formatDeltaUsd(delta, pct, { hidePercentage: true }); // "+$150.00"
formatPercentage
formatPercentage(
percentage?: bigint,
opts?: {
fallbackToZero?: boolean;
signed?: boolean;
displayDecimals?: number;
bps?: boolean;
showPlus?: boolean;
}
): string | undefined
Formats a percentage value. When bps is true (the default), treats the input as a basis-point-scaled value with 2 decimal places of precision. When bps is false, treats the input as PERCENT_PRECISION_DECIMALS-scaled (28 decimal places).
import { formatPercentage } from "@gmx-io/sdk/utils/numbers";
// Input in basis points (bps = true by default)
formatPercentage(525n); // "5.25%"
formatPercentage(525n, { signed: true }); // "+5.25%"
formatPercentage(525n, { displayDecimals: 1 }); // "5.3%"
formatPercentage(undefined, { fallbackToZero: true }); // "0.00%"
formatRatePercentage
formatRatePercentage(rate?: bigint, opts?: { displayDecimals?: number; signed?: boolean }): string
Formats a PRECISION-scaled rate as a percentage. The signed option defaults to true, so the result includes + or - by default. Returns "-" if rate is not a bigint.
import { formatRatePercentage, expandDecimals } from "@gmx-io/sdk/utils/numbers";
const rate = expandDecimals(5, 28); // 0.05 PRECISION-scaled (5%)
formatRatePercentage(rate); // "+5.0000%"
formatRatePercentage(rate, { signed: false }); // "5.0000%"
formatRatePercentage(rate, { displayDecimals: 2 }); // "+5.00%"
formatRatePercentage(undefined); // "-"
formatUsdPrice
formatUsdPrice(price?: bigint, opts?: Parameters<typeof formatUsd>[1]): string | undefined
Formats a USD price with dynamic decimal precision based on price magnitude (via calculateDisplayDecimals). Returns undefined for undefined input, and "NA" for negative prices.
import { formatUsdPrice, expandDecimals, USD_DECIMALS } from "@gmx-io/sdk/utils/numbers";
formatUsdPrice(expandDecimals(2500, USD_DECIMALS)); // "$2,500.00"
formatUsdPrice(expandDecimals(1, 27)); // "$0.001000" (more decimals for small prices)
formatUsdPrice(undefined); // undefined
formatUsdPrice(-expandDecimals(1, USD_DECIMALS)); // "NA"
formatPercentageDisplay
formatPercentageDisplay(percentage: number, hideThreshold?: number): string
Formats a plain JavaScript number as a percentage string. Returns an empty string if the value is below hideThreshold.
import { formatPercentageDisplay } from "@gmx-io/sdk/utils/numbers";
formatPercentageDisplay(5.25); // "5.25%"
formatPercentageDisplay(0.5, 1); // "" (hidden, 0.5 < 1)
formatPercentageDisplay(1.0, 1); // "1%" (returned, 1.0 is not < 1)
formatAmountHuman
formatAmountHuman(
amount: BigNumberish | undefined,
tokenDecimals: number,
showDollar?: boolean,
displayDecimals?: number
): string
Formats a scaled bigint amount as a compact human-readable string using k, m, or b suffixes. Returns "..." if amount is undefined. Default displayDecimals is 1.
import { formatAmountHuman, expandDecimals } from "@gmx-io/sdk/utils/numbers";
formatAmountHuman(expandDecimals(1_500_000, 18), 18); // "1.5m"
formatAmountHuman(expandDecimals(2_500_000_000, 18), 18, true); // "$2.5b"
formatAmountHuman(expandDecimals(750, 18), 18); // "750.0"
formatAmountHuman(undefined, 18); // "..."
formatTokenAmount
formatTokenAmount(
amount?: bigint,
tokenDecimals?: number,
symbol?: string,
opts?: {
showAllSignificant?: boolean;
displayDecimals?: number;
fallbackToZero?: boolean;
useCommas?: boolean;
minThreshold?: string;
maxThreshold?: string;
displayPlus?: boolean;
isStable?: boolean;
}
): string | undefined
Formats a token amount with an optional symbol. Automatically selects displayDecimals based on value magnitude using calculateDisplayDecimals unless you override it. Returns undefined if input is invalid and fallbackToZero is not set.
import { formatTokenAmount, expandDecimals } from "@gmx-io/sdk/utils/numbers";
const amount = expandDecimals(1234, 18);
formatTokenAmount(amount, 18, "ETH"); // "1,234.0000 ETH"
formatTokenAmount(amount, 18, "ETH", { isStable: true }); // "1,234.00 ETH"
formatTokenAmount(amount, 18, "ETH", { displayPlus: true }); // "+1,234.0000 ETH"
formatTokenAmount(undefined, 18, "ETH"); // undefined
formatTokenAmount(undefined, 18, "ETH", { fallbackToZero: true }); // "0.0000 ETH"
formatTokenAmountWithUsd
formatTokenAmountWithUsd(
tokenAmount?: bigint,
usdAmount?: bigint,
tokenSymbol?: string,
tokenDecimals?: number,
opts?: { fallbackToZero?: boolean; displayDecimals?: number; displayPlus?: boolean; isStable?: boolean }
): string | undefined
Formats a token amount followed by its USD equivalent in parentheses. Returns undefined if any required argument is missing and fallbackToZero is not set.
import { formatTokenAmountWithUsd, expandDecimals, USD_DECIMALS } from "@gmx-io/sdk/utils/numbers";
formatTokenAmountWithUsd(expandDecimals(1, 18), expandDecimals(2500, USD_DECIMALS), "ETH", 18); // "1.0000 ETH ($2,500.00)"
formatBalanceAmount
formatBalanceAmount(
amount: bigint,
tokenDecimals: number,
tokenSymbol?: string,
opts?: { showZero?: boolean; toExponential?: boolean; isStable?: boolean; signed?: boolean }
): string
Formats a balance with dynamic decimal precision. Returns "-" for zero by default. Switches to exponential notation for values below 1e-8 when toExponential is true (the default).
import { formatBalanceAmount, expandDecimals } from "@gmx-io/sdk/utils/numbers";
formatBalanceAmount(expandDecimals(123, 15), 18, "ETH"); // "0.000123 ETH"
formatBalanceAmount(0n, 18, "ETH"); // "-"
formatBalanceAmount(0n, 18, "ETH", { showZero: true }); // "0.0000 ETH"
formatFactor
formatFactor(factor: bigint): string
Formats a PRECISION-scaled factor as a human-readable string with the minimum decimal places needed to represent the value. For factors larger than PRECISION * 1000, it returns the integer quotient.
import { formatFactor, expandDecimals } from "@gmx-io/sdk/utils/numbers";
formatFactor(expandDecimals(15, 29)); // "1.5"
formatFactor(expandDecimals(2, 30)); // "2"
formatFactor(0n); // "0"
numberWithCommas
numberWithCommas(x: BigNumberish, opts?: { showDollar?: boolean }): string
Adds comma thousand-separators to a number string. Returns "..." if the input is undefined or null.
import { numberWithCommas } from "@gmx-io/sdk/utils/numbers";
numberWithCommas(1234567); // "1,234,567"
numberWithCommas(1234567.89); // "1,234,567.89"
numberWithCommas(1234567, { showDollar: true }); // "$1,234,567"
calculateDisplayDecimals
calculateDisplayDecimals(
price?: bigint,
decimals?: number,
visualMultiplier?: number,
isStable?: boolean
): number
Determines the appropriate number of decimal places to display for a price, based on its magnitude. Defaults to USD_DECIMALS (30) for decimals. Returns 2 for undefined or 0n inputs. Stable tokens use a different scale that favors more decimal places at smaller values.
import { calculateDisplayDecimals, expandDecimals, USD_DECIMALS } from "@gmx-io/sdk/utils/numbers";
calculateDisplayDecimals(expandDecimals(2500, USD_DECIMALS)); // 2 (price >= 1000)
calculateDisplayDecimals(expandDecimals(50, USD_DECIMALS)); // 4 (price >= 1)
calculateDisplayDecimals(expandDecimals(1, 27)); // 6 (price >= 0.01)
calculateDisplayDecimals(undefined); // 2 (default)
getPlusOrMinusSymbol
getPlusOrMinusSymbol(value?: bigint, opts?: { showPlusForZero?: boolean }): string
Returns "+" for positive values, "-" for negative values, and "" for zero. Pass showPlusForZero: true to return "+" for zero.
import { getPlusOrMinusSymbol } from "@gmx-io/sdk/utils/numbers";
getPlusOrMinusSymbol(100n); // "+"
getPlusOrMinusSymbol(-100n); // "-"
getPlusOrMinusSymbol(0n); // ""
getPlusOrMinusSymbol(0n, { showPlusForZero: true }); // "+"
getPlusOrMinusSymbol(undefined); // ""
Object serialization
The SDK serializes bigint values to JSON-safe objects using a { type: "bigint", value: "..." } envelope. Use these functions when you need to store or transmit SDK state as JSON.
serializeBigIntsInObject
serializeBigIntsInObject<T extends object>(obj: T): SerializedBigIntsInObject<T>
Recursively converts every bigint value in an object (or array) to { type: "bigint", value: string }. Non-bigint values are passed through unchanged. The returned type reflects the transformation.
import { serializeBigIntsInObject } from "@gmx-io/sdk/utils/numbers";
const position = { size: 1000000000000000000000000000000n, symbol: "ETH" };
const serialized = serializeBigIntsInObject(position);
// { size: { type: "bigint", value: "1000000000000000000000000000000" }, symbol: "ETH" }
JSON.stringify(serialized); // works — no BigInt serialization error
deserializeBigIntsInObject
deserializeBigIntsInObject<T extends object>(
obj: T,
opts?: { handleInts?: boolean }
): DeserializeBigIntInObject<T>
Reverses serializeBigIntsInObject, converting { type: "bigint", value: string } envelopes back to native bigint. Also handles legacy { _type: "BigNumber", hex: string } format. When handleInts is true, it also converts plain numeric strings to bigint.
import { deserializeBigIntsInObject } from "@gmx-io/sdk/utils/numbers";
const stored = { size: { type: "bigint", value: "1000000000000000000000000000000" } };
const position = deserializeBigIntsInObject(stored);
// { size: 1000000000000000000000000000000n }