Skip to main content

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.

TypeDefinitionDescription
Numericnumber | bigintA value that is either a JavaScript number or a bigint.
BigNumberishstring | NumericA 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>
}
note

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

ConstantValueDescription
USD_DECIMALS30Decimal precision for USD values. All USD amounts are stored as bigint scaled by 10^30.
PRECISION_DECIMALS30The number of decimal places in the PRECISION scaling factor.
PRECISION10n ** 30nScaling factor used in multiplications before division to preserve decimal precision.
PERCENT_PRECISION_DECIMALS28Decimal precision for percentage values (PRECISION_DECIMALS - 2).

Float precision

ConstantValueDescription
FLOAT_PRECISION_SQRT_DECIMALS15Decimal precision for square-root-scaled float values.
FLOAT_PRECISION_SQRT10n ** 15nSquare root of PRECISION, used in intermediate calculations that require reduced-precision float arithmetic.

Basis points

ConstantValueDescription
BASIS_POINTS_DIVISOR10000Divisor for basis point calculations as a number.
BASIS_POINTS_DIVISOR_BIGINT10000nSame divisor as a bigint, for use in bigint arithmetic.
BASIS_POINTS_DECIMALS4Number of decimal places represented by basis points (1 bps = 0.0001).

BigInt sentinel values

ConstantValueDescription
BN_ZERO0nReusable bigint zero.
BN_ONE1nReusable bigint one.
BN_NEGATIVE_ONE-1nReusable bigint negative one.
MaxUint2562n ** 256n - 1nMaximum value of a 256-bit unsigned integer.
MaxInt2562n ** 255n - 1nMaximum value of a 256-bit signed integer.

Display threshold prefixes

ConstantValueDescription
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 -∞)
note

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)
note

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
note

parseValue caps the result at 10^62 to prevent downstream bigint overflow. Values above this threshold return undefined.

toBigNumberWithDecimals

warning

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

warning

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 }