Skip to main content

swapRouting

This module provides utilities for finding optimal swap routes between tokens in GMX markets. It includes functions for creating swap estimators, finding best swap paths, and working with market adjacency graphs to determine the most efficient routes for token swaps.

Methods

The swapRouting module exports two categories of functions: estimator factories that produce closures used to score and compare routes, and path selection utilities that use those estimators to find the best route through the market graph.

Estimator factories

These functions return closures (estimators) rather than results. You create them once per session with the current market data, then call them repeatedly during path evaluation.

createSwapEstimator

createSwapEstimator(marketsInfoData: MarketsInfoData, swapPricingType: SwapPricingType): SwapEstimator

Creates an accurate swap estimator that computes the exact USD output for a MarketEdge and a USD input. It applies price impact and checks liquidity/capacity limits. Returns { usdOut: 0n } for disabled markets or when the swap would exceed available liquidity or capacity.

Use this estimator with getBestSwapPath for the final route selection pass.

import { createSwapEstimator } from "@gmx-io/sdk/utils/swap";
import { SwapPricingType } from "@gmx-io/sdk/utils/orders";

const estimator = createSwapEstimator(marketsInfoData, SwapPricingType.Swap);

// Evaluate a single edge: USDC → WETH via a specific market
const edge = { marketAddress: "0xMarketAddress", from: "0xUSDC", to: "0xWETH" };
const { usdOut } = estimator(edge, 1000n * 10n ** 30n); // 1000 USD in
note

The second parameter is swapPricingType (a SwapPricingType enum), not isAtomicSwap as earlier documentation stated. The swap pricing type determines whether price impact uses the standard swap formula or the two-step atomic swap formula.

createMarketEdgeLiquidityGetter

createMarketEdgeLiquidityGetter(marketsInfoData: MarketsInfoData): MarketEdgeLiquidityGetter

Creates a function that returns the available USD liquidity for the output token pool of a MarketEdge. Returns 0n for disabled markets.

Use this with getMaxLiquidityMarketSwapPathFromTokenSwapPaths and getMaxLiquidityMarketForTokenEdge to find the highest-capacity route.

import { createMarketEdgeLiquidityGetter } from "@gmx-io/sdk/utils/swap";

const getLiquidity = createMarketEdgeLiquidityGetter(marketsInfoData);

const edge = { marketAddress: "0xMarketAddress", from: "0xUSDC", to: "0xWETH" };
const availableLiquidity = getLiquidity(edge); // bigint in USD (30 decimals)

createNaiveSwapEstimator

createNaiveSwapEstimator(marketsInfoData: MarketsInfoData, swapPricingType: SwapPricingType): NaiveSwapEstimator

Creates a fast swap estimator for use in the path pre-selection phase. Instead of returning usdOut as a bigint, it returns swapYield as a plain number ratio (for example, 0.998 means 0.2% slippage). Returns { swapYield: 0 } when capacity, liquidity, or output is zero.

Use this with getNaiveBestMarketSwapPathsFromTokenSwapPaths to quickly narrow down the top candidate paths before running the accurate estimator.

import { createNaiveSwapEstimator } from "@gmx-io/sdk/utils/swap";
import { SwapPricingType } from "@gmx-io/sdk/utils/orders";

const naiveEstimator = createNaiveSwapEstimator(marketsInfoData, SwapPricingType.Swap);

const edge = { marketAddress: "0xMarketAddress", from: "0xUSDC", to: "0xWETH" };
const { swapYield } = naiveEstimator(edge, 1000n * 10n ** 30n);
// swapYield > 1.0 means favorable swap (output exceeds input in USD terms)
// swapYield < 1.0 means unfavorable swap (price impact)
note

swapYield is a ratio: usdOut / usdIn. A value of 1.1 means the output is 10% larger than the input; 0.9 means 10% less.

createNaiveNetworkEstimator

createNaiveNetworkEstimator(config: {
gasLimits: GasLimitsConfig;
tokensData: TokensData;
gasPrice: bigint;
chainId: number;
}): NaiveNetworkEstimator

Creates a network cost estimator that penalizes swap routes by their estimated execution fee. The returned estimator takes (usdIn, swapsCount) and returns { networkYield, usdOut } where networkYield is the fraction of input USD retained after gas costs.

If the execution fee cannot be computed (for example, missing token price data), it returns { networkYield: 1.0, usdOut: usdIn } as a safe fallback.

import { createNaiveNetworkEstimator } from "@gmx-io/sdk/utils/swap";

const networkEstimator = createNaiveNetworkEstimator({
gasLimits,
tokensData,
gasPrice: 100000000n, // 0.1 gwei
chainId: 42161, // Arbitrum
});

// How much USD remains after 2 swaps, accounting for execution fee?
const { networkYield, usdOut } = networkEstimator(1000n * 10n ** 30n, 2);
// networkYield ≈ 0.997 if execution fee is ~$3

Path selection utilities

getBestSwapPath

getBestSwapPath(params: {
routes: MarketEdge[][];
usdIn: bigint;
estimator: SwapEstimator;
networkEstimator?: NaiveNetworkEstimator;
}): MarketEdge[] | undefined

Evaluates every route in routes by chaining the estimator across each edge and returns the route with the highest usdOut. When networkEstimator is provided, it adjusts the final USD output for execution fee before comparing routes.

Returns undefined only when routes is empty. If all routes produce zero output (for example, all paths are out of liquidity), it returns the first route.

import {
createSwapEstimator,
createNaiveNetworkEstimator,
getBestSwapPath,
marketRouteToMarketEdges,
} from "@gmx-io/sdk/utils/swap";
import { SwapPricingType } from "@gmx-io/sdk/utils/orders";

const estimator = createSwapEstimator(marketsInfoData, SwapPricingType.Swap);
const networkEstimator = createNaiveNetworkEstimator({ gasLimits, tokensData, gasPrice, chainId: 42161 });

// Convert market address paths to MarketEdge arrays
const routes = marketPaths.map((path) => marketRouteToMarketEdges(path, fromTokenAddress, marketsInfoData));

const bestRoute = getBestSwapPath({ routes, usdIn, estimator, networkEstimator });

getNaiveBestMarketSwapPathsFromTokenSwapPaths

getNaiveBestMarketSwapPathsFromTokenSwapPaths(params: {
graph: MarketsGraph;
tokenSwapPaths: string[][];
usdIn: bigint;
tokenInAddress: string;
tokenOutAddress: string;
estimator: NaiveSwapEstimator;
topPathsCount?: number; // default: 3
networkEstimator?: NaiveNetworkEstimator;
}): string[][]

Evaluates token-level swap paths using the naive estimator and returns the top market paths by swap yield. The default topPathsCount is 3.

For each token-level hop, it independently selects the best market using getBestMarketForTokenEdge, then accumulates the path's total yield. Paths with zero yield on any hop are discarded. When networkEstimator is provided, it adjusts yields to account for execution fee when comparing against the current top paths.

import {
createNaiveSwapEstimator,
createNaiveNetworkEstimator,
getNaiveBestMarketSwapPathsFromTokenSwapPaths,
getTokenSwapPathsForTokenPairPrebuilt,
getMarketAdjacencyGraph,
} from "@gmx-io/sdk/utils/swap";
import { SwapPricingType } from "@gmx-io/sdk/utils/orders";

const chainId = 42161; // Arbitrum
const graph = getMarketAdjacencyGraph(chainId);
const tokenSwapPaths = getTokenSwapPathsForTokenPairPrebuilt(chainId, wethAddress, usdcAddress);

const naiveEstimator = createNaiveSwapEstimator(marketsInfoData, SwapPricingType.Swap);
const networkEstimator = createNaiveNetworkEstimator({ gasLimits, tokensData, gasPrice, chainId });

const topMarketPaths = getNaiveBestMarketSwapPathsFromTokenSwapPaths({
graph,
tokenSwapPaths,
usdIn: 1000n * 10n ** 30n,
tokenInAddress: wethAddress,
tokenOutAddress: usdcAddress,
estimator: naiveEstimator,
topPathsCount: 3,
networkEstimator,
});
// Returns up to 3 arrays of market addresses, sorted by estimated yield

getMarketsForTokenPair

getMarketsForTokenPair(graph: MarketsGraph, tokenAAddress: string, tokenBAddress: string): string[]

Looks up the market addresses that support a direct swap between tokenAAddress and tokenBAddress. The lookup is symmetric — it checks both graph[A][B] and graph[B][A]. Returns an empty array if no market connects the pair.

import { getMarketsForTokenPair, getMarketAdjacencyGraph } from "@gmx-io/sdk/utils/swap";

const graph = getMarketAdjacencyGraph(42161);
const markets = getMarketsForTokenPair(graph, wethAddress, usdcAddress);
// markets: ["0xETH-USD-MarketAddress", ...]

getBestMarketForTokenEdge

getBestMarketForTokenEdge(params: {
marketAddresses: string[];
usdIn: bigint;
tokenInAddress: string;
tokenOutAddress: string;
estimator: NaiveSwapEstimator;
marketPath?: string[];
calculatedCache?: Record<string, number>;
}): { marketAddress: string; swapYield: number } | undefined

From a list of candidate markets, selects the one with the highest swapYield for the given token edge. Markets already present in marketPath are skipped to prevent routing through the same market twice. Returns undefined if all candidates have zero yield.

The optional calculatedCache avoids recomputing yields for markets that have already been evaluated in the current routing pass.

import { getBestMarketForTokenEdge } from "@gmx-io/sdk/utils/swap";

const best = getBestMarketForTokenEdge({
marketAddresses: ["0xMarket1", "0xMarket2"],
usdIn: 500n * 10n ** 30n,
tokenInAddress: wethAddress,
tokenOutAddress: usdcAddress,
estimator: naiveEstimator,
});

if (best) {
// best.marketAddress — address of the best market
// best.swapYield — ratio, for example 0.998 for 0.2% slippage
}

marketRouteToMarketEdges

marketRouteToMarketEdges(marketPath: string[], from: string, marketsInfoData: MarketsInfoData): MarketEdge[]

Converts a sequence of market addresses into a sequence of MarketEdge objects. For each market, it determines from and to token addresses by inspecting the market's longTokenAddress and shortTokenAddress and comparing with the current input token.

import { marketRouteToMarketEdges } from "@gmx-io/sdk/utils/swap";

// Convert a 2-hop path [ETH-USD market, USDC-BTC market] into edges
const edges = marketRouteToMarketEdges(["0xETHUSDMarket", "0xUSDCBTCMarket"], wethAddress, marketsInfoData);
// edges[0]: { marketAddress: "0xETHUSDMarket", from: wethAddress, to: usdcAddress }
// edges[1]: { marketAddress: "0xUSDCBTCMarket", from: usdcAddress, to: wbtcAddress }

getTokenSwapPathsForTokenPair

getTokenSwapPathsForTokenPair(tokenSwapPaths: SwapPaths, tokenAAddress: string, tokenBAddress: string): string[][]

Retrieves all intermediate token paths between tokenAAddress and tokenBAddress from a SwapPaths data structure. The lookup is symmetric — if only B → A paths exist, they are reversed to produce A → B paths.

Each returned path is a list of intermediate token addresses (not including the start and end tokens).

import { getTokenSwapPathsForTokenPair } from "@gmx-io/sdk/utils/swap";

// All intermediate-token paths from WETH to USDC
const paths = getTokenSwapPathsForTokenPair(tokenSwapPaths, wethAddress, usdcAddress);
// paths: [[], ["0xWBTC"], ["0xLINK", "0xWBTC"]] (direct, 1-hop, 2-hop)

getTokenSwapPathsForTokenPairPrebuilt

getTokenSwapPathsForTokenPairPrebuilt(chainId: number, from: string, to: string): string[][]

Convenience wrapper that retrieves precomputed token swap paths for a chain without requiring you to load the SwapPaths data separately. Internally delegates to getTokenSwapPathsForTokenPair using the prebuilt TOKEN_SWAP_PATHS for the chain.

import { getTokenSwapPathsForTokenPairPrebuilt } from "@gmx-io/sdk/utils/swap";

const paths = getTokenSwapPathsForTokenPairPrebuilt(42161, wethAddress, usdcAddress);

getMarketAdjacencyGraph

getMarketAdjacencyGraph(chainId: number): MarketsGraph

Returns the prebuilt market adjacency graph for a chain. The graph maps tokenA → tokenB → marketAddress[], enabling O(1) market lookups for any token pair.

import { getMarketAdjacencyGraph } from "@gmx-io/sdk/utils/swap";

const graph = getMarketAdjacencyGraph(42161); // Arbitrum
// graph["0xWETH"]["0xUSDC"] → ["0xETH-USD-MarketAddress"]

findAllReachableTokens

findAllReachableTokens(chainId: number, from: string): string[]

Returns all token addresses reachable from from via at most MAX_EDGE_PATH_LENGTH hops (currently 3) on the given chain. This uses precomputed reachability data for O(1) lookup.

import { findAllReachableTokens } from "@gmx-io/sdk/utils/swap";

const reachable = findAllReachableTokens(42161, wethAddress);
// reachable: ["0xUSDC", "0xWBTC", "0xARB", ...]

getMaxLiquidityMarketSwapPathFromTokenSwapPaths

getMaxLiquidityMarketSwapPathFromTokenSwapPaths(params: {
graph: MarketsGraph;
tokenSwapPaths: string[][];
tokenInAddress: string;
tokenOutAddress: string;
getLiquidity: MarketEdgeLiquidityGetter;
}): { path: string[]; liquidity: bigint } | undefined

Finds the swap path with the greatest bottleneck liquidity across all candidate paths. For a multi-hop path, liquidity is the minimum available liquidity across all hops — the path's capacity is limited by its weakest link.

Returns undefined if no valid path exists.

import {
createMarketEdgeLiquidityGetter,
getMaxLiquidityMarketSwapPathFromTokenSwapPaths,
getTokenSwapPathsForTokenPairPrebuilt,
getMarketAdjacencyGraph,
} from "@gmx-io/sdk/utils/swap";

const chainId = 42161;
const graph = getMarketAdjacencyGraph(chainId);
const tokenSwapPaths = getTokenSwapPathsForTokenPairPrebuilt(chainId, wethAddress, usdcAddress);
const getLiquidity = createMarketEdgeLiquidityGetter(marketsInfoData);

const result = getMaxLiquidityMarketSwapPathFromTokenSwapPaths({
graph,
tokenSwapPaths,
tokenInAddress: wethAddress,
tokenOutAddress: usdcAddress,
getLiquidity,
});

if (result) {
// result.path — array of market addresses
// result.liquidity — minimum available liquidity across all hops (bigint, USD 30-decimal)
}

getMaxLiquidityMarketForTokenEdge

getMaxLiquidityMarketForTokenEdge(params: {
markets: string[];
tokenInAddress: string;
tokenOutAddress: string;
getLiquidity: MarketEdgeLiquidityGetter;
}): { marketAddress: string; liquidity: bigint }

From a list of candidate markets for a single token edge, selects the one with the most available output-side liquidity. Always returns a result (using the first market as a fallback if all have zero liquidity).

import { getMaxLiquidityMarketForTokenEdge } from "@gmx-io/sdk/utils/swap";

const best = getMaxLiquidityMarketForTokenEdge({
markets: ["0xMarket1", "0xMarket2"],
tokenInAddress: wethAddress,
tokenOutAddress: usdcAddress,
getLiquidity,
});
// best.marketAddress — market with most liquidity
// best.liquidity — available USD liquidity (bigint, 30 decimals)