# Table of Contents
- [Markdown page example | GMX Docs](#markdown-page-example-gmx-docs)
- [Search the documentation](#search-the-documentation)
- [Plugins and Skills | GMX Docs](#plugins-and-skills-gmx-docs)
- [AI Agents | GMX Docs](#ai-agents-gmx-docs)
- [GlvReader | GMX Docs](#glvreader-gmx-docs)
- [Delegated trading integration | GMX Docs](#delegated-trading-integration-gmx-docs)
- [Contract addresses | GMX Docs](#contract-addresses-gmx-docs)
- [Event monitoring | GMX Docs](#event-monitoring-gmx-docs)
- [Fees | GMX Docs](#fees-gmx-docs)
- [Advanced entry points | GMX Docs](#advanced-entry-points-gmx-docs)
- [Architecture | GMX Docs](#architecture-gmx-docs)
- [ExchangeRouter | GMX Docs](#exchangerouter-gmx-docs)
- [Frontend Integration | GMX Docs](#frontend-integration-gmx-docs)
- [GlvRouter | GMX Docs](#glvrouter-gmx-docs)
- [Known issues | GMX Docs](#known-issues-gmx-docs)
- [Overview | GMX Docs](#overview-gmx-docs)
- [Reader | GMX Docs](#reader-gmx-docs)
- [Simulations | GMX Docs](#simulations-gmx-docs)
- [GetAnnualized | GMX Docs](#getannualized-gmx-docs)
- [GetApy | GMX Docs](#getapy-gmx-docs)
- [GetPositionsInfo | GMX Docs](#getpositionsinfo-gmx-docs)
- [GMX Docs](#gmx-docs)
- [GMX Docs](#gmx-docs)
- [GMX Docs](#gmx-docs)
- [GMX Docs](#gmx-docs)
- [@gmx-io/gmx-public-api | GMX Docs](#-gmx-io-gmx-public-api-gmx-docs)
- [GetLiquidityInfo | GMX Docs](#getliquidityinfo-gmx-docs)
- [GetTokens | GMX Docs](#gettokens-gmx-docs)
- [GetTokensInfo | GMX Docs](#gettokensinfo-gmx-docs)
- [Troubleshooting | GMX Docs](#troubleshooting-gmx-docs)
- [GMX Docs](#gmx-docs)
- [GetSnapshots | GMX Docs](#getsnapshots-gmx-docs)
- [GetOhlcv | GMX Docs](#getohlcv-gmx-docs)
- [GetMarkets | GMX Docs](#getmarkets-gmx-docs)
- [Fallback URLs | GMX Docs](#fallback-urls-gmx-docs)
- [Markets | GMX Docs](#markets-gmx-docs)
- [Liquidity | GMX Docs](#liquidity-gmx-docs)
- [Contracts for V1 | GMX Docs](#contracts-for-v1-gmx-docs)
- [Updates and Support | GMX Docs](#updates-and-support-gmx-docs)
- [GetMarketsTickers | GMX Docs](#getmarketstickers-gmx-docs)
- [GetMarketsInfo | GMX Docs](#getmarketsinfo-gmx-docs)
- [Oracle Prices | GMX Docs](#oracle-prices-gmx-docs)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [GetOrdersByAddress | GMX Docs](#getordersbyaddress-gmx-docs)
- [Archived | GMX Docs](#archived-gmx-docs)
- [Contracts | GMX Docs](#contracts-gmx-docs)
- [GetPairs | GMX Docs](#getpairs-gmx-docs)
- [Tokenomics | GMX Docs](#tokenomics-gmx-docs)
- [Changelog | GMX Docs](#changelog-gmx-docs)
- [Referrals | GMX Docs](#referrals-gmx-docs)
- [Useful modules | GMX Docs](#useful-modules-gmx-docs)
- [Examples | GMX Docs](#examples-gmx-docs)
- [AI Agents | GMX Docs](#ai-agents-gmx-docs)
- [Trading on V1 | GMX Docs](#trading-on-v1-gmx-docs)
- [API v1 (REST API) | GMX Docs](#api-v1-rest-api-gmx-docs)
- [API | GMX Docs](#api-gmx-docs)
- [Governance | GMX Docs](#governance-gmx-docs)
- [SDK | GMX Docs](#sdk-gmx-docs)
- [API v2 (OpenAPI Reference) | GMX Docs](#api-v2-openapi-reference-gmx-docs)
- [Trading | GMX Docs](#trading-gmx-docs)
- [Community | GMX Docs](#community-gmx-docs)
- [Proposal Process | GMX Docs](#proposal-process-gmx-docs)
- [Voting power | GMX Docs](#voting-power-gmx-docs)
- [GMX | GMX Docs](#gmx-gmx-docs)
- [Providing liquidity | GMX Docs](#providing-liquidity-gmx-docs)
- [SDK Overview | GMX Docs](#sdk-overview-gmx-docs)
- [Getting Started | GMX Docs](#getting-started-gmx-docs)
- [Security | GMX Docs](#security-gmx-docs)
- [Troubleshooting | GMX Docs](#troubleshooting-gmx-docs)
- [GMX token | GMX Docs](#gmx-token-gmx-docs)
- [Getting Started | GMX Docs](#getting-started-gmx-docs)
- [Direct URLs | GMX Docs](#direct-urls-gmx-docs)
- [Rewards | GMX Docs](#rewards-gmx-docs)
- [Integration guide | GMX Docs](#integration-guide-gmx-docs)
- [Liquidations and ADL | GMX Docs](#liquidations-and-adl-gmx-docs)
- [Trading overview | GMX Docs](#trading-overview-gmx-docs)
- [Fees | GMX Docs](#fees-gmx-docs)
- [Positions and order types | GMX Docs](#positions-and-order-types-gmx-docs)
---
# Markdown page example | GMX Docs
[Skip to main content](https://docs.gmx.io/markdown-page/#__docusaurus_skipToContent_fallback)
You don't need React to write simple standalone pages.
---
# Search the documentation
[Skip to main content](https://docs.gmx.io/search/#__docusaurus_skipToContent_fallback)
Search the documentation
========================
Powered by[](https://www.algolia.com/)
---
# Plugins and Skills | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#__docusaurus_skipToContent_fallback)
On this page
The [`gmx-io/gmx-ai`](https://github.com/gmx-io/gmx-ai)
repository provides pre-built agent skills that give AI coding agents the ability to trade perpetuals, provide liquidity, and swap tokens on GMX V2. Skills use a filesystem-based format compatible with a wide range of agents — see [Installation](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#installation)
for supported clients.
note
Skills currently use [SDK v1](https://docs.gmx.io/docs/sdk/v1/)
and direct contract calls for write operations, and the [REST API](https://docs.gmx.io/docs/api/overview/)
for data access. As API v2 and SDK v2 mature, skills will migrate to fully leverage them — expanding capabilities to cover virtually any protocol action.
Available skills[](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#available-skills "Direct link to Available skills")
-------------------------------------------------------------------------------------------------------------------------------
The repository ships two skills that cover the main protocol operations.
### gmx-trading[](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#gmx-trading "Direct link to gmx-trading")
Bundles everything an AI agent needs to trade on GMX:
* **Trading operations** — Open long/short positions with up to 100x leverage, swap tokens at oracle prices, and place market, limit, stop-loss, and take-profit orders.
* **Position management** — Query open positions, pending orders, and trade history.
* **Market data** — Fetch markets, token prices, pool sizes, and utilization rates.
* **Reference material** — SDK method signatures, REST and GraphQL endpoint documentation, contract addresses for all supported chains, and order type behavior specifications.
### gmx-liquidity[](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#gmx-liquidity "Direct link to gmx-liquidity")
Covers liquidity provision across GM pools and GLV vaults:
* **GM pool operations** — Deposit into single-market pools (balanced or single-sided), withdraw, and shift liquidity between pools atomically.
* **GLV vault operations** — Deposit raw tokens or existing GM tokens into multi-market auto-rebalancing vaults, and withdraw.
* **Pool data** — Query pool TVL, composition, utilization, capacity, and GM/GLV token balances.
* **Reference material** — Contract struct definitions, execution flows, gas estimation formulas, GLV vault addresses, and viem multicall examples.
### Supported chains[](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#supported-chains "Direct link to Supported chains")
| Chain | Chain ID | Native token |
| --- | --- | --- |
| Arbitrum | 42161 | ETH |
| Avalanche | 43114 | AVAX |
| Botanix | 3637 | BTC |
| MegaETH | 4326 | ETH |
Installation[](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#installation "Direct link to Installation")
-------------------------------------------------------------------------------------------------------------------
### Claude Code[](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#claude-code "Direct link to Claude Code")
Install the GMX plugin from the Claude Code marketplace:
/plugin marketplace add gmx-io/gmx-ai/plugin install gmx-io@gmx-ai
Once installed, Claude Code can execute trades, provide liquidity, query positions, and interact with GMX markets using natural language instructions.
### Skills CLI (Codex, Cursor, Copilot, Windsurf, and others)[](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#skills-cli-codex-cursor-copilot-windsurf-and-others "Direct link to Skills CLI (Codex, Cursor, Copilot, Windsurf, and others)")
Add the skill using the [Skills CLI](https://github.com/vercel-labs/skills)
:
npx skills add gmx-io/gmx-ai
This installs both the `gmx-trading` and `gmx-liquidity` skills as filesystem-based context files that any compatible coding agent can read. Supported agents include:
* OpenAI Codex
* Cursor
* GitHub Copilot
* Windsurf
* Gemini CLI
* Amp (Sourcegraph)
* Roo Code
* Goose
* Cline
* Continue
Any agent that reads project-level instruction files from the filesystem can use the skill.
Reference files[](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#reference-files "Direct link to Reference files")
----------------------------------------------------------------------------------------------------------------------------
Both skills expose capabilities through shared and skill-specific reference files:
| Reference | Skill | Contents |
| --- | --- | --- |
| **SDK reference** | Shared | `GmxSdk` and `GmxApiSdk` class APIs, module methods, type definitions, and initialization patterns |
| **API endpoints** | Shared | Oracle REST endpoints, OpenAPI v2 endpoints, GraphQL queries, and fallback URLs per chain |
| **Contract addresses** | Shared | Deployed contract addresses for ExchangeRouter, Reader, GlvReader, vaults, and relay routers on every supported chain |
| **Order types** | Trading | Order type enum values, trigger conditions for longs and shorts, auto-cancel limits, and TWAP specifications |
| **Liquidity operations** | Liquidity | Contract struct definitions, execution flows, gas estimation formulas, GLV vault addresses, and viem multicall examples |
How agents use the skills[](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#how-agents-use-the-skills "Direct link to How agents use the skills")
----------------------------------------------------------------------------------------------------------------------------------------------------------
When an AI agent has the skills installed, it can:
1. **Fetch market data** — Discover available markets, current prices, and pool conditions.
2. **Calculate fees** — Estimate execution fees, position fees, and price impact before placing orders.
3. **Open positions** — Create long or short positions with specified leverage and collateral.
4. **Set conditional orders** — Place limit entries, stop-losses, and take-profit orders.
5. **Monitor positions** — Check open positions, unrealized PnL, and pending orders.
6. **Close positions** — Compute decrease amounts and submit close orders.
7. **Swap tokens** — Execute token swaps at oracle-determined prices.
8. **Deposit liquidity** — Deposit into GM pools (balanced or single-sided) and GLV vaults.
9. **Withdraw liquidity** — Withdraw from GM pools and GLV vaults.
10. **Shift liquidity** — Move GM tokens between pools atomically without withdrawing first.
Repository structure[](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#repository-structure "Direct link to Repository structure")
-------------------------------------------------------------------------------------------------------------------------------------------
gmx-io/gmx-ai/ .well-known/skills/ # Vercel Skills protocol index.json # Skill registry gmx-trading/ SKILL.md # Trading skill definition references/ sdk-reference.md # SDK API reference (shared) api-endpoints.md # REST and GraphQL endpoints (shared) contract-addresses.md # Deployed contracts per chain (shared) order-types.md # Order type specifications gmx-liquidity/ SKILL.md # Liquidity skill definition references/ liquidity-operations.md # Contract structs, flows, gas formulas plugins/gmx-io/ # Claude Code plugin .claude-plugin/ plugin.json # Plugin manifest skills/ gmx-trading/ # Trading skill files (mirrored) gmx-liquidity/ # Liquidity skill files (mirrored)
Links[](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#links "Direct link to Links")
----------------------------------------------------------------------------------------------
* **Repository:** [github.com/gmx-io/gmx-ai](https://github.com/gmx-io/gmx-ai)
* **SDK package:** [`@gmx-io/sdk` on npm](https://www.npmjs.com/package/@gmx-io/sdk)
* **SDK documentation:** [SDK overview](https://docs.gmx.io/docs/sdk/overview/)
* **API documentation:** [API overview](https://docs.gmx.io/docs/api/overview/)
* **GMX app:** [app.gmx.io](https://app.gmx.io/)
* [Available skills](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#available-skills)
* [gmx-trading](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#gmx-trading)
* [gmx-liquidity](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#gmx-liquidity)
* [Supported chains](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#supported-chains)
* [Installation](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#installation)
* [Claude Code](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#claude-code)
* [Skills CLI (Codex, Cursor, Copilot, Windsurf, and others)](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#skills-cli-codex-cursor-copilot-windsurf-and-others)
* [Reference files](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#reference-files)
* [How agents use the skills](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#how-agents-use-the-skills)
* [Repository structure](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#repository-structure)
* [Links](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/#links)
---
# AI Agents | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/ai-agents/overview/#__docusaurus_skipToContent_fallback)
On this page
GMX is built for both humans and AI agents. The protocol's oracle-based pricing, deterministic execution, and comprehensive APIs make it the ideal venue for autonomous on-chain perpetual and spot trading.
Why GMX for AI agents[](https://docs.gmx.io/docs/ai-agents/overview/#why-gmx-for-ai-agents "Direct link to Why GMX for AI agents")
------------------------------------------------------------------------------------------------------------------------------------
Centralized exchanges require API keys, KYC approvals, and custodial trust. GMX combines self-custody with oracle-based pricing and purpose-built primitives for autonomous trading:
* **Non-custodial** — Agents hold their own keys. No exchange custody, no counterparty risk, no account freezes.
* **Permissionless** — No KYC, no API key provisioning, no rate limit negotiations. Any wallet can trade immediately.
* **Oracle-based pricing** — Execution happens at Chainlink oracle prices rather than against an internal pool curve. Price impact is determined by open interest imbalance and is predictable before submission.
* **Gasless execution** — [Express orders](https://docs.gmx.io/docs/trading/order-types/)
use EIP-712 typed data signing with Gelato Relay. Agents sign off-chain and pay relay fees in supported tokens such as USDC, WETH, or USDM instead of managing native gas tokens.
* **MEV protection** — Two-phase order execution (create then execute via keeper) prevents frontrunning and sandwich attacks. The user's intent is committed on-chain before oracle prices are included.
* **Subaccounts** — Agents operate with scoped on-chain permissions via subaccounts, never exposing the master private key.
* **Up to 100x leverage** — Trade perpetuals across major assets on Arbitrum, Avalanche, Botanix, and MegaETH. Arbitrum has the deepest liquidity and most complete feature set.
* **Multichain trading** — Agents can trade from any chain by depositing into a GMX account, which routes funds to the destination chain without manual bridging. For direct non-custodial trading without account deposits, agents interact with GMX markets on the chains where they are deployed (Arbitrum, Avalanche, Botanix, and MegaETH).
* **Structured data APIs** — REST, GraphQL, on-chain contract reads, and an [MCP server](https://docs.gmx.io/docs/ai-agents/overview/#mcp-server)
_(coming soon)_ provide every data point an agent needs: prices, positions, orders, market conditions, fees, and trade history.
* **TypeScript SDK** — The [`@gmx-io/sdk`](https://docs.gmx.io/docs/sdk/overview/)
package wraps all protocol operations into typed methods. Agents can fetch markets, calculate fees, open positions, and manage orders programmatically.
* **LLM-optimized docs** — This documentation site generates [`llms.txt`](https://docs.gmx.io/llms.txt)
and [`llms-full.txt`](https://docs.gmx.io/llms-full.txt)
bundles for direct model consumption.
Integration paths[](https://docs.gmx.io/docs/ai-agents/overview/#integration-paths "Direct link to Integration paths")
------------------------------------------------------------------------------------------------------------------------
GMX offers multiple integration paths depending on the level of control your agent needs.
| Path | Best for | Capabilities |
| --- | --- | --- |
| **[Agent plugins and skills](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/)
** | AI coding agents (Claude Code, Codex, Cursor, Copilot, Windsurf, and others) | Pre-built trading skill with SDK and API references bundled |
| **[TypeScript SDK](https://docs.gmx.io/docs/sdk/overview/)
** | Custom agents and bots | Full read + write access: markets, orders, positions, fees |
| **[REST API](https://docs.gmx.io/docs/api/overview/)
** | Lightweight data access | Oracle prices, markets, positions, orders, rates |
| **[MCP server](https://docs.gmx.io/docs/ai-agents/overview/#mcp-server)
** _(coming soon)_ | Any MCP-compatible client (Claude, ChatGPT, Codex, Cursor, Copilot, Windsurf, and others) | Market data, positions, orders, pools; trade execution via prepare/confirm |
| **[Smart contracts](https://docs.gmx.io/docs/category/contracts/)
** | Direct on-chain interaction | Full protocol access via ExchangeRouter, Reader, GlvReader |
| **[GraphQL](https://docs.gmx.io/docs/api/graphql/)
** | Historical data queries | Trade history, position events, indexed on-chain data |
### Agent plugins and skills[](https://docs.gmx.io/docs/ai-agents/overview/#agent-plugins-and-skills "Direct link to Agent plugins and skills")
The [`gmx-io/gmx-ai`](https://github.com/gmx-io/gmx-ai)
repository provides ready-to-use agent skills for AI frameworks. These skills bundle trading capabilities with SDK references, API endpoint documentation, contract addresses, and order type specifications so agents can trade on GMX without manual setup. See [Plugins and skills](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/)
for installation and usage.
### SDK for autonomous agents[](https://docs.gmx.io/docs/ai-agents/overview/#sdk-for-autonomous-agents "Direct link to SDK for autonomous agents")
The [SDK v1 (`GmxSdk`)](https://docs.gmx.io/docs/sdk/v1/)
is the recommended integration for agents that need full trading capabilities. It provides:
* Market discovery and price feeds
* Order creation (market, limit, stop-loss, take-profit)
* Position monitoring and management
* Fee estimation and execution cost calculation
* Automatic RPC batching for efficient data fetching
const { GmxSdk } = require("@gmx-io/sdk");const sdk = new GmxSdk({ chainId: 42161, rpcUrl: "https://arb1.arbitrum.io/rpc", oracleUrl: "https://arbitrum-api.gmxinfra.io", subsquidUrl: "https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql", account: walletAddress, walletClient,});// Fetch markets and open a positionconst { marketsInfoData, tokensData } = await sdk.markets.getMarketsInfo();await sdk.orders.long({ marketAddress, payTokenAddress: usdcAddress, collateralTokenAddress: longToken, payAmount: 100_000000n, leverage: 50000n,});
See the [SDK examples](https://docs.gmx.io/docs/sdk/v1/examples/)
for complete agent workflows including position monitoring and closing.
### REST API for lightweight agents[](https://docs.gmx.io/docs/ai-agents/overview/#rest-api-for-lightweight-agents "Direct link to REST API for lightweight agents")
For read-only agents or those that submit transactions separately, the [REST API](https://docs.gmx.io/docs/api/overview/)
provides oracle prices, market data, and position information over HTTP. No RPC connection or SDK installation needed.
### MCP server[](https://docs.gmx.io/docs/ai-agents/overview/#mcp-server "Direct link to MCP server")
note
The MCP server is under development and not yet available.
An [MCP](https://modelcontextprotocol.io/)
(Model Context Protocol) server is being added as a transport layer to the GMX API. MCP is an open standard supported by [70+ AI clients](https://modelcontextprotocol.io/clients)
— including Claude, ChatGPT, OpenAI Codex, Cursor, GitHub Copilot, Windsurf, JetBrains, Gemini CLI, Amazon Q, and Cline. Any MCP-compatible client can query GMX data and execute trades directly through the protocol.
The server uses SSE transport mounted alongside the existing REST API, sharing the same domain layer with no separate infrastructure required.
The MCP server ships in two phases:
* **Read-only tools** — Market data, positions, orders, pool information, and account summaries
* **Read-write tools** — Trade execution using a prepare/confirm pattern where the server returns human-readable previews and unsigned transactions, and all signing happens client-side
Supported chains[](https://docs.gmx.io/docs/ai-agents/overview/#supported-chains "Direct link to Supported chains")
---------------------------------------------------------------------------------------------------------------------
| Chain | Chain ID | Native token |
| --- | --- | --- |
| Arbitrum | 42161 | ETH |
| Avalanche | 43114 | AVAX |
| Botanix | 3637 | BTC |
| MegaETH | 4326 | ETH |
* [Why GMX for AI agents](https://docs.gmx.io/docs/ai-agents/overview/#why-gmx-for-ai-agents)
* [Integration paths](https://docs.gmx.io/docs/ai-agents/overview/#integration-paths)
* [Agent plugins and skills](https://docs.gmx.io/docs/ai-agents/overview/#agent-plugins-and-skills)
* [SDK for autonomous agents](https://docs.gmx.io/docs/ai-agents/overview/#sdk-for-autonomous-agents)
* [REST API for lightweight agents](https://docs.gmx.io/docs/ai-agents/overview/#rest-api-for-lightweight-agents)
* [MCP server](https://docs.gmx.io/docs/ai-agents/overview/#mcp-server)
* [Supported chains](https://docs.gmx.io/docs/ai-agents/overview/#supported-chains)
---
# GlvReader | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/contracts/glv-reader/#__docusaurus_skipToContent_fallback)
On this page
The `GlvReader` contract provides read-only functions for querying GMX Liquidity Vault (GLV) data from on-chain storage.
For GM market reader functions, see [Reader](https://docs.gmx.io/docs/api/contracts/reader/)
.
This page focuses on the most commonly used GLV read helpers. For the full public surface, see [`GlvReader.sol`](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/reader/GlvReader.sol)
.
Examples below assume you already have contract instances such as `glvReader` and `dataStore`, plus any required price structs.
Getting a list of GLVs[](https://docs.gmx.io/docs/api/contracts/glv-reader/#getting-a-list-of-glvs "Direct link to Getting a list of GLVs")
---------------------------------------------------------------------------------------------------------------------------------------------
Use `getGlvs` to retrieve all registered GLV vaults.
### GlvReader.getGlvs[](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvs "Direct link to GlvReader.getGlvs")
function getGlvs(DataStore dataStore, uint256 start, uint256 end) external view returns (Glv.Props[] memory)
**Example (TypeScript / ethers):**
const glvs = await glvReader.getGlvs(dataStore.address, 0, 20);
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `start` | `uint256` | Start index for pagination |
| `end` | `uint256` | End index for pagination |
**Returns:** Array of `Glv.Props`.
### Glv.Props[](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvprops "Direct link to Glv.Props")
| Field | Type | Description |
| --- | --- | --- |
| `glvToken` | `address` | Address of the GLV token |
| `longToken` | `address` | Address of the long token |
| `shortToken` | `address` | Address of the short token |
Getting GLV info with market list[](https://docs.gmx.io/docs/api/contracts/glv-reader/#getting-glv-info-with-market-list "Direct link to Getting GLV info with market list")
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Use `getGlvInfoList` to retrieve GLV vaults together with the markets each vault is exposed to.
### GlvReader.getGlvInfoList[](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvinfolist "Direct link to GlvReader.getGlvInfoList")
function getGlvInfoList(DataStore dataStore, uint256 start, uint256 end) external view returns (GlvInfo[] memory)
**Example (TypeScript / ethers):**
const glvInfoList = await glvReader.getGlvInfoList(dataStore.address, 0, 20);
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `start` | `uint256` | Start index for pagination |
| `end` | `uint256` | End index for pagination |
**Returns:** Array of `GlvInfo` elements, each containing a `Glv.Props` and a list of market addresses.
Getting GLV value[](https://docs.gmx.io/docs/api/contracts/glv-reader/#getting-glv-value "Direct link to Getting GLV value")
------------------------------------------------------------------------------------------------------------------------------
Use `getGlvValue` to retrieve the total GLV vault value before converting it into a token price.
### GlvReader.getGlvValue[](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvvalue "Direct link to GlvReader.getGlvValue")
function getGlvValue( DataStore dataStore, address[] memory marketAddresses, Price.Props[] memory indexTokenPrices, Price.Props memory longTokenPrice, Price.Props memory shortTokenPrice, address glv, bool maximize) external view returns (uint256)
**Example (TypeScript / ethers):**
const glvValue = await glvReader.getGlvValue( dataStore.address, marketAddresses, indexTokenPrices, longTokenPrice, shortTokenPrice, glvAddress, true);
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `marketAddresses` | `address[]` | Addresses of the markets inside the GLV |
| `indexTokenPrices` | `Price.Props[]` | Prices for the index tokens of each GLV market. The order must match `marketAddresses`. |
| `longTokenPrice` | `Price.Props` | Price of the long token |
| `shortTokenPrice` | `Price.Props` | Price of the short token |
| `glv` | `address` | Address of the GLV vault |
| `maximize` | `bool` | When `true`, uses maximum token prices. When `false`, uses minimum prices. |
**Returns:** Total GLV vault value in 30-decimal USD precision.
Getting GLV token price[](https://docs.gmx.io/docs/api/contracts/glv-reader/#getting-glv-token-price "Direct link to Getting GLV token price")
------------------------------------------------------------------------------------------------------------------------------------------------
Use `getGlvTokenPrice` to retrieve the GLV token price, total vault value, and total supply.
### GlvReader.getGlvTokenPrice[](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvtokenprice "Direct link to GlvReader.getGlvTokenPrice")
function getGlvTokenPrice( DataStore dataStore, address[] memory marketAddresses, Price.Props[] memory indexTokenPrices, Price.Props memory longTokenPrice, Price.Props memory shortTokenPrice, address glv, bool maximize) external view returns (uint256, uint256, uint256)
**Example (TypeScript / ethers):**
const [glvPrice, glvValue, totalSupply] = await glvReader.getGlvTokenPrice( dataStore.address, marketAddresses, indexTokenPrices, longTokenPrice, shortTokenPrice, glvAddress, true);
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `marketAddresses` | `address[]` | Addresses of the markets inside the GLV |
| `indexTokenPrices` | `Price.Props[]` | Prices for the index tokens of each GLV market. The order must match `marketAddresses`. |
| `longTokenPrice` | `Price.Props` | Price of the long token |
| `shortTokenPrice` | `Price.Props` | Price of the short token |
| `glv` | `address` | Address of the GLV vault |
| `maximize` | `bool` | When `true`, uses maximum token prices. When `false`, uses minimum prices. |
**Returns:** A tuple of `(uint256 price, uint256 glvValue, uint256 totalSupply)`.
Direct GLV lookups[](https://docs.gmx.io/docs/api/contracts/glv-reader/#direct-glv-lookups "Direct link to Direct GLV lookups")
---------------------------------------------------------------------------------------------------------------------------------
Use these methods when you already have a GLV address or deployment salt and want the raw stored object.
### GlvReader.getGlv[](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglv "Direct link to GlvReader.getGlv")
function getGlv(DataStore dataStore, address glv) external view returns (Glv.Props memory)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `glv` | `address` | GLV token address |
**Returns:** `Glv.Props` for the requested GLV.
### GlvReader.getGlvInfo[](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvinfo "Direct link to GlvReader.getGlvInfo")
function getGlvInfo(DataStore dataStore, address glv) public view returns (GlvInfo memory)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `glv` | `address` | GLV token address |
**Returns:** `GlvInfo`, containing the GLV props plus its supported market list.
### GlvReader.getGlvBySalt[](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvbysalt "Direct link to GlvReader.getGlvBySalt")
function getGlvBySalt(DataStore dataStore, bytes32 salt) external view returns (Glv.Props memory)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `salt` | `bytes32` | Deterministic GLV deployment salt |
**Returns:** `Glv.Props` for the requested GLV.
GLV deposit requests[](https://docs.gmx.io/docs/api/contracts/glv-reader/#glv-deposit-requests "Direct link to GLV deposit requests")
---------------------------------------------------------------------------------------------------------------------------------------
Use these methods to inspect GLV deposit requests by key, globally, or for one account.
### GlvReader.getGlvDeposit[](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvdeposit "Direct link to GlvReader.getGlvDeposit")
function getGlvDeposit(DataStore dataStore, bytes32 key) external view returns (GlvDeposit.Props memory)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `key` | `bytes32` | GLV deposit request key |
**Returns:** Raw `GlvDeposit.Props` for the request.
### GlvReader.getGlvDeposits[](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvdeposits "Direct link to GlvReader.getGlvDeposits")
function getGlvDeposits( DataStore dataStore, uint256 start, uint256 end) external view returns (GlvDeposit.Props[] memory)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `start` | `uint256` | Start index for pagination |
| `end` | `uint256` | End index for pagination |
**Returns:** Array of `GlvDeposit.Props` values.
### GlvReader.getAccountGlvDeposits[](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetaccountglvdeposits "Direct link to GlvReader.getAccountGlvDeposits")
function getAccountGlvDeposits( DataStore dataStore, address account, uint256 start, uint256 end) external view returns (GlvDeposit.Props[] memory)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `account` | `address` | Account to retrieve GLV deposits for |
| `start` | `uint256` | Start index for pagination |
| `end` | `uint256` | End index for pagination |
**Returns:** Array of `GlvDeposit.Props` values for the account.
GLV withdrawal requests[](https://docs.gmx.io/docs/api/contracts/glv-reader/#glv-withdrawal-requests "Direct link to GLV withdrawal requests")
------------------------------------------------------------------------------------------------------------------------------------------------
Use these methods to inspect GLV withdrawal requests by key, globally, or for one account.
### GlvReader.getGlvWithdrawal[](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvwithdrawal "Direct link to GlvReader.getGlvWithdrawal")
function getGlvWithdrawal(DataStore dataStore, bytes32 key) external view returns (GlvWithdrawal.Props memory)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `key` | `bytes32` | GLV withdrawal request key |
**Returns:** Raw `GlvWithdrawal.Props` for the request.
### GlvReader.getGlvWithdrawals[](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvwithdrawals "Direct link to GlvReader.getGlvWithdrawals")
function getGlvWithdrawals( DataStore dataStore, uint256 start, uint256 end) external view returns (GlvWithdrawal.Props[] memory)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `start` | `uint256` | Start index for pagination |
| `end` | `uint256` | End index for pagination |
**Returns:** Array of `GlvWithdrawal.Props` values.
### GlvReader.getAccountGlvWithdrawals[](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetaccountglvwithdrawals "Direct link to GlvReader.getAccountGlvWithdrawals")
function getAccountGlvWithdrawals( DataStore dataStore, address account, uint256 start, uint256 end) external view returns (GlvWithdrawal.Props[] memory)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `account` | `address` | Account to retrieve GLV withdrawals for |
| `start` | `uint256` | Start index for pagination |
| `end` | `uint256` | End index for pagination |
**Returns:** Array of `GlvWithdrawal.Props` values for the account.
GLV shift requests[](https://docs.gmx.io/docs/api/contracts/glv-reader/#glv-shift-requests "Direct link to GLV shift requests")
---------------------------------------------------------------------------------------------------------------------------------
Use these methods to inspect GLV shift requests by key or through paginated lists.
### GlvReader.getGlvShift[](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvshift "Direct link to GlvReader.getGlvShift")
function getGlvShift(DataStore dataStore, bytes32 key) external view returns (GlvShift.Props memory)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `key` | `bytes32` | GLV shift request key |
**Returns:** Raw `GlvShift.Props` for the request.
### GlvReader.getGlvShifts[](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvshifts "Direct link to GlvReader.getGlvShifts")
function getGlvShifts( DataStore dataStore, uint256 start, uint256 end) external view returns (GlvShift.Props[] memory)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `start` | `uint256` | Start index for pagination |
| `end` | `uint256` | End index for pagination |
**Returns:** Array of `GlvShift.Props` values.
* [Getting a list of GLVs](https://docs.gmx.io/docs/api/contracts/glv-reader/#getting-a-list-of-glvs)
* [GlvReader.getGlvs](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvs)
* [Glv.Props](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvprops)
* [Getting GLV info with market list](https://docs.gmx.io/docs/api/contracts/glv-reader/#getting-glv-info-with-market-list)
* [GlvReader.getGlvInfoList](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvinfolist)
* [Getting GLV value](https://docs.gmx.io/docs/api/contracts/glv-reader/#getting-glv-value)
* [GlvReader.getGlvValue](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvvalue)
* [Getting GLV token price](https://docs.gmx.io/docs/api/contracts/glv-reader/#getting-glv-token-price)
* [GlvReader.getGlvTokenPrice](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvtokenprice)
* [Direct GLV lookups](https://docs.gmx.io/docs/api/contracts/glv-reader/#direct-glv-lookups)
* [GlvReader.getGlv](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglv)
* [GlvReader.getGlvInfo](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvinfo)
* [GlvReader.getGlvBySalt](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvbysalt)
* [GLV deposit requests](https://docs.gmx.io/docs/api/contracts/glv-reader/#glv-deposit-requests)
* [GlvReader.getGlvDeposit](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvdeposit)
* [GlvReader.getGlvDeposits](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvdeposits)
* [GlvReader.getAccountGlvDeposits](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetaccountglvdeposits)
* [GLV withdrawal requests](https://docs.gmx.io/docs/api/contracts/glv-reader/#glv-withdrawal-requests)
* [GlvReader.getGlvWithdrawal](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvwithdrawal)
* [GlvReader.getGlvWithdrawals](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvwithdrawals)
* [GlvReader.getAccountGlvWithdrawals](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetaccountglvwithdrawals)
* [GLV shift requests](https://docs.gmx.io/docs/api/contracts/glv-reader/#glv-shift-requests)
* [GlvReader.getGlvShift](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvshift)
* [GlvReader.getGlvShifts](https://docs.gmx.io/docs/api/contracts/glv-reader/#glvreadergetglvshifts)
---
# Delegated trading integration | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/contracts/delegated-trading/#__docusaurus_skipToContent_fallback)
On this page
This page explains how to build delegated trading flows on GMX V2 using the subaccount and relay surfaces documented in [Advanced entry points](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/)
. It is intended for integrators who need an end-to-end implementation pattern, not just a function reference.
Use this guide when your application needs a model like:
* an account owner retains primary control of funds
* a delegated trader can place, update, and cancel orders
* delegated access expires automatically or is limited by action count
* your backend, relayer, or UI coordinates the signing flow
If you only need the raw contract surfaces, start with [Advanced entry points](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/)
. If you need read-path architecture and freshness guidance, also see the [API integration guide](https://docs.gmx.io/docs/api/integration-guide/)
and [Reader](https://docs.gmx.io/docs/api/contracts/reader/)
.
What GMX exposes[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#what-gmx-exposes "Direct link to What GMX exposes")
----------------------------------------------------------------------------------------------------------------------------------
The delegated trading surface is built around:
* `SubaccountGelatoRelayRouter` for same-chain delegated order management (gasless, relay-based)
* `MultichainSubaccountRouter` for cross-chain delegated order management
* `DataStore` and `Keys` for delegated-access state such as expiry, action count, and integration id
A legacy `SubaccountRouter` contract is still deployed but is no longer used for order operations. The current GMX interface only calls it for wallet-based `removeSubaccount(...)` when the user is not going through the express flow. For new integrations, use `SubaccountGelatoRelayRouter` for same-chain delegated order execution and `MultichainSubaccountRouter` for cross-chain delegated order execution.
At the contract level, the main account can authorize or remove a subaccount, set an expiry timestamp for delegated actions, cap how many delegated actions may be performed, and bind a subaccount to an integration id. The delegated subaccount can then create, update, and cancel orders through the delegated trading surface.
Permission model[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#permission-model "Direct link to Permission model")
----------------------------------------------------------------------------------------------------------------------------------
The GMX subaccount model is scoped to delegated trading, not broad account delegation. Delegated access is designed for order management — it is narrower than giving a third party full account ownership, and it does not turn the delegated signer into a general-purpose owner of the account.
### Boundaries[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#boundaries "Direct link to Boundaries")
| Area | Behavior |
| --- | --- |
| Order outputs | Constrained to the main account |
| Collateral and WNT | The delegated flow can spend the main account's collateral and WNT within the supported order flow |
| Deposits, withdrawals, shifts, claims | Not delegated — these use their own routers and flows |
For a summary of integration caveats, also review [Known issues](https://docs.gmx.io/docs/api/contracts/known-issues/)
.
Roles in a delegated trading flow[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#roles-in-a-delegated-trading-flow "Direct link to Roles in a delegated trading flow")
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Most integrations end up with three roles:
### 1\. Main account owner[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#1-main-account-owner "Direct link to 1. Main account owner")
The owner wallet is the trust anchor for the trading account. It decides which delegated signer is allowed to trade, sets expiry and action-count limits, revokes delegated access, and optionally binds the subaccount to an `integrationId`.
### 2\. Delegated trader or subaccount signer[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#2-delegated-trader-or-subaccount-signer "Direct link to 2. Delegated trader or subaccount signer")
This signer executes delegated trading actions within the limits the owner authorized. Depending on your design, it may be a key generated and stored locally in the user's browser for one-click trading, a key generated and managed by your backend or trading service, or a wallet controlled directly by a trader operating under your system's authorization flow.
### 3\. Backend or relayer[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#3-backend-or-relayer "Direct link to 3. Backend or relayer")
Your backend may orchestrate owner-authorization flows, store or broker delegated session metadata, relay gasless order flow through `SubaccountGelatoRelayRouter`, and monitor expiry, action count, order lifecycle, and risk state.
Common integration patterns[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#common-integration-patterns "Direct link to Common integration patterns")
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
GMX supports multiple delegated trading patterns. The right one depends on your custody and trust model.
### Browser-local one-click signer[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#browser-local-one-click-signer "Direct link to Browser-local one-click signer")
This is the closest match to the GMX interface's one-click trading flow described in [Trading overview](https://docs.gmx.io/docs/trading/overview/#express-trading-and-one-click-trading)
. The delegated signer is created client-side, the key stays in the browser or local device storage, the owner authorizes delegated access with expiry and action limits, and the UI uses the delegated signer for order flow. This is the lowest-backend-custody model, but it shifts key-security risk to the browser environment.
### Backend-managed delegated signer[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#backend-managed-delegated-signer "Direct link to Backend-managed delegated signer")
This pattern is useful when your product already operates managed trading infrastructure. Your backend provisions and manages the delegated signer, the owner authorizes that signer as a subaccount, and your backend handles session lifecycle, revocation, and monitoring. This gives you more operational control, but the delegated signer becomes part of your key-management perimeter — treat it as a hot operational key with strict lifecycle controls.
### Relay-first owner approval flow[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#relay-first-owner-approval-flow "Direct link to Relay-first owner approval flow")
This pattern is useful when you want owner-controlled authorization, delegated trading without repeated wallet popups, and gasless or sponsored execution. The owner signs the subaccount approval payload, the delegated signer signs the trade payload, and your relayer or backend submits through `SubaccountGelatoRelayRouter`. This is the most natural path when you want tight control over expiry, nonce handling, and replay protection while still delivering a low-friction user experience.
Recommended end-to-end flow[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#recommended-end-to-end-flow "Direct link to Recommended end-to-end flow")
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
The most common delegated trading sequence looks like this:
### Step 1 — Choose the delegated signer model[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#step-1--choose-the-delegated-signer-model "Direct link to Step 1 — Choose the delegated signer model")
Decide whether the delegated signer will be browser-local, backend-managed, or externally controlled by the delegated trader.
### Step 2 — Create or identify the delegated signer[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#step-2--create-or-identify-the-delegated-signer "Direct link to Step 2 — Create or identify the delegated signer")
This signer becomes the subaccount address that the main account owner authorizes.
### Step 3 — Owner authorizes delegated trading[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#step-3--owner-authorizes-delegated-trading "Direct link to Step 3 — Owner authorizes delegated trading")
The owner enables delegated trading by setting the subaccount address, the delegated action type, expiry, maximum allowed action count, and an optional integration id.
### Step 4 — Store delegated session metadata[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#step-4--store-delegated-session-metadata "Direct link to Step 4 — Store delegated session metadata")
Your application should track:
| State | Notes |
| --- | --- |
| Subaccount address | The delegated signer's address |
| Authorization status | Whether the subaccount is currently active |
| Expiry | When delegated access expires |
| Remaining action budget | How many actions remain before re-authorization |
| Nonce state | Required if you are using relay-based approvals |
| Integration id | If you use one |
### Step 5 — Execute delegated orders[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#step-5--execute-delegated-orders "Direct link to Step 5 — Execute delegated orders")
Use `SubaccountGelatoRelayRouter` for same-chain delegated order execution or `MultichainSubaccountRouter` for cross-chain delegated order execution.
### Step 6 — Monitor and refresh[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#step-6--monitor-and-refresh "Direct link to Step 6 — Monitor and refresh")
Your system should detect expiry approaching, action count approaching the cap, nonce invalidation, and revoked delegated access.
### Step 7 — Re-authorize or revoke[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#step-7--re-authorize-or-revoke "Direct link to Step 7 — Re-authorize or revoke")
When the delegated session is no longer valid, the owner can refresh authorization with a new expiry or action budget, or remove the subaccount entirely.
Router selection[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#router-selection "Direct link to Router selection")
----------------------------------------------------------------------------------------------------------------------------------
Use `SubaccountGelatoRelayRouter` for same-chain delegated trading. This is the primary delegated order path used by the current GMX interface — it supports gasless delegated order creation, updates, cancellation, and subaccount removal, with owner-signed approval payloads and delegated trade payloads in one relay flow. Use `MultichainSubaccountRouter` for cross-chain delegated trading flows.
A legacy `SubaccountRouter` contract remains deployed on all networks but is no longer used for order operations. The GMX interface only calls it for wallet-based subaccount removal outside the express flow.
SDK, API, and contract responsibilities[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#sdk-api-and-contract-responsibilities "Direct link to SDK, API, and contract responsibilities")
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
GMX does not currently package delegated trading as a single turnkey integration surface. In practice, delegated trading integrations compose three layers:
| Layer | Role | Notes |
| --- | --- | --- |
| Contracts | Source of truth for delegated authorization, order execution, and expiry/action-count/integration-id enforcement | Always the canonical state |
| SDK | Typed read helpers, order-building convenience, and wallet-client integration | Useful in delegated flows, but you own the overall authorization and session architecture |
| API | Near-live positions and orders over HTTP, lighter-weight read integration, and separation between read polling and write submission | See [API integration guide](https://docs.gmx.io/docs/api/integration-guide/)
for freshness and consistency expectations |
Monitoring architecture[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#monitoring-architecture "Direct link to Monitoring architecture")
-------------------------------------------------------------------------------------------------------------------------------------------------------
If delegated trading is part of a risk-managed product, design the monitoring layer intentionally rather than treating every read surface as interchangeable.
| Surface | Best for | Latency | Examples |
| --- | --- | --- | --- |
| `Reader`, `DataStore`, `Multicall3` | Tight on-chain state loops | Lowest — same-block | Subaccount expiry, action-count consumption, delegated access status, position state for risk controls |
| API and SDK reads | Application state and account views | Near-live | Dashboards, trader-facing views, normal order monitoring, eventual-consistency workflows after writes |
| GraphQL and indexed surfaces | History and analytics | Higher | Investigations, reporting, trade history |
tip
Treat API and SDK reads as near-live, not as a strict same-block risk engine. Do not rely only on indexed or historical surfaces for latency-sensitive delegated trading controls.
See [Overview](https://docs.gmx.io/docs/api/contracts/overview/)
for the read contracts and [Reader](https://docs.gmx.io/docs/api/contracts/reader/)
for position and order helpers.
Security guidance[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#security-guidance "Direct link to Security guidance")
-------------------------------------------------------------------------------------------------------------------------------------
Delegated trading is a security-sensitive integration. Keep these constraints in mind:
### Limit scope aggressively[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#limit-scope-aggressively "Direct link to Limit scope aggressively")
Always use the protocol's built-in controls — expiry, maximum allowed action count, and optional integration id. Do not treat delegated access as open-ended if your use case does not require it.
### Be explicit about key custody[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#be-explicit-about-key-custody "Direct link to Be explicit about key custody")
If you use a browser-local signer, the browser becomes part of the trust boundary — compromised local storage or injected scripts can compromise the delegated signer. If you use a backend-managed signer, your backend becomes part of the custody boundary, and you should treat the delegated signer as a hot key with planned revocation, rotation, and auditability.
### Avoid unnecessary private-key transport[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#avoid-unnecessary-private-key-transport "Direct link to Avoid unnecessary private-key transport")
If your integration can avoid transporting raw delegated private keys between backend and browser, that is generally the safer design. Prefer architectures where the delegated signer is generated client-side, or the backend signs on behalf of the delegated session without exposing raw key material to the browser.
### Separate read architecture from write architecture[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#separate-read-architecture-from-write-architecture "Direct link to Separate read architecture from write architecture")
Do not tie delegated trade submission and risk monitoring to the same fragile polling path. In production integrations, treat authorization and write flow, state polling, and risk enforcement as separate responsibilities, even if they are implemented by the same service.
What GMX provides vs what your integration must provide[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#what-gmx-provides-vs-what-your-integration-must-provide "Direct link to What GMX provides vs what your integration must provide")
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| GMX provides | Your integration provides |
| --- | --- |
| Delegated trading primitives | Signer custody design |
| Gasless relay primitives | User authorization UX |
| Owner-controlled expiry and action limits | Session lifecycle management |
| Read contracts and APIs for account state | Monitoring and risk architecture |
| Protocol-level enforcement, not custody | Key-security controls appropriate for your trust model |
Next steps[](https://docs.gmx.io/docs/api/contracts/delegated-trading/#next-steps "Direct link to Next steps")
----------------------------------------------------------------------------------------------------------------
* [Advanced entry points](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/)
for the raw delegated trading surfaces
* [Reader](https://docs.gmx.io/docs/api/contracts/reader/)
for position and order reads
* [Overview](https://docs.gmx.io/docs/api/contracts/overview/)
for read contracts and multicall guidance
* [Trading overview](https://docs.gmx.io/docs/trading/overview/#express-trading-and-one-click-trading)
for the user-facing one-click trading model
* [SDK v1 integration guide](https://docs.gmx.io/docs/sdk/v1/integration-guide/)
for SDK operational notes
* [API integration guide](https://docs.gmx.io/docs/api/integration-guide/)
for freshness, consistency, and read-surface guidance
* [What GMX exposes](https://docs.gmx.io/docs/api/contracts/delegated-trading/#what-gmx-exposes)
* [Permission model](https://docs.gmx.io/docs/api/contracts/delegated-trading/#permission-model)
* [Boundaries](https://docs.gmx.io/docs/api/contracts/delegated-trading/#boundaries)
* [Roles in a delegated trading flow](https://docs.gmx.io/docs/api/contracts/delegated-trading/#roles-in-a-delegated-trading-flow)
* [1\. Main account owner](https://docs.gmx.io/docs/api/contracts/delegated-trading/#1-main-account-owner)
* [2\. Delegated trader or subaccount signer](https://docs.gmx.io/docs/api/contracts/delegated-trading/#2-delegated-trader-or-subaccount-signer)
* [3\. Backend or relayer](https://docs.gmx.io/docs/api/contracts/delegated-trading/#3-backend-or-relayer)
* [Common integration patterns](https://docs.gmx.io/docs/api/contracts/delegated-trading/#common-integration-patterns)
* [Browser-local one-click signer](https://docs.gmx.io/docs/api/contracts/delegated-trading/#browser-local-one-click-signer)
* [Backend-managed delegated signer](https://docs.gmx.io/docs/api/contracts/delegated-trading/#backend-managed-delegated-signer)
* [Relay-first owner approval flow](https://docs.gmx.io/docs/api/contracts/delegated-trading/#relay-first-owner-approval-flow)
* [Recommended end-to-end flow](https://docs.gmx.io/docs/api/contracts/delegated-trading/#recommended-end-to-end-flow)
* [Step 1 — Choose the delegated signer model](https://docs.gmx.io/docs/api/contracts/delegated-trading/#step-1--choose-the-delegated-signer-model)
* [Step 2 — Create or identify the delegated signer](https://docs.gmx.io/docs/api/contracts/delegated-trading/#step-2--create-or-identify-the-delegated-signer)
* [Step 3 — Owner authorizes delegated trading](https://docs.gmx.io/docs/api/contracts/delegated-trading/#step-3--owner-authorizes-delegated-trading)
* [Step 4 — Store delegated session metadata](https://docs.gmx.io/docs/api/contracts/delegated-trading/#step-4--store-delegated-session-metadata)
* [Step 5 — Execute delegated orders](https://docs.gmx.io/docs/api/contracts/delegated-trading/#step-5--execute-delegated-orders)
* [Step 6 — Monitor and refresh](https://docs.gmx.io/docs/api/contracts/delegated-trading/#step-6--monitor-and-refresh)
* [Step 7 — Re-authorize or revoke](https://docs.gmx.io/docs/api/contracts/delegated-trading/#step-7--re-authorize-or-revoke)
* [Router selection](https://docs.gmx.io/docs/api/contracts/delegated-trading/#router-selection)
* [SDK, API, and contract responsibilities](https://docs.gmx.io/docs/api/contracts/delegated-trading/#sdk-api-and-contract-responsibilities)
* [Monitoring architecture](https://docs.gmx.io/docs/api/contracts/delegated-trading/#monitoring-architecture)
* [Security guidance](https://docs.gmx.io/docs/api/contracts/delegated-trading/#security-guidance)
* [Limit scope aggressively](https://docs.gmx.io/docs/api/contracts/delegated-trading/#limit-scope-aggressively)
* [Be explicit about key custody](https://docs.gmx.io/docs/api/contracts/delegated-trading/#be-explicit-about-key-custody)
* [Avoid unnecessary private-key transport](https://docs.gmx.io/docs/api/contracts/delegated-trading/#avoid-unnecessary-private-key-transport)
* [Separate read architecture from write architecture](https://docs.gmx.io/docs/api/contracts/delegated-trading/#separate-read-architecture-from-write-architecture)
* [What GMX provides vs what your integration must provide](https://docs.gmx.io/docs/api/contracts/delegated-trading/#what-gmx-provides-vs-what-your-integration-must-provide)
* [Next steps](https://docs.gmx.io/docs/api/contracts/delegated-trading/#next-steps)
---
# Contract addresses | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/contracts/addresses/#__docusaurus_skipToContent_fallback)
On this page
This page lists the key contract addresses for each supported chain. For the complete list of all deployed contracts (100+ per chain), see the [gmx-synthetics deployments folder](https://github.com/gmx-io/gmx-synthetics/tree/updates/docs)
. The machine-readable `contracts.json` in that folder covers mainnet deployments, while testnet deployments are published in the per-network markdown files.
warning
Contract addresses change when logic contracts are upgraded. Subscribe to the [Updates and support](https://docs.gmx.io/docs/api/updates-support/)
channels for upgrade notifications.
`DataStore` and `RoleStore` addresses are permanent and don't change across upgrades.
Mainnet[](https://docs.gmx.io/docs/api/contracts/addresses/#mainnet "Direct link to Mainnet")
-----------------------------------------------------------------------------------------------
The tables below list the key integrator-facing contracts for each mainnet chain. For the full list of all deployed contracts on each chain, see the deployment files linked from each section.
### Arbitrum (Chain ID: 42161)[](https://docs.gmx.io/docs/api/contracts/addresses/#arbitrum-chain-id-42161 "Direct link to Arbitrum (Chain ID: 42161)")
Explorer: [arbiscan.io](https://arbiscan.io/)
| [Full deployment list](https://github.com/gmx-io/gmx-synthetics/blob/updates/docs/arbitrum-deployments.md)
| Contract | Address |
| --- | --- |
| DataStore | `0xFD70de6b91282D8017aA4E741e9Ae325CAb992d8` |
| RoleStore | `0x3c3d99FD298f679DBC2CEcd132b4eC4d0F5e6e72` |
| Reader | `0x470fbC46bcC0f16532691Df360A07d8Bf5ee0789` |
| ExchangeRouter | `0x1C3fa76e6E1088bCE750f23a5BFcffa1efEF6A41` |
| Router | `0x7452c558d45f8afC8c83dAe62C3f8A5BE19c71f6` |
| Oracle | `0x7F01614cA5198Ec979B1aAd1DAF0DE7e0a215BDF` |
| OrderVault | `0x31eF83a530Fde1B38EE9A18093A333D8Bbbc40D5` |
| DepositVault | `0xF89e77e8Dc11691C9e8757e84aaFbCD8A67d7A55` |
| WithdrawalVault | `0x0628D46b5D145f183AdB6Ef1f2c97eD1C4701C55` |
| ShiftVault | `0xfe99609C4AA83ff6816b64563Bdffd7fa68753Ab` |
| OrderHandler | `0x63492B775e30a9E6b4b4761c12605EB9d071d5e9` |
| DepositHandler | `0x33871b8568eDC4adf33338cdD8cF52a0eCC84D42` |
| WithdrawalHandler | `0x11e9E7464f3Bc887a7290ec41fCd22f619b177fd` |
| AdlHandler | `0x262df96a3a35D0A7950C5669238662df58Ae8bf7` |
| LiquidationHandler | `0xaf157Eb8e2398A8E1Fc1dA929974652b9ba9BC25` |
| ShiftHandler | `0x5F66cBb8D1766e6CE3c1ffba0987aeDe7a1DFf53` |
| GlvHandler | `0x3f6dF0c3A7221BA1375E87e7097885a601B41Afc` |
| GlvVault | `0x393053B58f9678C9c28c2cE941fF6cac49C3F8f9` |
| EventEmitter | `0xC8ee91A54287DB53897056e12D9819156D3822Fb` |
| MarketFactory | `0xf5F30B10141E1F63FC11eD772931A8294a591996` |
| GlvRouter | `0x7EAdEE2ca1b4D06a0d82fDF03D715550c26AA12F` |
| GlvReader | `0x2C670A23f1E798184647288072e84054938B5497` |
| SubaccountRouter | `0xdD00F639725E19a209880A44962Bc93b51B1B161` |
| Multicall3 | `0xe79118d6D92a4b23369ba356C90b9A7ABf1CB961` |
| Config | `0x33D1a645B9E9fc19b06Fe02981180c8DDAeE75B1` |
| ConfigTimelockController | `0xC77E6C0ca99E02660A23c00A860Dd5a8912DEaF5` |
| GovTimelockController | `0xFBEff82f2DD5E51B8AF34b57cf788b4b09d466F9` |
| Timelock | `0x7A967D114B8676874FA2cFC1C14F3095C88418Eb` |
| TimelockConfig | `0x4A1D9e342E2dB5f4a02c9eF5cB29CaF289f31599` |
#### Multichain contracts (Arbitrum)[](https://docs.gmx.io/docs/api/contracts/addresses/#multichain-contracts-arbitrum "Direct link to Multichain contracts (Arbitrum)")
| Contract | Address |
| --- | --- |
| MultichainOrderRouter | `0xD38111f8aF1A7Cd809457C8A2303e15aE2170724` |
| MultichainGmRouter | `0xC6782854A8639cC3b40f9497797d6B33797CA592` |
| MultichainGlvRouter | `0xabcBbe23BD8E0dDD344Ff5fd1439b785B828cD2d` |
| MultichainClaimsRouter | `0x277B4c0e8A76Fa927C9881967a4475Fd6E234e95` |
| MultichainTransferRouter | `0xfaBEb65bB877600be3A2C2a03aA56a95F9f845B9` |
| MultichainSubaccountRouter | `0x70AaAd50d53732b2D5534bb57332D00aE20cAd36` |
| MultichainReader | `0xC17AEf8559006e73B325C742143Eb2Aa1d6f79B2` |
| MultichainVault | `0xCeaadFAf6A8C489B250e407987877c5fDfcDBE6E` |
#### Relay and oracle provider contracts (Arbitrum)[](https://docs.gmx.io/docs/api/contracts/addresses/#relay-and-oracle-provider-contracts-arbitrum "Direct link to Relay and oracle provider contracts (Arbitrum)")
| Contract | Address |
| --- | --- |
| GelatoRelayRouter | `0xa9090E2fd6cD8Ee397cF3106189A7E1CFAE6C59C` |
| SubaccountGelatoRelayRouter | `0x517602BaC704B72993997820981603f5E4901273` |
| ChainlinkDataStreamProvider | `0xE1d5a068c5b75E0c7Ea1A9Fe8EA056f9356C6fFD` |
| ChainlinkPriceFeedProvider | `0x38B8dB61b724b51e42A88Cb8eC564CD685a0f53B` |
| EdgeDataStreamProvider | `0x24A01E28077C2b831166Dd4099DFfD4056a336a1` |
| LayerZeroProvider | `0xB6DE222dAef5029f31b8fABE498D34f3c491Ef85` |
### Avalanche (Chain ID: 43114)[](https://docs.gmx.io/docs/api/contracts/addresses/#avalanche-chain-id-43114 "Direct link to Avalanche (Chain ID: 43114)")
Explorer: [snowtrace.io](https://snowtrace.io/)
| [Full deployment list](https://github.com/gmx-io/gmx-synthetics/blob/updates/docs/avalanche-deployments.md)
| Contract | Address |
| --- | --- |
| DataStore | `0x2F0b22339414ADeD7D5F06f9D604c7fF5b2fe3f6` |
| RoleStore | `0xA44F830B6a2B6fa76657a3B92C1fe74fcB7C6AfD` |
| Reader | `0x62Cb8740E6986B29dC671B2EB596676f60590A5B` |
| ExchangeRouter | `0x8f550E53DFe96C055D5Bdb267c21F268fCAF63B2` |
| Router | `0x820F5FfC5b525cD4d88Cd91aCf2c28F16530Cc68` |
| Oracle | `0xE1d5a068c5b75E0c7Ea1A9Fe8EA056f9356C6fFD` |
| OrderVault | `0xD3D60D22d415aD43b7e64b510D86A30f19B1B12C` |
| DepositVault | `0x90c670825d0C62ede1c5ee9571d6d9a17A722DFF` |
| WithdrawalVault | `0xf5F30B10141E1F63FC11eD772931A8294a591996` |
| ShiftVault | `0x7fC46CCb386e9bbBFB49A2639002734C3Ec52b39` |
| OrderHandler | `0x823b558B4bC0a2C4974a0d8D7885AA1102D15dEC` |
| DepositHandler | `0xCC2645E961514A694bca228686ec664933c70647` |
| WithdrawalHandler | `0x334237f7d75497a22B1443f44DDCcF95e72904A0` |
| AdlHandler | `0x858559D39fe8B2fDfE452f895db36077859130e1` |
| LiquidationHandler | `0xad7F00b4080BACFfAaE7f44d67560C818d8e5468` |
| ShiftHandler | `0x6AdF7026D53057CED269DFDa318103db4F0Aa4Ba` |
| GlvHandler | `0x48486CaF8851ed0085432789D28A8820bEcbfd45` |
| GlvVault | `0x527FB0bCfF63C47761039bB386cFE181A92a4701` |
| EventEmitter | `0xDb17B211c34240B014ab6d61d4A31FA0C0e20c26` |
| MarketFactory | `0xc57C155FacCd93F62546F329D1483E0E5b9C1241` |
| GlvRouter | `0x7E425c47b2Ff0bE67228c842B9C792D0BCe58ae6` |
| GlvReader | `0x5C6905A3002f989E1625910ba1793d40a031f947` |
| SubaccountRouter | `0xf43F559774d2cF7882e6E846fCb87BDe183a6Da7` |
| Multicall3 | `0x50474CAe810B316c294111807F94F9f48527e7F8` |
| Config | `0x11e9E7464f3Bc887a7290ec41fCd22f619b177fd` |
| ConfigTimelockController | `0x20D56cf90fD3C8f3bEb9BAC03AfdA3241093DE36` |
| GovTimelockController | `0xA2aAaa1CbBd4B4f1Fd548f0a3f58B924EE36f266` |
| Timelock | `0xdF23692341538340db0ff04C65017F51b69a29f6` |
| TimelockConfig | `0x37e1AeB6118B0106810D2eF7662875C414e39Ca4` |
#### Multichain contracts (Avalanche)[](https://docs.gmx.io/docs/api/contracts/addresses/#multichain-contracts-avalanche "Direct link to Multichain contracts (Avalanche)")
| Contract | Address |
| --- | --- |
| MultichainOrderRouter | `0xd099565957046a2d2CF41B0CC9F95e14a8afD13b` |
| MultichainGmRouter | `0xA191Bc0B72332e4c2022dB50a9d619079cc6c4fD` |
| MultichainGlvRouter | `0xEEE61742bC4cf361c60Cd65826864560Bf2D0bB6` |
| MultichainClaimsRouter | `0xd10B10b816030347ff4E6767d340371B40b9F03D` |
| MultichainTransferRouter | `0x5A44a3b026d50EC039582fDb3aFDD88e2092E211` |
| MultichainSubaccountRouter | `0x5872E84e5ea23292b40183BE86D25fb428621fC1` |
| MultichainReader | `0xf7B962B085775A96A99E3dD38dfFf09D7e270088` |
| MultichainVault | `0x6D5F3c723002847B009D07Fe8e17d6958F153E4e` |
#### Relay and oracle provider contracts (Avalanche)[](https://docs.gmx.io/docs/api/contracts/addresses/#relay-and-oracle-provider-contracts-avalanche "Direct link to Relay and oracle provider contracts (Avalanche)")
| Contract | Address |
| --- | --- |
| GelatoRelayRouter | `0xEE2d3339CbcE7A42573C96ACc1298A79a5C996Df` |
| SubaccountGelatoRelayRouter | `0xfaBEb65bB877600be3A2C2a03aA56a95F9f845B9` |
| ChainlinkDataStreamProvider | `0xC181eB022F33b8ba808AD96348B03e8A753A859b` |
| ChainlinkPriceFeedProvider | `0x05d97cee050bfb81FB3EaD4A9368584F8e72C88e` |
| EdgeDataStreamProvider | `0x176fD214bc59005fFd722AE3F8fA12a31391F6Ae` |
| LayerZeroProvider | `0xF85Fd576bBe22Bce785B68922C1c9849d62737c0` |
### Botanix (Chain ID: 3637)[](https://docs.gmx.io/docs/api/contracts/addresses/#botanix-chain-id-3637 "Direct link to Botanix (Chain ID: 3637)")
Explorer: [botanixscan.io](https://botanixscan.io/)
| [Full deployment list](https://github.com/gmx-io/gmx-synthetics/blob/updates/docs/botanix-deployments.md)
| Contract | Address |
| --- | --- |
| DataStore | `0xA23B81a89Ab9D7D89fF8fc1b5d8508fB75Cc094d` |
| RoleStore | `0x51Aa17ca59E9e9C3cEc3c3c05c2B35f473b35D39` |
| Reader | `0x922766ca6234cD49A483b5ee8D86cA3590D0Fb0E` |
| ExchangeRouter | `0xBCB5eA3a84886Ce45FBBf09eBF0e883071cB2Dc8` |
| Router | `0x3d472afcd66F954Fe4909EEcDd5c940e9a99290c` |
| Oracle | `0x40d680E41FC4Bf973F0EA664981f6359195a6383` |
| OrderVault | `0xe52B3700D17B45dE9de7205DEe4685B4B9EC612D` |
| DepositVault | `0x4D12C3D3e750e051e87a2F3f7750fBd94767742c` |
| WithdrawalVault | `0x46BAeAEdbF90Ce46310173A04942e2B3B781Bf0e` |
| ShiftVault | `0xa7EE2737249e0099906cB079BCEe85f0bbd837d4` |
| OrderHandler | `0xBAD04dDcc5CC284A86493aFA75D2BEb970C72216` |
| DepositHandler | `0x839B6e19E54A5862da61974A01675a5f6CC5c8b4` |
| WithdrawalHandler | `0x5bB6DCb09010069228B2aA766FAE513EF7923472` |
| AdlHandler | `0xec0e4A27a9fbfc64e4915c254B961260df28054c` |
| LiquidationHandler | `0x1bC32eeCAa8F504D2225096649A0347153A37f10` |
| ShiftHandler | `0xAD712E1667bC8AAa6C4EA5f47dcD487ddd96BC35` |
| GlvHandler | `0xB75AdE19252A9db51ea861E9A39C80BB0D7aAd82` |
| GlvVault | `0xd336087512BeF8Df32AF605b492f452Fd6436CD8` |
| EventEmitter | `0xAf2E131d483cedE068e21a9228aD91E623a989C2` |
| MarketFactory | `0xcb7656751B0f8aFCBe15D135D7aC58727DE06768` |
| GlvRouter | `0xC92741F0a0D20A95529873cBB3480b1f8c228d9F` |
| GlvReader | `0x955Aa50d2ecCeffa59084BE5e875eb676FfAFa98` |
| SubaccountRouter | `0xa1793126B6Dc2f7F254a6c0E2F8013D2180C0D10` |
| Multicall3 | `0x4BaA24f93a657f0c1b4A0Ffc72B91011E35cA46b` |
| Config | `0x5a1344252f0CdfDB765DD5ab97C98734f1D7ED6d` |
| ConfigTimelockController | `0x3d6BA4a91Ffde7C519379F8dCA5FE58b7125c294` |
| GovTimelockController | `0x610701662CD64De835d53B2dE508d342781CC1Bd` |
| Timelock | `0xca3e30b51A7c3bd40bFc52a61AB0cE57B3Ab3ad8` |
| TimelockConfig | `0x72a30e76827Ce83cEf0b1BEd7e9aAF9F4a576990` |
#### Multichain contracts (Botanix)[](https://docs.gmx.io/docs/api/contracts/addresses/#multichain-contracts-botanix "Direct link to Multichain contracts (Botanix)")
| Contract | Address |
| --- | --- |
| MultichainOrderRouter | `0xbC074fF8b85f9b66884E1EdDcE3410fde96bd798` |
| MultichainGmRouter | `0x6a960F397eB8F2300F9FfA746F11375A613C5027` |
| MultichainGlvRouter | `0x9C11DFa4DAFA9227Ef172cc1d87D4D5008804C47` |
| MultichainClaimsRouter | `0x421eB756B8f887f036e7332801288BC2bbA600aC` |
| MultichainTransferRouter | `0x844D38f2c3875b8351feB4764718E1c64bD55c46` |
| MultichainSubaccountRouter | `0x8138Ce254Bc0AfE40369FDC2D1e46cE90944406d` |
| MultichainReader | `0x9511FAb77C8d7Acf56c9D8AE9278Cd3bd8Bd9D5c` |
| MultichainVault | `0x9a535f9343434D96c4a39fF1d90cC685A4F6Fb20` |
#### Relay and oracle provider contracts (Botanix)[](https://docs.gmx.io/docs/api/contracts/addresses/#relay-and-oracle-provider-contracts-botanix "Direct link to Relay and oracle provider contracts (Botanix)")
| Contract | Address |
| --- | --- |
| GelatoRelayRouter | `0x98e86155abf8bCbA566b4a909be8cF4e3F227FAf` |
| SubaccountGelatoRelayRouter | `0xd6b16f5ceE328310B1cf6d8C0401C23dCd3c40d4` |
| ChainlinkDataStreamProvider | `0x1A4D623301b9f58405d3Fff7a63624411d5eb940` |
| ChainlinkPriceFeedProvider | `0xDc613305e9267f0770072dEaB8c03162e0554b2d` |
| EdgeDataStreamProvider | `0x02E209c2c47956e4E2934A7516d81e86d88A5Dbc` |
| LayerZeroProvider | `0x9E721ef9b908B4814Aa18502692E4c5666d1942e` |
### MegaETH (Chain ID: 4326)[](https://docs.gmx.io/docs/api/contracts/addresses/#megaeth-chain-id-4326 "Direct link to MegaETH (Chain ID: 4326)")
Explorer: [megaeth.blockscout.com](https://megaeth.blockscout.com/)
| [Full deployment list](https://github.com/gmx-io/gmx-synthetics/blob/updates/docs/megaEth-deployments.md)
| Contract | Address |
| --- | --- |
| DataStore | `0xE43C7B694f6b652a9F4A0f275C008d18758Dce35` |
| RoleStore | `0xecA46636BDDbb4F451ca2B7062C7E36744934655` |
| Reader | `0x0f038EB4a38B08cd3c937a3256b51aa01904a684` |
| ExchangeRouter | `0x73B3593F01CF8e573a412D1d0c972b581794ebE0` |
| Router | `0x1eAfB14236C489C28845EC04F78DECA5Fb9879Aa` |
| Oracle | `0x611640B004719e4843552F60996360Ea6B39E75e` |
| OrderVault | `0xD5AE04762E2afb1506695b3F36286EBE7B0E6772` |
| DepositVault | `0x8231A60862F9b0bA93fFA050c0E94AC902D901d2` |
| WithdrawalVault | `0x0Ec53dda9676219dE63eC703212219b07811F33C` |
| ShiftVault | `0xC255c70b50623054CADbAD9A02E1CFE73d286666` |
| OrderHandler | `0x7d5F99Bab016b831648e278B208579e0eCdb3974` |
| DepositHandler | `0x0d776a8A8aB967193Ad50c3b220996834D5550c7` |
| WithdrawalHandler | `0x8ca83c6243b7461Ae24b5cB167912F5C055F80b0` |
| AdlHandler | `0xf97835F08c2Bc0DA66F0e354Aa6C22b1c99657E6` |
| LiquidationHandler | `0x74fCc13e7D2bf35eAaA06BC2CB3307eD6a852414` |
| ShiftHandler | `0xBb54059D79d6E887f17aF86f724Bb1634b2C6758` |
| GlvVault | `0x52e4875EB5603d21912d30A1dBA6B0B97192459A` |
| EventEmitter | `0xAf2E131d483cedE068e21a9228aD91E623a989C2` |
| MarketFactory | `0x5Fb9121Ca153B93dD70ae53280Dc3b64E1805940` |
| GlvRouter | `0x505F0cCADA00F0CcB4EEbf6467531cF4dd907B0E` |
| GlvReader | `0x424527a588D56513cB2F5161958D83883EE8aB0f` |
| SubaccountRouter | `0x3133aC88af73d3187f1700a2426AD95B5d6E0562` |
| Multicall3 | `0xF516BC01c50eebdBad4d7E506c8f690ae8EAFc52` |
| Config | `0xb7779724235Bc038e41B8b39CA3212411aDD1284` |
| ConfigTimelockController | `0xBf96f66932C1D826C172a80bE7c062ab6b26a4CC` |
| GovTimelockController | `0x0a42516de743D87572f5788cac23F0a2c1a39f69` |
| TimelockConfig | `0x9d5f3fac443748c28FB5dc964D74F8419F686F6D` |
#### Multichain contracts (MegaETH)[](https://docs.gmx.io/docs/api/contracts/addresses/#multichain-contracts-megaeth "Direct link to Multichain contracts (MegaETH)")
| Contract | Address |
| --- | --- |
| MultichainOrderRouter | `0x976363dFbA3AeB8Fb10b733baD74e7099cCB558A` |
| MultichainGmRouter | `0x041336A3DaF0a12d004a95f1511393d9A3d7236d` |
| MultichainGlvRouter | `0x7EF7d01316425de5d7C2EFDf8b802A250c222faB` |
| MultichainClaimsRouter | `0xfE9fD31e499bA6d8733Aec49ECe5b41381103433` |
| MultichainTransferRouter | `0xCa62C570D8667a00A56EB989881ECbA4364BFe9e` |
| MultichainSubaccountRouter | `0xeB8f828A4B89dc3A854f278227A2A5E136E50bF9` |
| MultichainReader | `0xcdA9c0f9Ad580DBf564a3b5a5Ca58D09F11f4FA8` |
| MultichainVault | `0xd6922E889cE4CF14e59427F20e7d857ff81A5A9D` |
#### Relay and oracle provider contracts (MegaETH)[](https://docs.gmx.io/docs/api/contracts/addresses/#relay-and-oracle-provider-contracts-megaeth "Direct link to Relay and oracle provider contracts (MegaETH)")
| Contract | Address |
| --- | --- |
| GelatoRelayRouter | `0x24eD625B9C47fDEbF088A4d12B7f9B4B2f556297` |
| SubaccountGelatoRelayRouter | `0xD515fA0B4d704f3E2C57270F1F53BEeE16348B3b` |
| ChainlinkDataStreamProvider | `0xfdD24de4974fFCeBBA126fF1D17bF18E4a9AE5ac` |
| ChainlinkPriceFeedProvider | `0x7452c558d45f8afC8c83dAe62C3f8A5BE19c71f6` |
| EdgeDataStreamProvider | `0xb9a3e10Fd35e10387B4d3a24AEa443577600E89b` |
| LayerZeroProvider | `0x9c41F854f123a7905907FfcF2578dFB7E47D02E0` |
Testnet[](https://docs.gmx.io/docs/api/contracts/addresses/#testnet "Direct link to Testnet")
-----------------------------------------------------------------------------------------------
Testnet contracts are redeployed more frequently than mainnet. Verify addresses before integrating. Arbitrum Sepolia is usually the most current testnet, but Avalanche Fuji deployment artifacts are also published in the `updates` branch.
### Arbitrum Sepolia (Chain ID: 421614)[](https://docs.gmx.io/docs/api/contracts/addresses/#arbitrum-sepolia-chain-id-421614 "Direct link to Arbitrum Sepolia (Chain ID: 421614)")
Explorer: [sepolia.arbiscan.io](https://sepolia.arbiscan.io/)
| [Full deployment list](https://github.com/gmx-io/gmx-synthetics/blob/updates/docs/arbitrumSepolia-deployments.md)
The Arbitrum Sepolia deployment is the most current testnet. For a frontend that connects to testnet, see [Testnet frontend](https://docs.gmx.io/docs/api/frontend-integration/#testnet-frontend)
.
| Contract | Address |
| --- | --- |
| DataStore | `0xCF4c2C4c53157BcC01A596e3788fFF69cBBCD201` |
| RoleStore | `0x433E3C47885b929aEcE4149E3c835E565a20D95c` |
| Reader | `0x4750376b9378294138Cf7B7D69a2d243f4940f71` |
| ExchangeRouter | `0xEd50B2A1eF0C35DAaF08Da6486971180237909c3` |
| Router | `0x72F13a44C8ba16a678CAD549F17bc9e06d2B8bD2` |
| Oracle | `0x0dC4e24C63C24fE898Dda574C962Ba7Fbb146964` |
| OrderVault | `0x1b8AC606de71686fd2a1AEDEcb6E0EFba28909a2` |
| DepositVault | `0x809Ea82C394beB993c2b6B0d73b8FD07ab92DE5A` |
| WithdrawalVault | `0x7601c9dBbDCf1f5ED1E7Adba4EFd9f2cADa037A5` |
| ShiftVault | `0x6b6F9B7B9a6b69942DAE74FB95E694ec277117af` |
| OrderHandler | `0x000F692690F6C39660AfB878D277f038fb3a8eC6` |
| DepositHandler | `0xdD0228e2806A348209F777c82C90515f9da1b790` |
| WithdrawalHandler | `0x039Ddee97368eb6ed20CE921dE7AD37A92A1A566` |
| AdlHandler | `0x6d8437132784CDDF0cCa3Da249EF49F92947EEE4` |
| LiquidationHandler | `0x268FA5c1dafeefd5E7Bc31CF517c780cb36E7a84` |
| ShiftHandler | `0xC72ea16031bd6731dE2812074cEca8028B8493b9` |
| GlvVault | `0x40bD50de0977c68ecB958ED4A065E14E1091ce64` |
| EventEmitter | `0xa973c2692C1556E1a3d478e745e9a75624AEDc73` |
| MarketFactory | `0x1934838E3d85416A6cF5bF7A5E619f12BE01C4b2` |
| GlvRouter | `0x21b044Bb4a2Ba667723aA3d15ba7b4bCc628084D` |
| GlvReader | `0x9B7D08AB020D9c180E4bAc370fB545317124Cf22` |
| SubaccountRouter | `0xCF45A7E8bB46738f454eC6766631E5612DA90836` |
| Multicall3 | `0xD84793ae65842fFac5C20Ab8eaBD699ea1FC79F3` |
| Config | `0xE2169693147dF45EDc84b759488Aa0E34FD9F939` |
| ConfigTimelockController | `0x8722Df9218bA7d7ee06AE48e990ef38B76750111` |
| GovTimelockController | `0xb1854C5CfB3D25be6198972d5c3AEa0592e933a4` |
| TimelockConfig | `0x674c5Cda9fA404B14D3834D54D7eF258b91BA4a8` |
### Avalanche Fuji (Chain ID: 43113)[](https://docs.gmx.io/docs/api/contracts/addresses/#avalanche-fuji-chain-id-43113 "Direct link to Avalanche Fuji (Chain ID: 43113)")
Explorer: [testnet.snowtrace.io](https://testnet.snowtrace.io/)
| [Full deployment list](https://github.com/gmx-io/gmx-synthetics/blob/updates/docs/avalancheFuji-deployments.md)
| Contract | Address |
| --- | --- |
| DataStore | `0xEA1BFb4Ea9A412dCCd63454AbC127431eBB0F0d4` |
| RoleStore | `0x19a8085537078e7847a332A76ABaDD5b02B1e736` |
| Reader | `0xf82Cc6EB57F8FF86bc5c5e90B8BA83DbBFB517eE` |
| ExchangeRouter | `0x0a458C96Ac0B2a130DA4BdF1aAdD4cb7Be036d11` |
| Router | `0x5e7d61e4C52123ADF651961e4833aCc349b61491` |
| Oracle | `0xae7c79ED2807Fe544f5757890ca8afB9d553f17c` |
| OrderVault | `0x25D23e8E655727F2687CC808BB9589525A6F599B` |
| DepositVault | `0x2964d242233036C8BDC1ADC795bB4DeA6fb929f2` |
| WithdrawalVault | `0x74d49B6A630Bf519bDb6E4efc4354C420418A6A2` |
| ShiftVault | `0x257D0EA0B040E2Cd1D456fB4C66d7814102aD346` |
| OrderHandler | `0xb525036363BC44695d36fD56Bcb86CEF39cd444A` |
| DepositHandler | `0x12383b2AB771471003185a83cf983c98A826bD4E` |
| WithdrawalHandler | `0xe80Fea80cA767a105A65D67bFA970ecF1B4e9127` |
| AdlHandler | `0x96b2004d52d30b21385E6757b1EEbd1565864f6A` |
| LiquidationHandler | `0x4092cC8E8dC0893f93f35f5998585a6109d91a46` |
| ShiftHandler | `0xd96Eb278505EF101B3a1328636DFb2F215Bb6bA5` |
| GlvVault | `0x76f93b5240DF811a3fc32bEDd58daA5784e46C96` |
| EventEmitter | `0xc67D98AC5803aFD776958622CeEE332A0B2CabB9` |
| MarketFactory | `0x89810f23585FDCfAFfB1712e5B76d9b0F722e1d6` |
| GlvRouter | `0x6B6595389A0196F882C0f66CB1F401f1D24afEdC` |
| GlvReader | `0xdeaC9ea3c72C102f2a9654b8E1A14Ef86Cdd3146` |
| SubaccountRouter | `0xD5EE3ECAF5754CE5Ff74847d0caf094EBB12ed5e` |
| Multicall3 | `0x966D1F5c54a714C6443205F0Ec49eEF81F10fdfD` |
| Config | `0x63725E32b05324042Fe78C34be3E72497C91e1E0` |
| ConfigTimelockController | `0xc120bD6756171691fC2e2D5EE876ae79526412c1` |
| GovTimelockController | `0x8beF3F7f3B2d8b8490Cf30b42c728293D1C2a9Ef` |
| Timelock | `0x0f0c78405A4E6dAfc188d539D61C69D74f42f9dB` |
| TimelockConfig | `0xa2c59bf9999915C2DF87998739c2e3Efa9c856f4` |
note
Testnet deployments may include additional test contracts (`MockPriceFeed`, test tokens) not present on mainnet. See the full deployment list linked above for all testnet contracts.
Contract categories[](https://docs.gmx.io/docs/api/contracts/addresses/#contract-categories "Direct link to Contract categories")
-----------------------------------------------------------------------------------------------------------------------------------
The sections below describe the purpose of each contract category listed in the address tables.
### Multichain contracts[](https://docs.gmx.io/docs/api/contracts/addresses/#multichain-contracts "Direct link to Multichain contracts")
The `Multichain*` contracts enable cross-chain operations through the [GMX Account](https://docs.gmx.io/docs/trading/overview/#gmx-account-multichain)
system. They let users on one chain submit orders, manage positions, and transfer funds to GMX deployments on other chains via LayerZero messaging.
| Contract | Purpose |
| --- | --- |
| MultichainOrderRouter | Routes cross-chain order creation requests |
| MultichainGmRouter | Routes cross-chain GM token deposit/withdrawal requests |
| MultichainGlvRouter | Routes cross-chain GLV deposit/withdrawal requests |
| MultichainClaimsRouter | Routes cross-chain claim requests (funding fees, rebates) |
| MultichainTransferRouter | Routes cross-chain token transfers |
| MultichainSubaccountRouter | Routes cross-chain subaccount operations |
| MultichainReader | Reads cross-chain state and pending operations |
| MultichainVault | Holds funds in transit during cross-chain operations |
### Gelato relay contracts[](https://docs.gmx.io/docs/api/contracts/addresses/#gelato-relay-contracts "Direct link to Gelato relay contracts")
The Gelato relay contracts enable gasless transaction submission. Users sign a message off-chain, and a Gelato relay network submits the transaction on their behalf. This powers the Express Trading mode in the GMX interface.
| Contract | Purpose |
| --- | --- |
| GelatoRelayRouter | Accepts relay requests for standard operations |
| SubaccountGelatoRelayRouter | Accepts relay requests for subaccount operations |
### Oracle provider contracts[](https://docs.gmx.io/docs/api/contracts/addresses/#oracle-provider-contracts "Direct link to Oracle provider contracts")
Multiple oracle providers feed price data into the protocol. The `Oracle` contract aggregates prices from these providers, selecting the most appropriate source for each token.
| Contract | Purpose |
| --- | --- |
| ChainlinkDataStreamProvider | Fetches prices from Chainlink Data Streams (primary source for most tokens) |
| ChainlinkPriceFeedProvider | Fetches prices from Chainlink Price Feeds (fallback and reference) |
| EdgeDataStreamProvider | Fetches prices from Edge oracle data streams |
### Governance and configuration contracts[](https://docs.gmx.io/docs/api/contracts/addresses/#governance-and-configuration-contracts "Direct link to Governance and configuration contracts")
The governance and configuration contracts control protocol parameters and enforce time-delayed updates. Changes to protocol parameters flow through the `Config` contract, which is gated by the `ConfigTimelockController` to ensure a mandatory delay before changes take effect. Higher-level governance actions are managed through `GovTimelockController` and `Timelock`.
| Contract | Purpose |
| --- | --- |
| Config | Applies parameter changes to the protocol through the timelock system |
| ConfigTimelockController | Enforces time delays on configuration updates submitted via Config |
| GovTimelockController | Controls governance-level actions with time-delayed execution |
| Timelock | Manages protocol upgrades, role assignments, and privileged operations |
| TimelockConfig | Stores timelock duration settings for different operation categories |
### Cross-chain messaging[](https://docs.gmx.io/docs/api/contracts/addresses/#cross-chain-messaging "Direct link to Cross-chain messaging")
| Contract | Purpose |
| --- | --- |
| LayerZeroProvider | Handles cross-chain message and data verification |
* [Mainnet](https://docs.gmx.io/docs/api/contracts/addresses/#mainnet)
* [Arbitrum (Chain ID: 42161)](https://docs.gmx.io/docs/api/contracts/addresses/#arbitrum-chain-id-42161)
* [Avalanche (Chain ID: 43114)](https://docs.gmx.io/docs/api/contracts/addresses/#avalanche-chain-id-43114)
* [Botanix (Chain ID: 3637)](https://docs.gmx.io/docs/api/contracts/addresses/#botanix-chain-id-3637)
* [MegaETH (Chain ID: 4326)](https://docs.gmx.io/docs/api/contracts/addresses/#megaeth-chain-id-4326)
* [Testnet](https://docs.gmx.io/docs/api/contracts/addresses/#testnet)
* [Arbitrum Sepolia (Chain ID: 421614)](https://docs.gmx.io/docs/api/contracts/addresses/#arbitrum-sepolia-chain-id-421614)
* [Avalanche Fuji (Chain ID: 43113)](https://docs.gmx.io/docs/api/contracts/addresses/#avalanche-fuji-chain-id-43113)
* [Contract categories](https://docs.gmx.io/docs/api/contracts/addresses/#contract-categories)
* [Multichain contracts](https://docs.gmx.io/docs/api/contracts/addresses/#multichain-contracts)
* [Gelato relay contracts](https://docs.gmx.io/docs/api/contracts/addresses/#gelato-relay-contracts)
* [Oracle provider contracts](https://docs.gmx.io/docs/api/contracts/addresses/#oracle-provider-contracts)
* [Governance and configuration contracts](https://docs.gmx.io/docs/api/contracts/addresses/#governance-and-configuration-contracts)
* [Cross-chain messaging](https://docs.gmx.io/docs/api/contracts/addresses/#cross-chain-messaging)
---
# Event monitoring | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/contracts/events/#__docusaurus_skipToContent_fallback)
On this page
All protocol events are emitted through a single `EventEmitter` contract. Every event carries an `eventName` field, so you can monitor any protocol action by filtering on the `EventEmitter` address plus the `eventName` value — without needing to track individual logic contract addresses, which may be upgraded over time.
The `EventEmitter` address for each network is listed on [Contract addresses](https://docs.gmx.io/docs/api/contracts/addresses/)
. For the full generated deployment inventory, see the [gmx-synthetics docs folder](https://github.com/gmx-io/gmx-synthetics/tree/updates/docs)
.
Event types[](https://docs.gmx.io/docs/api/contracts/events/#event-types "Direct link to Event types")
--------------------------------------------------------------------------------------------------------
The `EventEmitter` contract defines three structured event signatures that differ by the number of indexed `bytes32` topics:
| Event | Indexed topics | Use case |
| --- | --- | --- |
| `EventLog` | `eventNameHash` only | General events with no additional indexed lookup |
| `EventLog1` | `eventNameHash`, `topic1` | Events indexed by one key (for example, an action key) |
| `EventLog2` | `eventNameHash`, `topic1`, `topic2` | Events indexed by two keys (for example, market address and account) |
All three variants include `msgSender`, `eventName` (as a plain string), `eventNameHash` (indexed for filtering), and `eventData` (a structured `EventUtils.EventLogData` payload containing typed arrays of addresses, uints, ints, bools, bytes32 values, bytes, and strings).
The `EventEmitter` also exposes raw log functions (`emitDataLog1` through `emitDataLog4`) that emit unstructured logs using assembly. These are used for general-purpose data emission and don't follow the `EventLog` schema.
Which variant a specific protocol event uses depends on how the emitting contract calls the `EventEmitter`. Check the relevant contract source to determine the correct variant before setting up a filter.
Example: monitoring Timelock actions with OpenZeppelin Defender[](https://docs.gmx.io/docs/api/contracts/events/#example-monitoring-timelock-actions-with-openzeppelin-defender "Direct link to Example: monitoring Timelock actions with OpenZeppelin Defender")
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
The following steps configure an alert that fires whenever an action is signalled on the `TimelockConfig` contract. Timelock signal events use `EventLog1` with `eventName == "SignalPendingAction"` and the action key as `topic1`.
1. In [OpenZeppelin Defender](https://defender.openzeppelin.com/)
, select the "Monitor" (Sentinel) option.
2. Click "Create Monitor."
3. Enter a name for the monitor.
4. Select the target network.
5. Enter the `EventEmitter` address for that network in the "Addresses" field.
6. Under "Contract conditions," select "Events" > "EventLog1."
7. In the filter field below "EventLog1," enter `eventName == "SignalPendingAction"`.
8. Click "Next" and configure a notification channel.
With this configuration, you receive a notification each time an action is signalled on the Timelock.
* [Event types](https://docs.gmx.io/docs/api/contracts/events/#event-types)
* [Example: monitoring Timelock actions with OpenZeppelin Defender](https://docs.gmx.io/docs/api/contracts/events/#example-monitoring-timelock-actions-with-openzeppelin-defender)
---
# Fees | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/contracts/fees/#__docusaurus_skipToContent_fallback)
On this page
This page documents fee types, execution fee calculation, and how to retrieve fee parameters from the DataStore.
UI fee[](https://docs.gmx.io/docs/api/contracts/fees/#ui-fee "Direct link to UI fee")
---------------------------------------------------------------------------------------
UI fees are charged on top of the base protocol fee. The percentage is based on the `uiFeeFactor` configured for the `uiFeeReceiver` address you pass when creating an action. For more information, see [Running a frontend](https://docs.gmx.io/docs/api/frontend-integration/#running-a-frontend)
.
Configure the UI fee percentage for your address by calling `ExchangeRouter.setUiFeeFactor`. The `uiFeeFactor` is a percentage value over `10^30`. For example, if the `uiFeeFactor` is `2 * 10^25`, the percentage charged is `(2 * 10^25) / (10^30) = 0.00002 = 0.002%`. The call reverts with `InvalidUiFeeFactor` if the value exceeds the maximum.
The maximum `uiFeeFactor` is capped by `dataStore.getUint(Keys.MAX_UI_FEE_FACTOR)`.
You can pass the `uiFeeReceiver` value for the following actions:
* Deposits
* Withdrawals
* Swap orders
* Increase and decrease position orders (Market Increase, Limit Increase, Market Decrease, Limit Decrease, Stop-Loss, Take-Profit)
* GLV deposits
* GLV withdrawals
* Shifts
For deposits, withdrawals, and swaps, the fee is a percentage of the input amount. For increase and decrease position orders, the fee is a percentage of the position size change.
UI fees are credited when deposits, withdrawals, and orders execute. Call `ExchangeRouter.claimUiFees` to claim accumulated fees at any time. The caller's address (`msg.sender`) is used as the `uiFeeReceiver` for the claim.
Execution fee[](https://docs.gmx.io/docs/api/contracts/fees/#execution-fee "Direct link to Execution fee")
------------------------------------------------------------------------------------------------------------
Creating a deposit, order, withdrawal, shift, GLV deposit, or GLV withdrawal request requires sending an `executionFee` as the transaction value.
During creation, the contracts verify that the provided `executionFee` is at least the minimum, calculated as:
tx.gasprice * GasUtils.adjustGasLimitForEstimate(dataStore, estimatedGasLimit, oraclePriceCount)
To calculate the `estimatedGasLimit`, use the appropriate function:
* For deposits: `GasUtils.estimateExecuteDepositGasLimit`
* For withdrawals: `GasUtils.estimateExecuteWithdrawalGasLimit`
* For orders: `GasUtils.estimateExecuteOrderGasLimit`
* For shifts: `GasUtils.estimateExecuteShiftGasLimit`
* For GLV deposits: `GasUtils.estimateExecuteGlvDepositGasLimit`
* For GLV withdrawals: `GasUtils.estimateExecuteGlvWithdrawalGasLimit`
Because `tx.gasprice` fluctuates based on network usage, add a buffer to reduce the risk of the creation transaction reverting. If the provided `executionFee` is below the minimum, the transaction reverts with `InsufficientExecutionFee`. Upon execution, any excess execution fee is refunded to the request's `account` address.
Funding[](https://docs.gmx.io/docs/api/contracts/fees/#funding "Direct link to Funding")
------------------------------------------------------------------------------------------
For an overview of how funding fees work, see [adaptive funding](https://docs.gmx.io/docs/trading/fees/#adaptive-funding)
.
Retrieve funding fee parameters from the [DataStore](https://docs.gmx.io/docs/api/contracts/overview/#reading-values)
using these keys. All keys are per-market.
| Key | Description |
| --- | --- |
| `FUNDING_FACTOR` | Base funding factor per second |
| `FUNDING_EXPONENT_FACTOR` | Exponent applied to the open interest imbalance ratio |
| `FUNDING_INCREASE_FACTOR_PER_SECOND` | Rate at which the funding factor increases per second |
| `FUNDING_DECREASE_FACTOR_PER_SECOND` | Rate at which the funding factor decreases per second |
| `MIN_FUNDING_FACTOR_PER_SECOND` | Minimum funding factor per second |
| `MAX_FUNDING_FACTOR_PER_SECOND` | Maximum funding factor per second |
| `THRESHOLD_FOR_STABLE_FUNDING` | Imbalance threshold below which funding stays stable |
| `THRESHOLD_FOR_DECREASE_FUNDING` | Imbalance threshold below which the funding factor decreases |
Borrowing[](https://docs.gmx.io/docs/api/contracts/fees/#borrowing "Direct link to Borrowing")
------------------------------------------------------------------------------------------------
For an overview of how borrow fees work, see [borrow fees](https://docs.gmx.io/docs/trading/fees/#borrow-fees)
.
Retrieve borrow fee parameters from the [DataStore](https://docs.gmx.io/docs/api/contracts/overview/#reading-values)
using these keys. Each market uses one of the two models below.
### Kink model[](https://docs.gmx.io/docs/api/contracts/fees/#kink-model "Direct link to Kink model")
| Key | Description |
| --- | --- |
| `OPTIMAL_USAGE_FACTOR` | Utilization threshold where the rate slope increases |
| `BASE_BORROWING_FACTOR` | Base rate factor below optimal utilization |
| `ABOVE_OPTIMAL_USAGE_BORROWING_FACTOR` | Rate factor applied above optimal utilization |
### Curve (power) model[](https://docs.gmx.io/docs/api/contracts/fees/#curve-power-model "Direct link to Curve (power) model")
| Key | Description |
| --- | --- |
| `BORROWING_FACTOR` | Per-market borrowing factor for longs and shorts |
| `BORROWING_EXPONENT_FACTOR` | Per-market exponent for longs and shorts |
| `SKIP_BORROWING_FEE_FOR_SMALLER_SIDE` | If true, the side with smaller open interest pays zero borrow fees |
Position and swap fees[](https://docs.gmx.io/docs/api/contracts/fees/#position-and-swap-fees "Direct link to Position and swap fees")
---------------------------------------------------------------------------------------------------------------------------------------
Retrieve position and swap fee parameters from the [DataStore](https://docs.gmx.io/docs/api/contracts/overview/#reading-values)
using these keys. Fee factors are percentage values over `10^30`.
### Position fees[](https://docs.gmx.io/docs/api/contracts/fees/#position-fees "Direct link to Position fees")
| Key | Description |
| --- | --- |
| `POSITION_FEE_FACTOR` | Percentage fee deducted on position increase and decrease, based on position size change |
| `POSITION_IMPACT_FACTOR` | Price impact factor for position actions |
| `MAX_POSITION_IMPACT_FACTOR` | Cap on negative price impact for positions |
| `MAX_POSITION_IMPACT_FACTOR_FOR_LIQUIDATIONS` | Cap on negative price impact applied during liquidations |
| `POSITION_IMPACT_EXPONENT_FACTOR` | Exponent for position price impact calculation |
| `POSITION_IMPACT_POOL_DISTRIBUTION_RATE` | Rate at which the position impact pool is distributed to the market pool |
| `PRO_DISCOUNT_FACTOR` | Fee discount factor applied to pro-tier traders |
### Swap fees[](https://docs.gmx.io/docs/api/contracts/fees/#swap-fees "Direct link to Swap fees")
| Key | Description |
| --- | --- |
| `SWAP_FEE_FACTOR` | Percentage fee deducted on swaps, based on swap amount |
| `ATOMIC_SWAP_FEE_FACTOR` | Percentage fee deducted on atomic swaps using on-chain price feeds |
| `SWAP_IMPACT_FACTOR` | Price impact factor for swaps |
| `SWAP_IMPACT_EXPONENT_FACTOR` | Exponent for swap price impact calculation |
| `ATOMIC_SWAP_FEE_TYPE` | Type flag that determines the atomic swap fee behavior |
### Deposit and withdrawal fees[](https://docs.gmx.io/docs/api/contracts/fees/#deposit-and-withdrawal-fees "Direct link to Deposit and withdrawal fees")
| Key | Description |
| --- | --- |
| `DEPOSIT_FEE_FACTOR` | Percentage fee deducted on deposits, based on deposit amount |
| `WITHDRAWAL_FEE_FACTOR` | Percentage fee deducted on withdrawals, based on withdrawal amount |
| `ATOMIC_WITHDRAWAL_FEE_FACTOR` | Percentage fee deducted on atomic withdrawals using on-chain price feeds |
### Liquidation fees[](https://docs.gmx.io/docs/api/contracts/fees/#liquidation-fees "Direct link to Liquidation fees")
| Key | Description |
| --- | --- |
| `LIQUIDATION_FEE_FACTOR` | Percentage fee deducted when a position is liquidated |
### Fee receiver factors[](https://docs.gmx.io/docs/api/contracts/fees/#fee-receiver-factors "Direct link to Fee receiver factors")
These parameters control the share of collected fees allocated to the fee receiver. Each is a percentage value over `10^30`.
| Key | Description |
| --- | --- |
| `POSITION_FEE_RECEIVER_FACTOR` | Share of position fees allocated to the fee receiver |
| `SWAP_FEE_RECEIVER_FACTOR` | Share of swap fees allocated to the fee receiver |
| `BORROWING_FEE_RECEIVER_FACTOR` | Share of borrow fees allocated to the fee receiver |
| `LIQUIDATION_FEE_RECEIVER_FACTOR` | Share of liquidation fees allocated to the fee receiver |
Relay fees[](https://docs.gmx.io/docs/api/contracts/fees/#relay-fees "Direct link to Relay fees")
---------------------------------------------------------------------------------------------------
These parameters control fee calculation for Gelato relay (gasless) transactions.
| Key | Description |
| --- | --- |
| `GELATO_RELAY_FEE_MULTIPLIER_FACTOR` | Multiplier applied to the relay fee calculation |
| `GELATO_RELAY_FEE_BASE_AMOUNT` | Base fee amount for relay transactions |
Atomic operation parameters[](https://docs.gmx.io/docs/api/contracts/fees/#atomic-operation-parameters "Direct link to Atomic operation parameters")
------------------------------------------------------------------------------------------------------------------------------------------------------
These parameters control behavior for atomic (synchronous) operations that use on-chain price feeds.
| Key | Description |
| --- | --- |
| `MAX_ATOMIC_ORACLE_PRICE_AGE` | Maximum acceptable age for oracle prices in atomic operations |
Advanced parameters[](https://docs.gmx.io/docs/api/contracts/fees/#advanced-parameters "Direct link to Advanced parameters")
------------------------------------------------------------------------------------------------------------------------------
These parameters control specialized protocol behavior.
| Key | Description |
| --- | --- |
| `DATA_STREAM_SPREAD_REDUCTION_FACTOR` | Factor applied to reduce the bid-ask spread from data stream oracle prices |
| `GLV_SHIFT_MAX_LOSS_FACTOR` | Maximum acceptable loss factor when executing GLV shifts |
| `BUYBACK_GMX_FACTOR` | Factor controlling GMX token buyback from protocol fees |
| `BUYBACK_MAX_PRICE_IMPACT_FACTOR` | Maximum price impact allowed for buyback operations |
* [UI fee](https://docs.gmx.io/docs/api/contracts/fees/#ui-fee)
* [Execution fee](https://docs.gmx.io/docs/api/contracts/fees/#execution-fee)
* [Funding](https://docs.gmx.io/docs/api/contracts/fees/#funding)
* [Borrowing](https://docs.gmx.io/docs/api/contracts/fees/#borrowing)
* [Kink model](https://docs.gmx.io/docs/api/contracts/fees/#kink-model)
* [Curve (power) model](https://docs.gmx.io/docs/api/contracts/fees/#curve-power-model)
* [Position and swap fees](https://docs.gmx.io/docs/api/contracts/fees/#position-and-swap-fees)
* [Position fees](https://docs.gmx.io/docs/api/contracts/fees/#position-fees)
* [Swap fees](https://docs.gmx.io/docs/api/contracts/fees/#swap-fees)
* [Deposit and withdrawal fees](https://docs.gmx.io/docs/api/contracts/fees/#deposit-and-withdrawal-fees)
* [Liquidation fees](https://docs.gmx.io/docs/api/contracts/fees/#liquidation-fees)
* [Fee receiver factors](https://docs.gmx.io/docs/api/contracts/fees/#fee-receiver-factors)
* [Relay fees](https://docs.gmx.io/docs/api/contracts/fees/#relay-fees)
* [Atomic operation parameters](https://docs.gmx.io/docs/api/contracts/fees/#atomic-operation-parameters)
* [Advanced parameters](https://docs.gmx.io/docs/api/contracts/fees/#advanced-parameters)
---
# Advanced entry points | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#__docusaurus_skipToContent_fallback)
On this page
This page covers the contract surfaces beyond the core `ExchangeRouter` / `GlvRouter` flow: delegated subaccount trading, gasless relay routers, and multichain GMX Account routers. Some of these are end-user or integrator entry points, while others are specialized router or controller surfaces.
If you need an end-to-end implementation pattern for delegated trader flows rather than just the raw contract surface, see [Delegated trading integration](https://docs.gmx.io/docs/api/contracts/delegated-trading/)
.
For the core request lifecycle, see [Architecture](https://docs.gmx.io/docs/api/contracts/architecture/)
. For standard GM and GLV actions, see [ExchangeRouter](https://docs.gmx.io/docs/api/contracts/exchange-router/)
and [GlvRouter](https://docs.gmx.io/docs/api/contracts/glv-router/)
.
SubaccountRouter[](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#subaccountrouter "Direct link to SubaccountRouter")
-------------------------------------------------------------------------------------------------------------------------------------
`SubaccountRouter` is a legacy contract that is still deployed but no longer used for order operations. The current GMX interface only calls it for wallet-based subaccount removal outside the express flow. New integrations should use `SubaccountGelatoRelayRouter` for delegated order execution.
The contract originally let a main account delegate order management to a subaccount without giving that subaccount full custody of the account.
### Management functions[](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#management-functions "Direct link to Management functions")
| Function | Purpose |
| --- | --- |
| `addSubaccount(address subaccount)` | Authorize a delegated subaccount |
| `removeSubaccount(address subaccount)` | Remove a delegated subaccount |
| `setSubaccountExpiresAt(address subaccount, bytes32 actionType, uint256 expiresAt)` | Set an expiry timestamp for a delegated action type |
| `setMaxAllowedSubaccountActionCount(address subaccount, bytes32 actionType, uint256 maxAllowedCount)` | Cap how many actions a subaccount can perform |
| `setSubaccountAutoTopUpAmount(address subaccount, uint256 amount)` | Configure automatic native-token top-ups for the subaccount |
| `setIntegrationId(address subaccount, bytes32 integrationId)` | Bind the subaccount to an integration identifier |
### Order functions[](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#order-functions "Direct link to Order functions")
`SubaccountRouter` only exposes delegated order actions:
| Function | Purpose |
| --- | --- |
| `createOrder(address account, CreateOrderParams params)` | Create an order for the main account |
| `updateOrder(bytes32 key, ...)` | Update a pending order |
| `cancelOrder(bytes32 key)` | Cancel a pending order |
### Integration notes[](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#integration-notes "Direct link to Integration notes")
* Subaccount order actions are gated by `Keys.SUBACCOUNT_ORDER_ACTION`.
* The router validates the main account's integration id before handling the action.
* For swap and increase orders, the router transfers the main account's collateral into `OrderVault` through the core `Router` plugin mechanism.
* Auto top-up uses the main account's WNT allowance and balance, then unwraps native token to the subaccount. The top-up amount is capped to the native tokens actually spent on gas plus execution fee.
For the exact implementation, see [`SubaccountRouter.sol`](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/router/SubaccountRouter.sol)
.
Gelato relay routers[](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#gelato-relay-routers "Direct link to Gelato relay routers")
-------------------------------------------------------------------------------------------------------------------------------------------------
GMX exposes two relay entry points for gasless order management:
| Contract | Purpose |
| --- | --- |
| `GelatoRelayRouter` | Gasless create / update / cancel / batch order flow for the main account |
| `SubaccountGelatoRelayRouter` | Gasless delegated order flow for subaccounts, plus `removeSubaccount` |
### Supported actions[](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#supported-actions "Direct link to Supported actions")
| Function | `GelatoRelayRouter` | `SubaccountGelatoRelayRouter` |
| --- | --- | --- |
| `batch(...)` | Yes | Yes |
| `createOrder(...)` | Yes | Yes |
| `updateOrder(...)` | Yes | Yes |
| `cancelOrder(...)` | Yes | Yes |
| `removeSubaccount(...)` | No | Yes |
### RelayParams structure[](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#relayparams-structure "Direct link to RelayParams structure")
Relay calls share the `IRelayUtils.RelayParams` envelope:
* `oracleParams`: optional oracle data for GMX-based fee swaps
* `externalCalls`: optional external swap / call bundle
* `tokenPermits`: optional EIP-2612 permits
* `fee`: `feeToken`, `feeAmount`, and optional `feeSwapPath`
* `userNonce`: replay-protection nonce chosen by the user
* `deadline`: signature expiry
* `signature`: signed relay authorization
* `desChainId`: destination chain id expected by the signature
### Integration notes[](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#integration-notes-1 "Direct link to Integration notes")
* Relay routers do not expose `multicall` or `sendTokens`; token movements for external calls must be declared through `externalCalls.sendTokens` and `externalCalls.sendAmounts`.
* Relay fees are paid from the main account, not the relayer.
* `SubaccountGelatoRelayRouter` additionally validates a `SubaccountApproval` signature and per-account nonce.
* External calls are rejected for subaccount relay orders.
For the exact implementation, see [`GelatoRelayRouter.sol`](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/router/relay/GelatoRelayRouter.sol)
, [`SubaccountGelatoRelayRouter.sol`](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/router/relay/SubaccountGelatoRelayRouter.sol)
, and [`IRelayUtils.sol`](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/router/relay/IRelayUtils.sol)
.
Multichain routers[](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#multichain-routers "Direct link to Multichain routers")
-------------------------------------------------------------------------------------------------------------------------------------------
The multichain contracts power GMX Account flows and other cross-chain operations.
### Action routers[](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#action-routers "Direct link to Action routers")
| Contract | Notable surface |
| --- | --- |
| `MultichainOrderRouter` | `batch`, `createOrder`, `updateOrder`, `cancelOrder`, `setTraderReferralCode`, `registerCode` |
| `MultichainGmRouter` | `createDeposit`, `createWithdrawal`, `createShift` |
| `MultichainGlvRouter` | `createGlvDeposit`, `createGlvWithdrawal` |
| `MultichainClaimsRouter` | `claimFundingFees`, `claimCollateral`, `claimAffiliateRewards` |
| `MultichainTransferRouter` | `bridgeIn`, `bridgeOut`, `transferOut` |
### Reader surface[](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#reader-surface "Direct link to Reader surface")
`MultichainReader` is the cross-chain read helper. Its notable entry points are:
* `quoteReadFee(...)` to estimate the LayerZero read fee
* `sendReadRequests(...)` to dispatch read requests across configured chains
* `lzReceive(...)` to receive LayerZero read responses and forward them to the registered originator
### Integration notes[](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#integration-notes-2 "Direct link to Integration notes")
* Multichain action routers take both `account` and `srcChainId`, because the action may originate from a different chain than the settlement chain.
* GM and GLV multichain routers also take `TransferRequests` so funds can be routed into the correct vaults before the action is created.
* Claim routes send outputs into `MultichainVault` first, then record the transfer for the destination receiver.
* `MultichainTransferRouter.bridgeOutFromController(...)` is controller-only infrastructure for protocol-driven bridge-outs after execution, not a general user-facing entry point.
* `MultichainReader.quoteReadFee(...)` is a public read helper, but `sendReadRequests(...)` is controller-gated and intended for authorized originators rather than general end users.
* `lzReceive(...)` is part of the LayerZero receive path and not a normal end-user entry point.
For the exact implementation, see [`IMultichainOrderRouter.sol`](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/multichain/IMultichainOrderRouter.sol)
, [`IMultichainGmRouter.sol`](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/multichain/IMultichainGmRouter.sol)
, [`IMultichainGlvRouter.sol`](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/multichain/IMultichainGlvRouter.sol)
, [`IMultichainTransferRouter.sol`](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/multichain/IMultichainTransferRouter.sol)
, [`MultichainClaimsRouter.sol`](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/multichain/MultichainClaimsRouter.sol)
, and [`MultichainReader.sol`](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/multichain/MultichainReader.sol)
.
Next steps[](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#next-steps "Direct link to Next steps")
-------------------------------------------------------------------------------------------------------------------
* [Contract addresses](https://docs.gmx.io/docs/api/contracts/addresses/)
for live deployments
* [Delegated trading integration](https://docs.gmx.io/docs/api/contracts/delegated-trading/)
for end-to-end subaccount and relay patterns
* [ExchangeRouter](https://docs.gmx.io/docs/api/contracts/exchange-router/)
for standard order, deposit, withdrawal, and shift flows
* [GlvRouter](https://docs.gmx.io/docs/api/contracts/glv-router/)
for GLV request flows
* [Known issues](https://docs.gmx.io/docs/api/contracts/known-issues/)
for integration caveats and operational risks
* [SubaccountRouter](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#subaccountrouter)
* [Management functions](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#management-functions)
* [Order functions](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#order-functions)
* [Integration notes](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#integration-notes)
* [Gelato relay routers](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#gelato-relay-routers)
* [Supported actions](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#supported-actions)
* [RelayParams structure](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#relayparams-structure)
* [Integration notes](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#integration-notes-1)
* [Multichain routers](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#multichain-routers)
* [Action routers](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#action-routers)
* [Reader surface](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#reader-surface)
* [Integration notes](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#integration-notes-2)
* [Next steps](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/#next-steps)
---
# Architecture | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/contracts/architecture/#__docusaurus_skipToContent_fallback)
On this page
This page covers the GMX smart contract architecture, execution model, keeper network, and integration considerations. For contract function references, see [Reader](https://docs.gmx.io/docs/api/contracts/reader/)
, [ExchangeRouter](https://docs.gmx.io/docs/api/contracts/exchange-router/)
, and [GLV Reader](https://docs.gmx.io/docs/api/contracts/glv-reader/)
.
Contract structure[](https://docs.gmx.io/docs/api/contracts/architecture/#contract-structure "Direct link to Contract structure")
-----------------------------------------------------------------------------------------------------------------------------------
The GMX protocol separates concerns across four contract categories. These categories describe the internal contract architecture, not the subset of contracts most integrations call directly day to day.
| Category | Role | Examples |
| --- | --- | --- |
| **Bank contracts** | Hold funds. Only these contracts custody tokens. | `Bank`, `StrictBank`, `MarketToken`, `DepositVault`, `OrderVault`, `WithdrawalVault`, `ShiftVault`, `GlvVault` |
| **Data storage** | Maintain all protocol state in a single store. | `DataStore`, `RoleStore`, `OracleStore` |
| **Logic contracts** | Stateless execution logic. Read from DataStore, compute results, emit events. | `ExchangeRouter`, `GlvRouter`, `Reader`, `GlvReader`, `OrderHandler`, `DepositHandler`, `WithdrawalHandler`, `ShiftHandler`, `LiquidationHandler`, `AdlHandler`, all `*Utils` contracts |
| **Event utilities** | Generalized event emission for indexing and monitoring. | `EventEmitter` |
This separation enables contract upgrades without migrating funds. When a logic contract is upgraded, a new version is deployed and granted the appropriate roles in `RoleStore`. The bank contracts and `DataStore` remain unchanged — no fund migration is required.
For most integrations, the main entry points are `ExchangeRouter` for writes and `Reader` / `GlvReader` for reads. `GlvRouter` handles GLV-specific operations (deposits, withdrawals). Many of the other contracts listed above are supporting handlers, storage contracts, or utilities used internally by those entry points.
Struct data is serialized into `DataStore` through `*StoreUtils` contracts (for example, `OrderStoreUtils`, `PositionStoreUtils`, `ShiftStoreUtils`, `MarketStoreUtils`, `GlvStoreUtils`), which allows new keys to be added to structs without requiring storage migration. Order and position lists are stored on-chain using `EnumerableSet` rather than relying on indexers, so interfaces and keepers can query accurate data without waiting for indexer sync delays.
warning
`RoleStore` and `DataStore` must not change after deployment. Replacing either requires migrating all funds and reconfiguring every dependent contract. New handlers and routers receive different addresses; integrations must support multiple handler versions temporarily during transitions.
### Role-based access control[](https://docs.gmx.io/docs/api/contracts/architecture/#role-based-access-control "Direct link to Role-based access control")
All privileged operations are gated through `RoleStore`, which maps addresses to roles using an `EnumerableSet`\-backed store with a `roleCache` mapping for gas-efficient lookups. Handlers, keepers, and governance controllers each hold specific roles that authorize their actions. The `Config` contract applies parameter changes through a `ConfigTimelockController` (extending OpenZeppelin's `TimelockController`) that enforces time delays on sensitive updates.
### EventEmitter[](https://docs.gmx.io/docs/api/contracts/architecture/#eventemitter "Direct link to EventEmitter")
Rather than emitting events from each contract individually, the protocol routes all events through a shared `EventEmitter` contract. This provides a single address to monitor for all protocol activity. The `EventEmitter` uses three structured event types (`EventLog`, `EventLog1`, `EventLog2`) with different numbers of indexed topics for efficient filtering, plus raw `emitDataLog1` through `emitDataLog4` functions for general-purpose log emission.
For monitoring integration examples, see [Events](https://docs.gmx.io/docs/api/contracts/events/)
.
Execution model[](https://docs.gmx.io/docs/api/contracts/architecture/#execution-model "Direct link to Execution model")
--------------------------------------------------------------------------------------------------------------------------
Most user actions follow a two-phase request-execution pattern:
**Phase 1 — Request:** The user submits a transaction (via `ExchangeRouter`) that stores the request parameters on-chain — order type, size, collateral, acceptable price, and execution fee. No oracle prices are needed at this stage.
**Phase 2 — Execution:** A keeper observes the request, fetches signed oracle prices from archive nodes, and submits an execution transaction that bundles the prices with the request key. The contract validates the prices and executes the order atomically.
Execution uses a try/catch pattern in `OrderHandler.executeOrder`. If the error is a keeper issue (insufficient gas, missing oracle prices), the entire transaction reverts so that the user's request is not unnecessarily cancelled. For market orders, user-side errors (unmet conditions, insufficient funds) cancel the request and return funds. For limit and trigger orders, the order is frozen instead of cancelled to prevent gaming — see [Frozen orders](https://docs.gmx.io/docs/api/contracts/architecture/#frozen-orders)
below.
This two-phase design prevents front-running: the user's intent is committed on-chain before oracle prices are included, so no actor can see the execution price before the request is recorded.
### Execution latency[](https://docs.gmx.io/docs/api/contracts/architecture/#execution-latency "Direct link to Execution latency")
The two-phase model introduces a brief delay between request and execution (typically a few seconds), during which the market price may move. The `acceptablePrice` parameter protects users — if the execution price exceeds their tolerance, the order is not fulfilled at that price.
### Simulations[](https://docs.gmx.io/docs/api/contracts/architecture/#simulations "Direct link to Simulations")
You can dry-run actions before keeper execution by calling the simulation functions on `ExchangeRouter` (for example, `simulateExecuteLatestOrder`, `simulateExecuteLatestDeposit`, `simulateExecuteLatestWithdrawal`, `simulateExecuteLatestShift`, `simulateExecuteLatestJitOrder`) and `GlvRouter` (for example, `simulateExecuteLatestGlvDeposit`, `simulateExecuteLatestGlvWithdrawal`). These are public router entry points intended for preflight checks, while the actual execution functions live on keeper-gated handlers. Simulations use the `withSimulatedOraclePrices` modifier and revert with `EndOfOracleSimulation` on success (not failure). See [Simulations](https://docs.gmx.io/docs/api/contracts/simulations/)
for details.
Keeper network[](https://docs.gmx.io/docs/api/contracts/architecture/#keeper-network "Direct link to Keeper network")
-----------------------------------------------------------------------------------------------------------------------
Three components work together to execute orders:
### Oracle keepers[](https://docs.gmx.io/docs/api/contracts/architecture/#oracle-keepers "Direct link to Oracle keepers")
Oracle keepers fetch prices from oracle providers. The primary provider is `ChainlinkDataStreamProvider`, which sources prices from [Chainlink Data Streams](https://docs.chain.link/data-streams)
. Additional providers include `EdgeDataStreamProvider` and `GmOracleProvider`. Each price report includes both a minimum price (`min`) and a maximum price (`max`), capturing the bid-ask spread. All prices use 30-decimal precision (`FLOAT_PRECISION = 10^30`) and represent the USD value of one full token unit, so conversions require no unit adjustment on the token amount:
fiatValue = tokenAmount * oraclePricetokenAmount = fiatValue / oraclePrice
The protocol validates oracle prices against Chainlink reference feeds using the `MAX_ORACLE_REF_PRICE_DEVIATION_FACTOR` parameter, rejecting any price that deviates beyond the configured threshold. Not all tokens have a `ChainlinkPriceFeedProvider` configured as a reference price source.
### Order keepers[](https://docs.gmx.io/docs/api/contracts/architecture/#order-keepers "Direct link to Order keepers")
Order keepers monitor the chain for pending requests (orders, deposits, withdrawals, shifts). When a request is detected, the keeper:
1. Fetches signed prices from the configured oracle providers.
2. Bundles the prices with the request key into an execution transaction.
3. Submits the transaction. The execution fee (paid by the user at request time) covers the keeper's gas cost.
If gas prices spike, the keeper may wait or the user can cancel the request after a cancellation period. Execution fees include a buffer to account for gas price volatility — any excess is refunded after execution.
### Frozen orders[](https://docs.gmx.io/docs/api/contracts/architecture/#frozen-orders "Direct link to Frozen orders")
If an order cannot be fulfilled at execution time (for example, the order size exceeds available liquidity, or position constraints aren't met), the order is frozen rather than cancelled. This prevents gaming where a user could create a limit order with size greater than available pool liquidity, wait for the trigger price to be hit, then deposit into the pool to allow execution at a favorable price.
Frozen orders can be retried by dedicated frozen order keepers when conditions improve. Users can also call `updateOrder` to unfreeze and modify the order, or cancel it entirely.
Integration considerations[](https://docs.gmx.io/docs/api/contracts/architecture/#integration-considerations "Direct link to Integration considerations")
-----------------------------------------------------------------------------------------------------------------------------------------------------------
### Contract versioning[](https://docs.gmx.io/docs/api/contracts/architecture/#contract-versioning "Direct link to Contract versioning")
Integrations must handle contract address changes during upgrades. When logic contracts are upgraded, new handler and router contracts are deployed at different addresses. During transition periods:
* Multiple handler versions may be active simultaneously.
* Callback contracts must whitelist both old and new handler addresses.
* Use configurable contract addresses rather than hardcoding them.
Subscribe to the channels in the [Updates and Support](https://docs.gmx.io/docs/api/updates-support/)
page for contract update notifications.
### ETH and WETH handling[](https://docs.gmx.io/docs/api/contracts/architecture/#eth-and-weth-handling "Direct link to ETH and WETH handling")
When the protocol needs to send ETH (for example, returning execution fee refunds), it first attempts a native ETH transfer with a configurable gas limit (`NATIVE_TOKEN_TRANSFER_GAS_LIMIT`). If the transfer fails (for example, the recipient contract lacks a `receive` function or doesn't have enough gas), the protocol wraps the ETH as WETH and sends that instead.
### First market deposit[](https://docs.gmx.io/docs/api/contracts/architecture/#first-market-deposit "Direct link to First market deposit")
The first deposit into a newly created market must set the receiver to `address(1)` and meet a minimum market token threshold (`MIN_MARKET_TOKENS_FOR_FIRST_DEPOSIT`). The minted market tokens are sent to `address(1)`, effectively locking them. This prevents manipulation of the market token price through rounding on the initial deposit. Subsequent deposits mint market tokens to the depositor normally.
### Token compatibility[](https://docs.gmx.io/docs/api/contracts/architecture/#token-compatibility "Direct link to Token compatibility")
The protocol is designed for standard ERC-20 tokens. The following token types are **not compatible**:
* **Rebasing tokens** — tokens that automatically adjust balances (for example, stETH in rebasing mode)
* **ERC-777 tokens** — tokens with transfer hooks that could enable reentrancy
* **Fee-on-transfer tokens** — tokens that deduct a fee on every transfer
* **Tokens with built-in burn mechanisms** — tokens where the supply decreases on transfer
### Token airdrops to GM holders[](https://docs.gmx.io/docs/api/contracts/architecture/#token-airdrops-to-gm-holders "Direct link to Token airdrops to GM holders")
If airdropping tokens to GM token holders, the airdrop must be claimable by contracts (not just EOAs). Integrating protocols that hold GM tokens on behalf of users need to be able to claim and distribute the airdrop to their users.
Known issues[](https://docs.gmx.io/docs/api/contracts/architecture/#known-issues "Direct link to Known issues")
-----------------------------------------------------------------------------------------------------------------
For the full list of known issues, token compatibility constraints, and integration considerations, see the dedicated [Known issues](https://docs.gmx.io/docs/api/contracts/known-issues/)
page.
Next steps[](https://docs.gmx.io/docs/api/contracts/architecture/#next-steps "Direct link to Next steps")
-----------------------------------------------------------------------------------------------------------
* [Contract addresses](https://docs.gmx.io/docs/api/contracts/addresses/)
— Deployment addresses for all supported chains.
* [ExchangeRouter](https://docs.gmx.io/docs/api/contracts/exchange-router/)
— Create orders, deposits, withdrawals, and shifts.
* [GlvRouter](https://docs.gmx.io/docs/api/contracts/glv-router/)
— Create GLV deposits and withdrawals.
* [Reader](https://docs.gmx.io/docs/api/contracts/reader/)
— Query market, position, and pricing data.
* [GLV Reader](https://docs.gmx.io/docs/api/contracts/glv-reader/)
— Query GLV vault data and pricing.
* [Advanced entry points](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/)
— Delegated subaccount trading, Gelato relay flows, and multichain routers.
* [Simulations](https://docs.gmx.io/docs/api/contracts/simulations/)
— Dry-run actions before submitting on-chain.
* [Events](https://docs.gmx.io/docs/api/contracts/events/)
— Monitor protocol activity through EventEmitter.
* [Contract structure](https://docs.gmx.io/docs/api/contracts/architecture/#contract-structure)
* [Role-based access control](https://docs.gmx.io/docs/api/contracts/architecture/#role-based-access-control)
* [EventEmitter](https://docs.gmx.io/docs/api/contracts/architecture/#eventemitter)
* [Execution model](https://docs.gmx.io/docs/api/contracts/architecture/#execution-model)
* [Execution latency](https://docs.gmx.io/docs/api/contracts/architecture/#execution-latency)
* [Simulations](https://docs.gmx.io/docs/api/contracts/architecture/#simulations)
* [Keeper network](https://docs.gmx.io/docs/api/contracts/architecture/#keeper-network)
* [Oracle keepers](https://docs.gmx.io/docs/api/contracts/architecture/#oracle-keepers)
* [Order keepers](https://docs.gmx.io/docs/api/contracts/architecture/#order-keepers)
* [Frozen orders](https://docs.gmx.io/docs/api/contracts/architecture/#frozen-orders)
* [Integration considerations](https://docs.gmx.io/docs/api/contracts/architecture/#integration-considerations)
* [Contract versioning](https://docs.gmx.io/docs/api/contracts/architecture/#contract-versioning)
* [ETH and WETH handling](https://docs.gmx.io/docs/api/contracts/architecture/#eth-and-weth-handling)
* [First market deposit](https://docs.gmx.io/docs/api/contracts/architecture/#first-market-deposit)
* [Token compatibility](https://docs.gmx.io/docs/api/contracts/architecture/#token-compatibility)
* [Token airdrops to GM holders](https://docs.gmx.io/docs/api/contracts/architecture/#token-airdrops-to-gm-holders)
* [Known issues](https://docs.gmx.io/docs/api/contracts/architecture/#known-issues)
* [Next steps](https://docs.gmx.io/docs/api/contracts/architecture/#next-steps)
---
# ExchangeRouter | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/contracts/exchange-router/#__docusaurus_skipToContent_fallback)
On this page
The `ExchangeRouter` contract exposes the main protocol functions for creating orders, deposits, and withdrawals.
For an overview of the contract architecture and execution model, see [Architecture](https://docs.gmx.io/docs/api/contracts/architecture/)
.
Creating an order[](https://docs.gmx.io/docs/api/contracts/exchange-router/#creating-an-order "Direct link to Creating an order")
-----------------------------------------------------------------------------------------------------------------------------------
To create a swap, increase-position, or decrease-position order, you must first transfer the required tokens to the `OrderVault`, then call `ExchangeRouter.createOrder` in the same transaction.
warning
The token transfer and the `ExchangeRouter.createOrder` call must occur in a single transaction. If they are separated, other users may withdraw the transferred tokens before your order is created.
See the [ExchangeRouter tests](https://github.com/gmx-io/gmx-synthetics/blob/updates/test/router/ExchangeRouter.ts)
for a complete example.
### ExchangeRouter.createOrder[](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangeroutercreateorder "Direct link to ExchangeRouter.createOrder")
function createOrder(IBaseOrderUtils.CreateOrderParams calldata params) returns (bytes32)
Use this to create swap, increase, or decrease orders through the router. For increase and swap orders, transfer the execution fee and any input collateral to the `OrderVault` in the same transaction, usually via `multicall`.
**Example (TypeScript / ethers):**
await usdc.approve(router.address, collateralAmount);await exchangeRouter.multicall( [ exchangeRouter.interface.encodeFunctionData("sendWnt", [orderVault.address, executionFee]), exchangeRouter.interface.encodeFunctionData("sendTokens", [usdc.address, orderVault.address, collateralAmount]), exchangeRouter.interface.encodeFunctionData("createOrder", [ { addresses: { receiver: trader.address, cancellationReceiver: trader.address, callbackContract: ethers.constants.AddressZero, uiFeeReceiver: ethers.constants.AddressZero, market: marketToken, initialCollateralToken: usdc.address, swapPath: [], }, numbers: { sizeDeltaUsd, initialCollateralDeltaAmount: collateralAmount, triggerPrice: 0, acceptablePrice, executionFee, callbackGasLimit: 0, minOutputAmount: 0, validFromTime: 0, }, orderType: OrderType.MarketIncrease, decreasePositionSwapType: DecreasePositionSwapType.NoSwap, isLong: true, shouldUnwrapNativeToken: false, autoCancel: false, referralCode: ethers.constants.HashZero, dataList: [], }, ]), ], { value: executionFee });
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `params` | `IBaseOrderUtils.CreateOrderParams` | Struct containing order configuration |
### CreateOrderParams[](https://docs.gmx.io/docs/api/contracts/exchange-router/#createorderparams "Direct link to CreateOrderParams")
The order struct is split into address fields, numeric fields, and a small set of enums and flags.
| Field | Description |
| --- | --- |
| `addresses` | Group of address fields listed in [CreateOrderParamsAddresses](https://docs.gmx.io/docs/api/contracts/exchange-router/#createorderparamsaddresses)
. |
| `numbers` | Group of numeric fields listed in [CreateOrderParamsNumbers](https://docs.gmx.io/docs/api/contracts/exchange-router/#createorderparamsnumbers)
. |
| `orderType` | Order type enum listed in [OrderType](https://docs.gmx.io/docs/api/contracts/exchange-router/#ordertype)
. |
| `decreasePositionSwapType` | Swap behavior for decrease orders listed in [DecreasePositionSwapType](https://docs.gmx.io/docs/api/contracts/exchange-router/#decreasepositionswaptype)
. |
| `isLong` | `true` for a long position, `false` for a short position. |
| `shouldUnwrapNativeToken` | Whether to unwrap the native token on output. For example, if the output token is WETH and this is `true`, the contract converts WETH to ETH before sending. |
| `autoCancel` | For `LimitDecrease` and `StopLossDecrease` orders, whether the order is cancelled automatically when the position closes. Ignored for all other order types. |
| `referralCode` | Referral code to set for the trader alongside order creation. If the trader already has a referral code set, this parameter has no effect. |
| `dataList` | Array of additional `bytes32` data. Pass an empty array if no extra data is needed. |
### CreateOrderParamsAddresses[](https://docs.gmx.io/docs/api/contracts/exchange-router/#createorderparamsaddresses "Direct link to CreateOrderParamsAddresses")
| Field | Description |
| --- | --- |
| `receiver` | Address that receives any output amounts. |
| `cancellationReceiver` | If the order is cancelled, collateral and the network fee gas are sent to this address if it is not the zero address. |
| `callbackContract` | Contract to call on order execution or cancellation. |
| `uiFeeReceiver` | Address that receives the UI fee. |
| `market` | Market to trade in. |
| `initialCollateralToken` | Initial collateral token transferred into the contract. |
| `swapPath` | Array of market addresses to swap `initialCollateralToken` through. For increase and swap orders, the token is swapped before entering the position. For decrease orders, the output is swapped through these markets. |
### CreateOrderParamsNumbers[](https://docs.gmx.io/docs/api/contracts/exchange-router/#createorderparamsnumbers "Direct link to CreateOrderParamsNumbers")
| Field | Description |
| --- | --- |
| `sizeDeltaUsd` | Position size to increase or decrease. |
| `initialCollateralDeltaAmount` | Amount of input collateral sent to the `OrderVault` for swap and increase orders, or collateral amount to withdraw for decrease orders. |
| `triggerPrice` | Trigger price for `LimitIncrease`, `LimitDecrease`, and `StopLossDecrease` orders. The keeper attempts execution when price reaches this level. |
| `acceptablePrice` | Price at which the order can execute. For market orders, the order is cancelled if it cannot execute at this price. For limit and stop-loss orders, execution is skipped if the trigger price is reached but the acceptable price cannot be filled. |
| `executionFee` | Amount of native token (for example, ETH on Arbitrum) included as the execution fee. This is the maximum fee keepers can use to execute the order. Any excess is returned to the order account. See [Execution Fee](https://docs.gmx.io/docs/api/contracts/fees/#execution-fee)
for details. |
| `callbackGasLimit` | Gas limit passed to the callback contract on order execution or cancellation. |
| `minOutputAmount` | For swap orders, the minimum token output amount. For increase orders, the minimum token amount after `initialCollateralDeltaAmount` is swapped through `swapPath`. For decrease orders, this is the minimum USD value, because decrease orders can produce two output tokens: the profit token and the withdrawn collateral token. |
| `validFromTime` | Timestamp from which the order becomes valid for execution. The keeper skips the order until `block.timestamp` reaches this value. Pass `0` for immediate validity. |
### OrderType[](https://docs.gmx.io/docs/api/contracts/exchange-router/#ordertype "Direct link to OrderType")
| Value | Description |
| --- | --- |
| `MarketSwap` | Execute a swap at the current market price. |
| `LimitSwap` | Execute a swap when `minOutputAmount` can be filled. |
| `MarketIncrease` | Open or increase a long or short position at market price. |
| `LimitIncrease` | Open or increase a position when the trigger price is reached. |
| `MarketDecrease` | Close or reduce a position at market price. |
| `LimitDecrease` | Close or reduce a position when the trigger price is reached. |
| `StopLossDecrease` | Close or reduce a position when price falls to the trigger level. |
| `Liquidation` | Forced position closure triggered by the protocol when margin requirements are no longer met. Not user-callable. |
| `StopIncrease` | Open or increase a position when the stop price is reached. |
### DecreasePositionSwapType[](https://docs.gmx.io/docs/api/contracts/exchange-router/#decreasepositionswaptype "Direct link to DecreasePositionSwapType")
| Value | Description |
| --- | --- |
| `NoSwap` | No swap is performed. |
| `SwapPnlTokenToCollateralToken` | The profit token is swapped to the collateral token, if possible. |
| `SwapCollateralTokenToPnlToken` | The withdrawn collateral is swapped to the profit token, if possible. |
Creating a deposit[](https://docs.gmx.io/docs/api/contracts/exchange-router/#creating-a-deposit "Direct link to Creating a deposit")
--------------------------------------------------------------------------------------------------------------------------------------
To create a deposit, you must first transfer tokens to the `DepositVault`, then call `ExchangeRouter.createDeposit` in the same transaction.
warning
The token transfer and the `ExchangeRouter.createDeposit` call must occur in a single transaction. If they are separated, other users may withdraw the transferred tokens before your deposit is created.
If this transaction reverts, the token transfer also reverts, so no funds remain in the `DepositVault`. If the deposit request is created successfully and is later cancelled, the initial deposit tokens are returned to the account that created the deposit, and any unused execution fee is refunded separately.
See the [ExchangeRouter tests](https://github.com/gmx-io/gmx-synthetics/blob/updates/test/router/ExchangeRouter.ts)
for a complete example.
### ExchangeRouter.createDeposit[](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangeroutercreatedeposit "Direct link to ExchangeRouter.createDeposit")
function createDeposit(IDepositUtils.CreateDepositParams calldata params) returns (bytes32)
Use this to add liquidity to a GM market. Transfer the execution fee and any long / short input tokens to the `DepositVault` in the same transaction, usually via `multicall`.
**Example (TypeScript / ethers):**
await usdc.approve(router.address, shortTokenAmount);await exchangeRouter.multicall( [ exchangeRouter.interface.encodeFunctionData("sendWnt", [depositVault.address, executionFee]), exchangeRouter.interface.encodeFunctionData("sendTokens", [usdc.address, depositVault.address, shortTokenAmount]), exchangeRouter.interface.encodeFunctionData("createDeposit", [ { addresses: { receiver: liquidityProvider.address, callbackContract: ethers.constants.AddressZero, uiFeeReceiver: ethers.constants.AddressZero, market: marketToken, initialLongToken: longToken, initialShortToken: usdc.address, longTokenSwapPath: [], shortTokenSwapPath: [], }, minMarketTokens, shouldUnwrapNativeToken: false, executionFee, callbackGasLimit: 0, dataList: [], }, ]), ], { value: executionFee });
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `params` | `IDepositUtils.CreateDepositParams` | Struct containing deposit configuration |
### CreateDepositParams[](https://docs.gmx.io/docs/api/contracts/exchange-router/#createdepositparams "Direct link to CreateDepositParams")
| Field | Description |
| --- | --- |
| `receiver` | Address that receives the GM tokens. |
| `callbackContract` | Contract to call on deposit execution or cancellation. |
| `uiFeeReceiver` | Address that receives the UI fee. |
| `market` | Market to deposit into. |
| `initialLongToken` | Long token transferred into the contract. |
| `initialShortToken` | Short token transferred into the contract. |
| `longTokenSwapPath` | Array of market addresses to swap `initialLongToken` through before depositing. |
| `shortTokenSwapPath` | Array of market addresses to swap `initialShortToken` through before depositing. |
| `minMarketTokens` | Minimum acceptable amount of GM tokens to receive. |
| `shouldUnwrapNativeToken` | Whether to unwrap the native token if the deposit is cancelled. For example, if `initialLongToken` is WETH and this is `true`, the contract converts WETH to ETH before refunding. |
| `executionFee` | Amount of native token (for example, ETH on Arbitrum) included as the execution fee. This is the maximum fee keepers can use to execute the deposit. Any excess is returned to the deposit account. See [Execution Fee](https://docs.gmx.io/docs/api/contracts/fees/#execution-fee)
for details. |
| `callbackGasLimit` | Gas limit passed to the callback contract on deposit execution or cancellation. |
| `dataList` | Array of additional `bytes32` data. Pass an empty array if no extra data is needed. |
Creating a withdrawal[](https://docs.gmx.io/docs/api/contracts/exchange-router/#creating-a-withdrawal "Direct link to Creating a withdrawal")
-----------------------------------------------------------------------------------------------------------------------------------------------
To create a withdrawal through `ExchangeRouter`, send the GM market tokens and execution fee to the `WithdrawalVault` and call `ExchangeRouter.createWithdrawal` in the same transaction, usually via `multicall`.
### ExchangeRouter.createWithdrawal[](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangeroutercreatewithdrawal "Direct link to ExchangeRouter.createWithdrawal")
function createWithdrawal(IWithdrawalUtils.CreateWithdrawalParams calldata params) returns (bytes32)
Use this to create an asynchronous withdrawal request. Transfer the GM market tokens and execution fee to the `WithdrawalVault` in the same transaction, usually via `multicall`. The withdrawal size is determined by the GM market token amount sent to `WithdrawalVault` with `sendTokens`.
**Example (TypeScript / ethers):**
await marketToken.approve(router.address, marketTokenAmount);await exchangeRouter.multicall( [ exchangeRouter.interface.encodeFunctionData("sendWnt", [withdrawalVault.address, executionFee]), exchangeRouter.interface.encodeFunctionData("sendTokens", [ marketToken.address, withdrawalVault.address, marketTokenAmount, ]), exchangeRouter.interface.encodeFunctionData("createWithdrawal", [ { addresses: { receiver: trader.address, callbackContract: ethers.constants.AddressZero, uiFeeReceiver: ethers.constants.AddressZero, market: marketToken.address, longTokenSwapPath: [], shortTokenSwapPath: [], }, minLongTokenAmount, minShortTokenAmount, shouldUnwrapNativeToken: false, executionFee, callbackGasLimit: 0, dataList: [], }, ]), ], { value: executionFee });
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `params` | `IWithdrawalUtils.CreateWithdrawalParams` | Struct containing withdrawal configuration |
### CreateWithdrawalParams[](https://docs.gmx.io/docs/api/contracts/exchange-router/#createwithdrawalparams "Direct link to CreateWithdrawalParams")
The GM market token amount to withdraw is not part of `CreateWithdrawalParams`. It is set by the amount sent to `WithdrawalVault` in the preceding `sendTokens` call.
| Field | Description |
| --- | --- |
| `receiver` | Address that receives the withdrawn tokens. |
| `callbackContract` | Contract to call on withdrawal execution or cancellation. |
| `uiFeeReceiver` | Address that receives the UI fee. |
| `market` | Market to withdraw from. |
| `longTokenSwapPath` | Array of market addresses to swap the withdrawn long token through. |
| `shortTokenSwapPath` | Array of market addresses to swap the withdrawn short token through. |
| `minLongTokenAmount` | Minimum output amount of long token after swapping through `longTokenSwapPath`. For example, if WETH is swapped to BTC, this specifies the minimum BTC amount. |
| `minShortTokenAmount` | Minimum output amount of short token after swapping through `shortTokenSwapPath`. |
| `shouldUnwrapNativeToken` | Whether to unwrap the native token on output. For example, if the output token is WETH and this is `true`, the contract converts WETH to ETH before sending. |
| `executionFee` | Amount of native token (for example, ETH on Arbitrum) included as the execution fee. This is the maximum fee keepers can use to execute the withdrawal. Any excess is returned to the withdrawal account. See [Execution Fee](https://docs.gmx.io/docs/api/contracts/fees/#execution-fee)
for details. |
| `callbackGasLimit` | Gas limit passed to the callback contract on withdrawal execution or cancellation. |
| `dataList` | Array of additional `bytes32` data. Pass an empty array if no extra data is needed. |
Creating an atomic withdrawal[](https://docs.gmx.io/docs/api/contracts/exchange-router/#creating-an-atomic-withdrawal "Direct link to Creating an atomic withdrawal")
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
An atomic withdrawal executes synchronously without waiting for a keeper. It uses on-chain Chainlink price feeds rather than off-chain oracle data, so only tokens with a registered `ChainlinkPriceFeedProvider` are supported.
### ExchangeRouter.executeAtomicWithdrawal[](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangerouterexecuteatomicwithdrawal "Direct link to ExchangeRouter.executeAtomicWithdrawal")
function executeAtomicWithdrawal( IWithdrawalUtils.CreateWithdrawalParams calldata params, OracleUtils.SetPricesParams calldata oracleParams)
Use this to withdraw synchronously using on-chain Chainlink prices instead of the normal keeper flow. Swaps are not supported, so both swap paths must be empty. As with standard withdrawals, the withdrawal size is determined by the GM market token amount sent to `WithdrawalVault`.
**Example (TypeScript / ethers):**
await marketToken.approve(router.address, marketTokenAmount);await exchangeRouter.multicall( [ exchangeRouter.interface.encodeFunctionData("sendWnt", [withdrawalVault.address, executionFee]), exchangeRouter.interface.encodeFunctionData("sendTokens", [ marketToken.address, withdrawalVault.address, marketTokenAmount, ]), exchangeRouter.interface.encodeFunctionData("executeAtomicWithdrawal", [ { addresses: { receiver: trader.address, callbackContract: ethers.constants.AddressZero, uiFeeReceiver: ethers.constants.AddressZero, market: marketToken.address, longTokenSwapPath: [], shortTokenSwapPath: [], }, minLongTokenAmount, minShortTokenAmount, shouldUnwrapNativeToken: false, executionFee, callbackGasLimit: 0, dataList: [], }, { tokens: [indexToken.address, longToken.address, shortToken.address], providers: [ chainlinkPriceFeedProvider.address, chainlinkPriceFeedProvider.address, chainlinkPriceFeedProvider.address, ], data: ["0x", "0x", "0x"], }, ]), ], { value: executionFee });
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `params` | `IWithdrawalUtils.CreateWithdrawalParams` | Withdrawal configuration, using the same fields as a standard withdrawal with the constraints listed in [CreateWithdrawalParams for atomic withdrawal](https://docs.gmx.io/docs/api/contracts/exchange-router/#createwithdrawalparams-for-atomic-withdrawal)
. |
| `oracleParams` | `OracleUtils.SetPricesParams` | Oracle price inputs required for atomic execution. |
### CreateWithdrawalParams for atomic withdrawal[](https://docs.gmx.io/docs/api/contracts/exchange-router/#createwithdrawalparams-for-atomic-withdrawal "Direct link to CreateWithdrawalParams for atomic withdrawal")
| Field | Description |
| --- | --- |
| `longTokenSwapPath` | Must be empty. Swaps are not supported for atomic withdrawals. |
| `shortTokenSwapPath` | Must be empty. Swaps are not supported for atomic withdrawals. |
| All other fields | Same as [CreateWithdrawalParams](https://docs.gmx.io/docs/api/contracts/exchange-router/#createwithdrawalparams)
. |
### OracleUtils.SetPricesParams[](https://docs.gmx.io/docs/api/contracts/exchange-router/#oracleutilssetpricesparams "Direct link to OracleUtils.SetPricesParams")
| Field | Description |
| --- | --- |
| `tokens` | Array of token addresses: the index token, long token, and short token of the market. |
| `providers` | Array of price providers for each token. Use the `ChainlinkPriceFeedProvider` address found in the `deployments` folder. To check whether a token is supported, call `dataStore.getAddress(Keys.priceFeedKey(token))` and verify the result is not the zero address. |
| `data` | Array of provider data. Pass an array of `0x` empty bytes for Chainlink feeds. |
Creating a shift[](https://docs.gmx.io/docs/api/contracts/exchange-router/#creating-a-shift "Direct link to Creating a shift")
--------------------------------------------------------------------------------------------------------------------------------
A shift moves liquidity from one GM market to another in a single request. Instead of withdrawing from the source market and depositing into the destination market separately, you can use `createShift` to do both atomically. Transfer the GM market tokens from the source market and the execution fee to the `ShiftVault` before calling `ExchangeRouter.createShift` in the same transaction.
warning
The token transfer and the `ExchangeRouter.createShift` call must occur in a single transaction. If they are separated, other users may withdraw the transferred tokens before your shift is created.
### ExchangeRouter.createShift[](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangeroutercreateshift "Direct link to ExchangeRouter.createShift")
function createShift(IShiftUtils.CreateShiftParams calldata params) returns (bytes32)
Use this to move GM liquidity from one market to another. Transfer the source market's GM tokens and the execution fee to the `ShiftVault` in the same transaction, usually via `multicall`. The shift amount is determined by the GM token amount sent to `ShiftVault` with `sendTokens`.
**Example (TypeScript / ethers):**
await sourceMarketToken.approve(router.address, marketTokenAmount);await exchangeRouter.multicall( [ exchangeRouter.interface.encodeFunctionData("sendWnt", [shiftVault.address, executionFee]), exchangeRouter.interface.encodeFunctionData("sendTokens", [ sourceMarketToken.address, shiftVault.address, marketTokenAmount, ]), exchangeRouter.interface.encodeFunctionData("createShift", [ { addresses: { receiver: account.address, callbackContract: ethers.constants.AddressZero, uiFeeReceiver: ethers.constants.AddressZero, fromMarket: sourceMarketToken.address, toMarket: destinationMarketToken.address, }, minMarketTokens, executionFee, callbackGasLimit: 0, dataList: [], }, ]), ], { value: executionFee });
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `params` | `IShiftUtils.CreateShiftParams` | Struct containing shift configuration |
**Returns:** `bytes32` -- the unique key identifying the shift request.
### CreateShiftParams[](https://docs.gmx.io/docs/api/contracts/exchange-router/#createshiftparams "Direct link to CreateShiftParams")
The GM market token amount to shift is not part of `CreateShiftParams`. It is set by the amount sent to `ShiftVault` in the preceding `sendTokens` call.
| Field | Description |
| --- | --- |
| `receiver` | Address that receives the destination market's GM tokens. |
| `callbackContract` | Contract to call on shift execution or cancellation. |
| `uiFeeReceiver` | Address that receives the UI fee. |
| `fromMarket` | Source GM market to withdraw liquidity from. |
| `toMarket` | Destination GM market to deposit liquidity into. |
| `minMarketTokens` | Minimum acceptable amount of destination GM tokens to receive. |
| `executionFee` | Amount of native token (for example, ETH on Arbitrum) included as the execution fee. This is the maximum fee keepers can use to execute the shift. Any excess is returned to the shift account. See [Execution Fee](https://docs.gmx.io/docs/api/contracts/fees/#execution-fee)
for details. |
| `callbackGasLimit` | Gas limit passed to the callback contract on shift execution or cancellation. |
| `dataList` | Array of additional `bytes32` data. Pass an empty array if no extra data is needed. |
Updating an order[](https://docs.gmx.io/docs/api/contracts/exchange-router/#updating-an-order "Direct link to Updating an order")
-----------------------------------------------------------------------------------------------------------------------------------
You can modify the parameters of an existing pending order by calling `updateOrder`. Only the order's creator can update it, and market orders can't be updated. Any additional WNT transferred to the contract during the update is added to the order's execution fee.
### ExchangeRouter.updateOrder[](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangerouterupdateorder "Direct link to ExchangeRouter.updateOrder")
function updateOrder( bytes32 key, uint256 sizeDeltaUsd, uint256 acceptablePrice, uint256 triggerPrice, uint256 minOutputAmount, uint256 validFromTime, bool autoCancel)
Use this to change the parameters of a pending limit or trigger order. The order is also unfrozen if it was previously frozen due to an execution error.
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `key` | `bytes32` | Unique key of the order to update, returned by `createOrder`. |
| `sizeDeltaUsd` | `uint256` | New position size delta in USD. |
| `acceptablePrice` | `uint256` | New acceptable execution price. For long increase orders, the order is cancelled if the execution price is greater than `acceptablePrice`. For short increase orders, the order is cancelled if the execution price is less than `acceptablePrice`. |
| `triggerPrice` | `uint256` | New trigger price for limit and stop-loss orders. |
| `minOutputAmount` | `uint256` | New minimum output amount for swap orders or minimum USD value for decrease orders. |
| `validFromTime` | `uint256` | New timestamp from which the order becomes valid. Pass `0` for immediate validity. |
| `autoCancel` | `bool` | Whether to automatically cancel the order when the associated position closes. Only applies to `LimitDecrease` and `StopLossDecrease` orders. |
Cancelling requests[](https://docs.gmx.io/docs/api/contracts/exchange-router/#cancelling-requests "Direct link to Cancelling requests")
-----------------------------------------------------------------------------------------------------------------------------------------
You can cancel pending orders, deposits, withdrawals, and shifts that you created. When a request is cancelled, the deposited funds and any unused execution fee are returned to the creator. Cancellation is subject to a delay period -- the request must have been pending for at least the configured `requestExpirationTime` before it can be cancelled. If you attempt to cancel too early, the transaction reverts with `RequestNotYetCancellable`.
### ExchangeRouter.cancelOrder[](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangeroutercancelorder "Direct link to ExchangeRouter.cancelOrder")
function cancelOrder(bytes32 key)
Cancels a pending order. Only the order's creator can cancel it.
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `key` | `bytes32` | Unique key of the order to cancel, returned by `createOrder`. |
### ExchangeRouter.cancelDeposit[](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangeroutercanceldeposit "Direct link to ExchangeRouter.cancelDeposit")
function cancelDeposit(bytes32 key)
Cancels a pending deposit. Only the deposit's creator can cancel it. The initial deposit tokens are returned to the creator's account.
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `key` | `bytes32` | Unique key of the deposit to cancel, returned by `createDeposit`. |
### ExchangeRouter.cancelWithdrawal[](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangeroutercancelwithdrawal "Direct link to ExchangeRouter.cancelWithdrawal")
function cancelWithdrawal(bytes32 key)
Cancels a pending withdrawal. Only the withdrawal's creator can cancel it. The GM market tokens are returned to the creator's account.
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `key` | `bytes32` | Unique key of the withdrawal to cancel, returned by `createWithdrawal`. |
### ExchangeRouter.cancelShift[](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangeroutercancelshift "Direct link to ExchangeRouter.cancelShift")
function cancelShift(bytes32 key)
Cancels a pending shift. Only the shift's creator can cancel it. The source market's GM tokens are returned to the creator's account.
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `key` | `bytes32` | Unique key of the shift to cancel, returned by `createShift`. |
Setting a callback contract[](https://docs.gmx.io/docs/api/contracts/exchange-router/#setting-a-callback-contract "Direct link to Setting a callback contract")
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
You can set a persistent callback contract for a specific market. The protocol uses this saved callback contract for liquidations and auto-deleveraging (ADL), where no user-initiated order exists to specify a callback. This lets your contract receive notifications when your position is liquidated or reduced by ADL.
### ExchangeRouter.setSavedCallbackContract[](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangeroutersetsavedcallbackcontract "Direct link to ExchangeRouter.setSavedCallbackContract")
function setSavedCallbackContract(address market, address callbackContract)
Saves a callback contract for the caller's account in the given market. The protocol calls this contract during liquidation and ADL events for that account and market.
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `market` | `address` | Market address to associate the callback contract with. |
| `callbackContract` | `address` | Contract address to call on liquidation or ADL. Pass the zero address to remove it. |
Claiming fees and rewards[](https://docs.gmx.io/docs/api/contracts/exchange-router/#claiming-fees-and-rewards "Direct link to Claiming fees and rewards")
-----------------------------------------------------------------------------------------------------------------------------------------------------------
These functions let you claim accumulated fees and rewards across multiple markets in a single transaction. The `markets` and `tokens` arrays must have the same length -- each index pairs a market with the token to claim.
### ExchangeRouter.claimFundingFees[](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangerouterclaimfundingfees "Direct link to ExchangeRouter.claimFundingFees")
function claimFundingFees( address[] memory markets, address[] memory tokens, address receiver) returns (uint256[] memory)
Claims accumulated positive funding fees for the caller across the specified market-token pairs. Funding fees accrue when you hold a position on the less-crowded side of a market.
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `markets` | `address[]` | Array of market addresses to claim funding fees from. |
| `tokens` | `address[]` | Array of token addresses, one per market, specifying which token to claim. |
| `receiver` | `address` | Address that receives the claimed funding fees. |
**Returns:** `uint256[]` -- the amount claimed for each market-token pair.
### ExchangeRouter.claimCollateral[](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangerouterclaimcollateral "Direct link to ExchangeRouter.claimCollateral")
function claimCollateral( address[] memory markets, address[] memory tokens, uint256[] memory timeKeys, address receiver) returns (uint256[] memory)
Claims collateral that was capped due to negative price impact. When a position's price impact is capped, the excess amount is stored and becomes claimable over time as the price impact factor recovers. Each claim is keyed by the timestamp when the capped amount was recorded.
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `markets` | `address[]` | Array of market addresses to claim collateral from. |
| `tokens` | `address[]` | Array of token addresses, one per market, specifying which token to claim. |
| `timeKeys` | `uint256[]` | Array of timestamps identifying the specific capped collateral entries to claim. |
| `receiver` | `address` | Address that receives the claimed collateral. |
**Returns:** `uint256[]` -- the amount claimed for each entry.
### ExchangeRouter.claimAffiliateRewards[](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangerouterclaimaffiliaterewards "Direct link to ExchangeRouter.claimAffiliateRewards")
function claimAffiliateRewards( address[] memory markets, address[] memory tokens, address receiver) returns (uint256[] memory)
Claims accumulated affiliate (referral) rewards for the caller across the specified market-token pairs. Rewards accrue when traders you referred generate trading fees.
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `markets` | `address[]` | Array of market addresses to claim affiliate rewards from. |
| `tokens` | `address[]` | Array of token addresses, one per market, specifying which token to claim. |
| `receiver` | `address` | Address that receives the claimed affiliate rewards. |
**Returns:** `uint256[]` -- the amount claimed for each market-token pair.
UI fee configuration[](https://docs.gmx.io/docs/api/contracts/exchange-router/#ui-fee-configuration "Direct link to UI fee configuration")
--------------------------------------------------------------------------------------------------------------------------------------------
These functions let an integration configure its UI fee factor and claim accumulated UI fees.
### ExchangeRouter.setUiFeeFactor[](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangeroutersetuifeefactor "Direct link to ExchangeRouter.setUiFeeFactor")
function setUiFeeFactor(uint256 uiFeeFactor)
Sets the UI fee factor for the caller's account. The factor is stored in the protocol configuration and is applied when users submit actions with your address as `uiFeeReceiver`.
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `uiFeeFactor` | `uint256` | UI fee percentage in 30-decimal precision. The value must not exceed `MAX_UI_FEE_FACTOR`. |
### ExchangeRouter.claimUiFees[](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangerouterclaimuifees "Direct link to ExchangeRouter.claimUiFees")
function claimUiFees( address[] memory markets, address[] memory tokens, address receiver) returns (uint256[] memory)
Claims accumulated UI fees for the caller across the specified market-token pairs. The caller address (`msg.sender`) is treated as the `uiFeeReceiver` whose balance is being claimed.
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `markets` | `address[]` | Array of market addresses to claim UI fees from. |
| `tokens` | `address[]` | Array of token addresses, one per market, specifying which token to claim. |
| `receiver` | `address` | Address that receives the claimed UI fees. |
**Returns:** `uint256[]` -- the amount claimed for each market-token pair.
* [Creating an order](https://docs.gmx.io/docs/api/contracts/exchange-router/#creating-an-order)
* [ExchangeRouter.createOrder](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangeroutercreateorder)
* [CreateOrderParams](https://docs.gmx.io/docs/api/contracts/exchange-router/#createorderparams)
* [CreateOrderParamsAddresses](https://docs.gmx.io/docs/api/contracts/exchange-router/#createorderparamsaddresses)
* [CreateOrderParamsNumbers](https://docs.gmx.io/docs/api/contracts/exchange-router/#createorderparamsnumbers)
* [OrderType](https://docs.gmx.io/docs/api/contracts/exchange-router/#ordertype)
* [DecreasePositionSwapType](https://docs.gmx.io/docs/api/contracts/exchange-router/#decreasepositionswaptype)
* [Creating a deposit](https://docs.gmx.io/docs/api/contracts/exchange-router/#creating-a-deposit)
* [ExchangeRouter.createDeposit](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangeroutercreatedeposit)
* [CreateDepositParams](https://docs.gmx.io/docs/api/contracts/exchange-router/#createdepositparams)
* [Creating a withdrawal](https://docs.gmx.io/docs/api/contracts/exchange-router/#creating-a-withdrawal)
* [ExchangeRouter.createWithdrawal](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangeroutercreatewithdrawal)
* [CreateWithdrawalParams](https://docs.gmx.io/docs/api/contracts/exchange-router/#createwithdrawalparams)
* [Creating an atomic withdrawal](https://docs.gmx.io/docs/api/contracts/exchange-router/#creating-an-atomic-withdrawal)
* [ExchangeRouter.executeAtomicWithdrawal](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangerouterexecuteatomicwithdrawal)
* [CreateWithdrawalParams for atomic withdrawal](https://docs.gmx.io/docs/api/contracts/exchange-router/#createwithdrawalparams-for-atomic-withdrawal)
* [OracleUtils.SetPricesParams](https://docs.gmx.io/docs/api/contracts/exchange-router/#oracleutilssetpricesparams)
* [Creating a shift](https://docs.gmx.io/docs/api/contracts/exchange-router/#creating-a-shift)
* [ExchangeRouter.createShift](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangeroutercreateshift)
* [CreateShiftParams](https://docs.gmx.io/docs/api/contracts/exchange-router/#createshiftparams)
* [Updating an order](https://docs.gmx.io/docs/api/contracts/exchange-router/#updating-an-order)
* [ExchangeRouter.updateOrder](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangerouterupdateorder)
* [Cancelling requests](https://docs.gmx.io/docs/api/contracts/exchange-router/#cancelling-requests)
* [ExchangeRouter.cancelOrder](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangeroutercancelorder)
* [ExchangeRouter.cancelDeposit](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangeroutercanceldeposit)
* [ExchangeRouter.cancelWithdrawal](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangeroutercancelwithdrawal)
* [ExchangeRouter.cancelShift](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangeroutercancelshift)
* [Setting a callback contract](https://docs.gmx.io/docs/api/contracts/exchange-router/#setting-a-callback-contract)
* [ExchangeRouter.setSavedCallbackContract](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangeroutersetsavedcallbackcontract)
* [Claiming fees and rewards](https://docs.gmx.io/docs/api/contracts/exchange-router/#claiming-fees-and-rewards)
* [ExchangeRouter.claimFundingFees](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangerouterclaimfundingfees)
* [ExchangeRouter.claimCollateral](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangerouterclaimcollateral)
* [ExchangeRouter.claimAffiliateRewards](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangerouterclaimaffiliaterewards)
* [UI fee configuration](https://docs.gmx.io/docs/api/contracts/exchange-router/#ui-fee-configuration)
* [ExchangeRouter.setUiFeeFactor](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangeroutersetuifeefactor)
* [ExchangeRouter.claimUiFees](https://docs.gmx.io/docs/api/contracts/exchange-router/#exchangerouterclaimuifees)
---
# Frontend Integration | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/frontend-integration/#__docusaurus_skipToContent_fallback)
On this page
The GMX protocol consists of smart contracts deployed on blockchains.
Users can interact directly with the smart contracts using blockchain explorers such as [Arbiscan](https://arbiscan.io/)
and [SnowTrace](https://snowtrace.io/)
.
The [GMX frontend repository](https://github.com/gmx-io/gmx-interface)
provides code to simplify contract interaction and to view protocol information and can be deployed by any community member.
A deployed instance of the GMX frontend is available at [https://app.gmx.io/](https://app.gmx.io/)
.
A backup instance of the GMX frontend is available at [https://gmxalt.io/](https://gmxalt.io/)
.
Testnet frontend[](https://docs.gmx.io/docs/api/frontend-integration/#testnet-frontend "Direct link to Testnet frontend")
---------------------------------------------------------------------------------------------------------------------------
A testnet GMX frontend is available at [https://test.gmx-interface.pages.dev/](https://test.gmx-interface.pages.dev/)
. Use it to test against testnet networks (Arbitrum Sepolia and Avalanche Fuji) and to access debug mode tooling.
Running a frontend[](https://docs.gmx.io/docs/api/frontend-integration/#running-a-frontend "Direct link to Running a frontend")
---------------------------------------------------------------------------------------------------------------------------------
To run the GMX frontend locally, follow the instructions in the [GMX frontend repository](https://github.com/gmx-io/gmx-interface)
. You can also deploy it using a static hosting service such as Vercel, Netlify, or Cloudflare Pages.
GMX orders support a [UI fee](https://docs.gmx.io/docs/api/contracts/fees/#ui-fee)
: you pass in a receiving address, and it receives fees when the order executes. These fees are charged on top of the base fees.
The GMX interface lets you configure a UI fee receiver and custom RPC URLs by adding environment variables to the `.env` file in the project root.
### UI fee receiver[](https://docs.gmx.io/docs/api/frontend-integration/#ui-fee-receiver "Direct link to UI fee receiver")
To configure the UI fee receiver, add `VITE_APP_UI_FEE_RECEIVER` to your `.env` file. Set it to the wallet address that receives [UI fees](https://docs.gmx.io/docs/api/contracts/fees/#ui-fee)
.
VITE_APP_UI_FEE_RECEIVER=0xYourReceiverAddressHere
The interface only sets `uiFeeReceiver` for orders. To set it for deposits and withdrawals, you must add custom code.
### Custom RPC URLs[](https://docs.gmx.io/docs/api/frontend-integration/#custom-rpc-urls "Direct link to Custom RPC URLs")
To override the default RPC endpoints for Arbitrum, Avalanche, or Botanix, add the corresponding variable to your `.env` file. Each variable takes a JSON array of RPC URLs, which the interface uses as fallback endpoints.
VITE_APP_ARBITRUM_RPC_URLS=["https://arb-rpc-url-1", "https://arb-rpc-url-2"]VITE_APP_AVALANCHE_RPC_URLS=["https://avax-rpc-url-1", "https://avax-rpc-url-2"]VITE_APP_BOTANIX_RPC_URLS=["https://botanix-rpc-url-1", "https://botanix-rpc-url-2"]
* [Testnet frontend](https://docs.gmx.io/docs/api/frontend-integration/#testnet-frontend)
* [Running a frontend](https://docs.gmx.io/docs/api/frontend-integration/#running-a-frontend)
* [UI fee receiver](https://docs.gmx.io/docs/api/frontend-integration/#ui-fee-receiver)
* [Custom RPC URLs](https://docs.gmx.io/docs/api/frontend-integration/#custom-rpc-urls)
---
# GlvRouter | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/contracts/glv-router/#__docusaurus_skipToContent_fallback)
On this page
The `GlvRouter` contract is the main entry point for creating and cancelling GLV (GMX Liquidity Vault) deposits and withdrawals. It works similarly to the [ExchangeRouter](https://docs.gmx.io/docs/api/contracts/exchange-router/)
but targets GLV vaults instead of individual GM markets.
For an overview of the contract architecture and execution model, see [Architecture](https://docs.gmx.io/docs/api/contracts/architecture/)
.
Creating a GLV deposit[](https://docs.gmx.io/docs/api/contracts/glv-router/#creating-a-glv-deposit "Direct link to Creating a GLV deposit")
---------------------------------------------------------------------------------------------------------------------------------------------
To create a GLV deposit, you must first transfer the required tokens to the `GlvVault`, then call `GlvRouter.createGlvDeposit` in the same transaction.
warning
The token transfer and the `GlvRouter.createGlvDeposit` call must occur in a single transaction. If they are separated, other users may withdraw the transferred tokens before your deposit is created.
You can deposit in two ways:
* **Underlying tokens** -- Transfer long and short tokens to the `GlvVault`. The protocol mints GM tokens internally, then mints GLV tokens to the receiver.
* **GM market tokens** -- Transfer GM tokens directly to the `GlvVault` by setting `isMarketTokenDeposit` to `true`. The protocol skips the GM minting step and mints GLV tokens to the receiver.
If this transaction reverts, the token transfer also reverts, so no funds remain in the `GlvVault`. If the deposit request is created successfully and is later cancelled, the initial deposit tokens are returned to the account that created the deposit, and any unused execution fee is refunded separately.
### GlvRouter.createGlvDeposit[](https://docs.gmx.io/docs/api/contracts/glv-router/#glvroutercreateglvdeposit "Direct link to GlvRouter.createGlvDeposit")
function createGlvDeposit( IGlvDepositUtils.CreateGlvDepositParams calldata params) external payable returns (bytes32)
Use this to add liquidity to a GLV vault. Transfer the execution fee and any long / short input tokens (or GM tokens) to the `GlvVault` in the same transaction, usually via `multicall`.
**Example (TypeScript / ethers):**
await usdc.approve(router.address, shortTokenAmount);await glvRouter.multicall( [ glvRouter.interface.encodeFunctionData("sendWnt", [glvVault.address, executionFee]), glvRouter.interface.encodeFunctionData("sendTokens", [usdc.address, glvVault.address, shortTokenAmount]), glvRouter.interface.encodeFunctionData("createGlvDeposit", [ { addresses: { glv: glvToken.address, market: marketToken, receiver: liquidityProvider.address, callbackContract: ethers.constants.AddressZero, uiFeeReceiver: ethers.constants.AddressZero, initialLongToken: longToken, initialShortToken: usdc.address, longTokenSwapPath: [], shortTokenSwapPath: [], }, minGlvTokens, executionFee, callbackGasLimit: 0, shouldUnwrapNativeToken: false, isMarketTokenDeposit: false, dataList: [], }, ]), ], { value: executionFee });
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `params` | `IGlvDepositUtils.CreateGlvDepositParams` | Struct containing GLV deposit configuration |
**Returns:** `bytes32` -- the key that identifies this GLV deposit request.
### CreateGlvDepositParams[](https://docs.gmx.io/docs/api/contracts/glv-router/#createglvdepositparams "Direct link to CreateGlvDepositParams")
The deposit struct is split into address fields and a set of numeric fields and flags.
| Field | Description |
| --- | --- |
| `addresses` | Group of address fields listed in [CreateGlvDepositParamsAddresses](https://docs.gmx.io/docs/api/contracts/glv-router/#createglvdepositparamsaddresses)
. |
| `minGlvTokens` | Minimum acceptable amount of GLV tokens to receive. |
| `executionFee` | Amount of native token (for example, ETH on Arbitrum) included as the execution fee. This is the maximum fee keepers can use to execute the deposit. Any excess is returned to the deposit account. See [Execution Fee](https://docs.gmx.io/docs/api/contracts/fees/#execution-fee)
for details. |
| `callbackGasLimit` | Gas limit passed to the callback contract on deposit execution or cancellation. |
| `shouldUnwrapNativeToken` | Whether to unwrap the native token if the deposit is cancelled. For example, if `initialLongToken` is WETH and this is `true`, the contract converts WETH to ETH before refunding. |
| `isMarketTokenDeposit` | Set to `true` when depositing GM market tokens directly instead of underlying long/short tokens. When `true`, `initialLongToken` and `initialShortToken` must be the zero address, and both swap paths must be empty. |
| `dataList` | Array of additional `bytes32` data. Pass an empty array if no extra data is needed. |
### CreateGlvDepositParamsAddresses[](https://docs.gmx.io/docs/api/contracts/glv-router/#createglvdepositparamsaddresses "Direct link to CreateGlvDepositParamsAddresses")
| Field | Description |
| --- | --- |
| `glv` | Address of the GLV vault to deposit into. |
| `market` | GM market to deposit into. Must be a market that the GLV vault supports. |
| `receiver` | Address that receives the GLV tokens. |
| `callbackContract` | Contract to call on deposit execution or cancellation. |
| `uiFeeReceiver` | Address that receives the UI fee. |
| `initialLongToken` | Long token transferred into the contract. Set to the zero address for GM token deposits. |
| `initialShortToken` | Short token transferred into the contract. Set to the zero address for GM token deposits. |
| `longTokenSwapPath` | Array of market addresses to swap `initialLongToken` through before depositing. |
| `shortTokenSwapPath` | Array of market addresses to swap `initialShortToken` through before depositing. |
Creating a GLV withdrawal[](https://docs.gmx.io/docs/api/contracts/glv-router/#creating-a-glv-withdrawal "Direct link to Creating a GLV withdrawal")
------------------------------------------------------------------------------------------------------------------------------------------------------
To create a GLV withdrawal, send the GLV tokens and execution fee to the `GlvVault` and call `GlvRouter.createGlvWithdrawal` in the same transaction, usually via `multicall`.
warning
The token transfer and the `GlvRouter.createGlvWithdrawal` call must occur in a single transaction. If they are separated, other users may withdraw the transferred tokens before your withdrawal is created.
### GlvRouter.createGlvWithdrawal[](https://docs.gmx.io/docs/api/contracts/glv-router/#glvroutercreateglvwithdrawal "Direct link to GlvRouter.createGlvWithdrawal")
function createGlvWithdrawal( IGlvWithdrawalUtils.CreateGlvWithdrawalParams calldata params) external payable returns (bytes32)
Use this to create an asynchronous GLV withdrawal request. Transfer the GLV tokens and execution fee to the `GlvVault` in the same transaction, usually via `multicall`. The withdrawal size is determined by the GLV token amount sent to the `GlvVault` with `sendTokens`.
**Example (TypeScript / ethers):**
await glvToken.approve(router.address, glvTokenAmount);await glvRouter.multicall( [ glvRouter.interface.encodeFunctionData("sendWnt", [glvVault.address, executionFee]), glvRouter.interface.encodeFunctionData("sendTokens", [ glvToken.address, glvVault.address, glvTokenAmount, ]), glvRouter.interface.encodeFunctionData("createGlvWithdrawal", [ { addresses: { receiver: trader.address, callbackContract: ethers.constants.AddressZero, uiFeeReceiver: ethers.constants.AddressZero, market: marketToken.address, glv: glvToken.address, longTokenSwapPath: [], shortTokenSwapPath: [], }, minLongTokenAmount, minShortTokenAmount, shouldUnwrapNativeToken: false, executionFee, callbackGasLimit: 0, dataList: [], }, ]), ], { value: executionFee });
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `params` | `IGlvWithdrawalUtils.CreateGlvWithdrawalParams` | Struct containing GLV withdrawal configuration |
**Returns:** `bytes32` -- the key that identifies this GLV withdrawal request.
### CreateGlvWithdrawalParams[](https://docs.gmx.io/docs/api/contracts/glv-router/#createglvwithdrawalparams "Direct link to CreateGlvWithdrawalParams")
The GLV token amount to withdraw is not part of `CreateGlvWithdrawalParams`. It is set by the amount sent to the `GlvVault` in the preceding `sendTokens` call.
| Field | Description |
| --- | --- |
| `addresses` | Group of address fields listed in [CreateGlvWithdrawalParamsAddresses](https://docs.gmx.io/docs/api/contracts/glv-router/#createglvwithdrawalparamsaddresses)
. |
| `minLongTokenAmount` | Minimum output amount of long token after swapping through `longTokenSwapPath`. For example, if WETH is swapped to BTC, this specifies the minimum BTC amount. |
| `minShortTokenAmount` | Minimum output amount of short token after swapping through `shortTokenSwapPath`. |
| `shouldUnwrapNativeToken` | Whether to unwrap the native token on output. For example, if the output token is WETH and this is `true`, the contract converts WETH to ETH before sending. |
| `executionFee` | Amount of native token (for example, ETH on Arbitrum) included as the execution fee. This is the maximum fee keepers can use to execute the withdrawal. Any excess is returned to the withdrawal account. See [Execution Fee](https://docs.gmx.io/docs/api/contracts/fees/#execution-fee)
for details. |
| `callbackGasLimit` | Gas limit passed to the callback contract on withdrawal execution or cancellation. |
| `dataList` | Array of additional `bytes32` data. Pass an empty array if no extra data is needed. |
### CreateGlvWithdrawalParamsAddresses[](https://docs.gmx.io/docs/api/contracts/glv-router/#createglvwithdrawalparamsaddresses "Direct link to CreateGlvWithdrawalParamsAddresses")
| Field | Description |
| --- | --- |
| `receiver` | Address that receives the withdrawn tokens. |
| `callbackContract` | Contract to call on withdrawal execution or cancellation. |
| `uiFeeReceiver` | Address that receives the UI fee. |
| `market` | GM market to withdraw from. Must be a market that the GLV vault supports. |
| `glv` | Address of the GLV vault to withdraw from. |
| `longTokenSwapPath` | Array of market addresses to swap the withdrawn long token through. |
| `shortTokenSwapPath` | Array of market addresses to swap the withdrawn short token through. |
Cancelling GLV requests[](https://docs.gmx.io/docs/api/contracts/glv-router/#cancelling-glv-requests "Direct link to Cancelling GLV requests")
------------------------------------------------------------------------------------------------------------------------------------------------
You can cancel a pending GLV deposit or withdrawal if it hasn't been executed yet. Only the account that created the request can cancel it.
### GlvRouter.cancelGlvDeposit[](https://docs.gmx.io/docs/api/contracts/glv-router/#glvroutercancelglvdeposit "Direct link to GlvRouter.cancelGlvDeposit")
function cancelGlvDeposit(bytes32 key) external
Cancels a pending GLV deposit. The deposited tokens and any unused execution fee are returned to the original account.
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `key` | `bytes32` | Key of the GLV deposit request to cancel |
### GlvRouter.cancelGlvWithdrawal[](https://docs.gmx.io/docs/api/contracts/glv-router/#glvroutercancelglvwithdrawal "Direct link to GlvRouter.cancelGlvWithdrawal")
function cancelGlvWithdrawal(bytes32 key) external
Cancels a pending GLV withdrawal. The GLV tokens and any unused execution fee are returned to the original account.
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `key` | `bytes32` | Key of the GLV withdrawal request to cancel |
Simulating GLV execution[](https://docs.gmx.io/docs/api/contracts/glv-router/#simulating-glv-execution "Direct link to Simulating GLV execution")
---------------------------------------------------------------------------------------------------------------------------------------------------
You can dry-run GLV deposits and withdrawals before keeper execution. These simulation helpers are publicly callable on `GlvRouter`, but the real execution path remains keeper-only on `GlvDepositHandler.executeGlvDeposit` and `GlvWithdrawalHandler.executeGlvWithdrawal`. Like the simulation helpers on `ExchangeRouter`, these calls execute with supplied oracle prices and revert with `EndOfOracleSimulation` on success, so they are typically used through `eth_call` or `callStatic`\-style preflight checks rather than as standalone state-changing transactions.
### GlvRouter.simulateExecuteGlvDeposit[](https://docs.gmx.io/docs/api/contracts/glv-router/#glvroutersimulateexecuteglvdeposit "Direct link to GlvRouter.simulateExecuteGlvDeposit")
function simulateExecuteGlvDeposit( bytes32 key, OracleUtils.SimulatePricesParams memory simulatedOracleParams)
Simulates execution for a specific GLV deposit request key.
### GlvRouter.simulateExecuteLatestGlvDeposit[](https://docs.gmx.io/docs/api/contracts/glv-router/#glvroutersimulateexecutelatestglvdeposit "Direct link to GlvRouter.simulateExecuteLatestGlvDeposit")
function simulateExecuteLatestGlvDeposit( OracleUtils.SimulatePricesParams memory simulatedOracleParams)
Simulates execution for the latest created GLV deposit request.
### GlvRouter.simulateExecuteGlvWithdrawal[](https://docs.gmx.io/docs/api/contracts/glv-router/#glvroutersimulateexecuteglvwithdrawal "Direct link to GlvRouter.simulateExecuteGlvWithdrawal")
function simulateExecuteGlvWithdrawal( bytes32 key, OracleUtils.SimulatePricesParams memory simulatedOracleParams)
Simulates execution for a specific GLV withdrawal request key.
### GlvRouter.simulateExecuteLatestGlvWithdrawal[](https://docs.gmx.io/docs/api/contracts/glv-router/#glvroutersimulateexecutelatestglvwithdrawal "Direct link to GlvRouter.simulateExecuteLatestGlvWithdrawal")
function simulateExecuteLatestGlvWithdrawal( OracleUtils.SimulatePricesParams memory simulatedOracleParams)
Simulates execution for the latest created GLV withdrawal request.
External swaps before GLV actions[](https://docs.gmx.io/docs/api/contracts/glv-router/#external-swaps-before-glv-actions "Direct link to External swaps before GLV actions")
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
`GlvRouter` also exposes `makeExternalCalls(...)` through its `ExternalHandler` integration. Use this when you need to perform an external swap or aggregator call before creating the GLV request, then refund any residual tokens back to the intended receivers.
Next steps[](https://docs.gmx.io/docs/api/contracts/glv-router/#next-steps "Direct link to Next steps")
---------------------------------------------------------------------------------------------------------
* [GLV Reader](https://docs.gmx.io/docs/api/contracts/glv-reader/)
-- Query GLV vault data and pricing
* [Simulations](https://docs.gmx.io/docs/api/contracts/simulations/)
-- Dry-run GLV actions
* [Contract addresses](https://docs.gmx.io/docs/api/contracts/addresses/)
-- GlvRouter and GlvVault addresses per chain
* [ExchangeRouter](https://docs.gmx.io/docs/api/contracts/exchange-router/)
-- GM market operations
* [Creating a GLV deposit](https://docs.gmx.io/docs/api/contracts/glv-router/#creating-a-glv-deposit)
* [GlvRouter.createGlvDeposit](https://docs.gmx.io/docs/api/contracts/glv-router/#glvroutercreateglvdeposit)
* [CreateGlvDepositParams](https://docs.gmx.io/docs/api/contracts/glv-router/#createglvdepositparams)
* [CreateGlvDepositParamsAddresses](https://docs.gmx.io/docs/api/contracts/glv-router/#createglvdepositparamsaddresses)
* [Creating a GLV withdrawal](https://docs.gmx.io/docs/api/contracts/glv-router/#creating-a-glv-withdrawal)
* [GlvRouter.createGlvWithdrawal](https://docs.gmx.io/docs/api/contracts/glv-router/#glvroutercreateglvwithdrawal)
* [CreateGlvWithdrawalParams](https://docs.gmx.io/docs/api/contracts/glv-router/#createglvwithdrawalparams)
* [CreateGlvWithdrawalParamsAddresses](https://docs.gmx.io/docs/api/contracts/glv-router/#createglvwithdrawalparamsaddresses)
* [Cancelling GLV requests](https://docs.gmx.io/docs/api/contracts/glv-router/#cancelling-glv-requests)
* [GlvRouter.cancelGlvDeposit](https://docs.gmx.io/docs/api/contracts/glv-router/#glvroutercancelglvdeposit)
* [GlvRouter.cancelGlvWithdrawal](https://docs.gmx.io/docs/api/contracts/glv-router/#glvroutercancelglvwithdrawal)
* [Simulating GLV execution](https://docs.gmx.io/docs/api/contracts/glv-router/#simulating-glv-execution)
* [GlvRouter.simulateExecuteGlvDeposit](https://docs.gmx.io/docs/api/contracts/glv-router/#glvroutersimulateexecuteglvdeposit)
* [GlvRouter.simulateExecuteLatestGlvDeposit](https://docs.gmx.io/docs/api/contracts/glv-router/#glvroutersimulateexecutelatestglvdeposit)
* [GlvRouter.simulateExecuteGlvWithdrawal](https://docs.gmx.io/docs/api/contracts/glv-router/#glvroutersimulateexecuteglvwithdrawal)
* [GlvRouter.simulateExecuteLatestGlvWithdrawal](https://docs.gmx.io/docs/api/contracts/glv-router/#glvroutersimulateexecutelatestglvwithdrawal)
* [External swaps before GLV actions](https://docs.gmx.io/docs/api/contracts/glv-router/#external-swaps-before-glv-actions)
* [Next steps](https://docs.gmx.io/docs/api/contracts/glv-router/#next-steps)
---
# Known issues | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/contracts/known-issues/#__docusaurus_skipToContent_fallback)
On this page
This page is based on the known issues section of the [gmx-synthetics repository](https://github.com/gmx-io/gmx-synthetics/blob/updates/README.md#known-issues)
, with corrections and additions. It is intended for integrators, auditors, and developers building on top of the GMX contracts.
Tokens[](https://docs.gmx.io/docs/api/contracts/known-issues/#tokens "Direct link to Tokens")
-----------------------------------------------------------------------------------------------
These constraints apply to tokens used with the protocol.
* Collateral tokens must be whitelisted with a configured `TOKEN_TRANSFER_GAS_LIMIT`.
* Rebasing tokens, tokens that change balance on transfer, tokens with burns, tokens with callbacks (for example, ERC-777 tokens), and similar non-standard tokens are not compatible with the system and must not be whitelisted.
Keepers[](https://docs.gmx.io/docs/api/contracts/known-issues/#keepers "Direct link to Keepers")
--------------------------------------------------------------------------------------------------
These items describe known keeper behavior and limitations.
* Order keepers can use prices from different timestamps for limit orders with a swap, which leads to different output amounts.
* Order keepers are expected to validate whether a transaction will revert before sending it, to minimize gas wastage.
* Order keepers may cause requests to be cancelled instead of executed by executing the request with insufficient gas.
* If an execution transaction requires a large amount of gas close to the maximum block gas limit, it may be possible to stuff blocks to prevent the transaction from being included.
* On certain blockchains, the keeper can control the `tx.gasprice` used to execute a transaction, which affects the execution fee paid to the keeper.
* A malicious user can intentionally unbalance a market to create high price impact, preventing order execution. This is expected to be costly and difficult to benefit from.
Price impact[](https://docs.gmx.io/docs/api/contracts/known-issues/#price-impact "Direct link to Price impact")
-----------------------------------------------------------------------------------------------------------------
These items describe known limitations of the price impact mechanism.
* Price impact can be reduced by using positions and swaps across markets, chains, forks, and other protocols. Virtual inventory tracking partially mitigates this.
* A user can reduce price impact by using high-leverage positions. The `MIN_COLLATERAL_FACTOR_FOR_OPEN_INTEREST_MULTIPLIER` value partially mitigates this.
* Price impact calculations don't account for fees or the effects of the price impact itself. In most cases, the effect on the calculation is expected to be small.
Market token price[](https://docs.gmx.io/docs/api/contracts/known-issues/#market-token-price "Direct link to Market token price")
-----------------------------------------------------------------------------------------------------------------------------------
These items describe edge cases in market token pricing.
* It is rare but possible for a pool's value to become negative. This can happen because the `impactPoolAmount` and pending PnL are subtracted from the worth of the tokens in the pool.
* Due to the difference in positive and negative position price impact, virtual token amounts can build up in the position impact pool, which affects the pricing of market tokens. The position impact pool must be gradually distributed if needed.
Virtual inventory[](https://docs.gmx.io/docs/api/contracts/known-issues/#virtual-inventory "Direct link to Virtual inventory")
--------------------------------------------------------------------------------------------------------------------------------
Virtual inventory tracking has the following constraints.
* Virtual inventory tracks the amount of tokens in pools. Tokens in each grouping must be the same type and have the same decimals — the long tokens across pools in the group must have the same decimals, and the short tokens across pools in the group must have the same decimals. For example, because USDC has 6 decimals and DAI has 18 decimals, markets like ETH-USDC and ETH-DAI must not be grouped.
* Virtual IDs must be set before market creation or token whitelisting. If set after trading for the token or market has occurred, the tracking won't be accurate and may need to be adjusted.
Blockchain[](https://docs.gmx.io/docs/api/contracts/known-issues/#blockchain "Direct link to Blockchain")
-----------------------------------------------------------------------------------------------------------
These items cover blockchain-level risks and mitigations.
* For L2s with sequencers, there is no contract validation to check if the L2 sequencer is active. Oracle keepers must stop signing prices if the sequencer stops producing blocks. When the sequencer resumes, oracle keepers must sign prices for the latest blocks using the latest fetched prices.
* If an L2 sequencer is down, it may prevent deposits into positions to prevent liquidations.
* For transactions that can be executed entirely using on-chain price feeds, it may be possible to take advantage of stale pricing due to price latency or the chain being down. On-chain price feeds must be temporary, and low-latency feeds must be used instead once all tokens are supported.
* Block re-orgs could allow a user to retroactively cancel an order after it has been executed if price didn't move favorably for the user. Handle this case if using the contracts on chains where long re-orgs are possible.
* Updating and cancellation of orders could be front-run to prevent order execution. This is not expected to be an issue if the probability of successful front-running is `<= 50%`. If the probability is higher than 50%, fees and price impact must be adjusted to ensure the strategy is not net profitable. Adjusting the UI fee or referral discount could similarly be used to cause order cancellations.
* During downtime of the blockchain or oracle, orders may be executed at significantly different prices or may not execute if the order's acceptable price can't be fulfilled.
* There is a dependency on the accuracy of the block timestamp because oracle prices are validated against this value. For blockchains where nodes have some control over the timestamp, set the `oracleTimestampAdjustment` to a value that makes manipulation of the timestamp unprofitable.
GLV[](https://docs.gmx.io/docs/api/contracts/known-issues/#glv "Direct link to GLV")
--------------------------------------------------------------------------------------
These items describe known risks specific to GLV vaults.
* The GLV shift feature can be exploited by temporarily increasing the utilization in a market that typically has low utilization. Once the keeper executes the shift, the attacker can lower the utilization back to normal levels. Position fees and price impact must be configured to make this attack expensive enough to cover the GLV loss.
* A GLV may contain GM markets that are above their maximum `pnlToPoolFactorForTraders`. If a GM market's `maxPnlFactorForDeposits` is higher than `maxPnlFactorForTraders`, the GM market is valued lower during deposits than it will be once traders have realized their capped profits. A malicious user may observe a GM market in this condition and deposit into the GLV to gain from the ADLs that follow. To avoid this, `maxPnlFactorForDeposits` must be less than or equal to `maxPnlFactorForTraders`.
* It is technically possible for market value to become negative. In this case, the GLV is unusable until the market value becomes positive.
* GM tokens could become illiquid due to high PnL factor or high reserved USD. Users can deposit illiquid GM tokens into a GLV and withdraw liquidity from a different market, leaving the GLV with illiquid tokens. The `glvMaxMarketTokenBalanceUsd` and `glvMaxMarketTokenBalanceAmount` parameters must account for the riskiness of a market to avoid accumulating too many GM tokens from a risky market.
Factories[](https://docs.gmx.io/docs/api/contracts/known-issues/#factories "Direct link to Factories")
--------------------------------------------------------------------------------------------------------
This item describes a known behavior in market and GLV factory contracts.
* When adding a market with the `MarketStoreUtils.set` function, the market receives a lookup where the market address can be obtained with the market salt. This lookup is not cleared on market deletion. The same applies to GLV.
Notes[](https://docs.gmx.io/docs/api/contracts/known-issues/#notes "Direct link to Notes")
--------------------------------------------------------------------------------------------
These notes cover deployment, configuration, and upgrade procedures.
### Deployment[](https://docs.gmx.io/docs/api/contracts/known-issues/#deployment "Direct link to Deployment")
These items cover the initial deployment verification process.
* Use `scripts/verifyFallback.ts` to verify contracts.
* One MarketToken contract needs to be verified using `npx hardhat verify`. After that, all MarketToken contracts are verified because the source code is the same.
### Configuration[](https://docs.gmx.io/docs/api/contracts/known-issues/#configuration "Direct link to Configuration")
This item covers a key configuration parameter.
* `MAX_ORACLE_REF_PRICE_DEVIATION_FACTOR` is a sanity check that helps guard against incorrect oracle decimal configuration or incorrect price feed configuration. Set this to a sufficiently high value to prevent reverts during times of high volatility.
### Upgrades[](https://docs.gmx.io/docs/api/contracts/known-issues/#upgrades "Direct link to Upgrades")
These items describe considerations when upgrading contracts.
* If new contracts lead to a difference in pricing (for example, of market tokens) between old and new contracts, disable the old contracts before enabling the new ones.
* Notify external protocols that use the Reader contract or potentially outdated pricing calculations to use the latest contracts and calculations (for example, Chainlink price feeds for GM tokens).
* Publish a best-effort changelog documenting important changes that integrations must be aware of (for example, if a field is added to a struct passed into a callback function). These changes may not be obvious to integrations.
* If the contracts support equity synthetic markets, ensure that stock splits and similar changes can be handled.
* Contracts with the `CONTROLLER` role have access to important functions such as setting DataStore values. Ensure that such contracts don't have generic functions that can be used to change important values.
* Add tests for the different market types (for example, spot-only markets, single-token markets).
* Don't modify the ordering of values in the `eventData` for callbacks unless strictly necessary, because callback contracts may reference values by a fixed index.
* If a struct passed into callbacks is changed (for example, Deposit, Withdrawal, Order structs), callback contracts expecting the previous struct stop working. Highlight struct changes to integrations.
* If the referral system is in use, the OrderHandler must be given access to update the referral code for traders.
Integrations[](https://docs.gmx.io/docs/api/contracts/known-issues/#integrations "Direct link to Integrations")
-----------------------------------------------------------------------------------------------------------------
These items describe integration considerations for protocols building on the GMX contracts.
### General[](https://docs.gmx.io/docs/api/contracts/known-issues/#general "Direct link to General")
These general considerations apply to all integrations.
* Deposits, withdrawals, and orders may be cancelled if the requirements specified in the request can't be fulfilled (for example, minimum output amount). Check where funds and gas refunds are sent on cancellation to ensure it matches expectations.
* Decrease position orders can output two tokens instead of one if the decrease position swap fails. The output amount and collateral may also not be sufficient to cover fees, causing the order not to be executed.
* If there is a large spread, opening or closing a position can significantly change the min and max price of the market token. This must not be manipulatable in a profitable way.
* Changes in config values such as `FUNDING_FACTOR`, `THRESHOLD_FOR_STABLE_FUNDING`, `BORROWING_FACTOR`, `SKIP_BORROWING_FEE_FOR_SMALLER_SIDE`, and `BORROWING_FEE_RECEIVER_FACTOR` could lead to additional charges for users and changes in market token price.
* If trader PnL is capped due to `MAX_PNL_FACTOR_FOR_TRADERS`, the percentage of profit paid out to traders may differ depending on the order in which positions are decreased or closed, because the cap is recalculated based on the current state of the pool.
* Event data may be passed to callback contracts. The ordering of params in the `eventData` is kept unchanged where possible, so params can be accessed by index. For safety, validate the key of each param before use to confirm it matches the expected value.
* Some parameters such as `order.sizeDelta` and `order.initialCollateralDeltaAmount` may be updated during execution. The updated values may not be passed to the callback contract.
* Callback contracts may need to whitelist the DepositHandler, OrderHandler, or WithdrawalHandler. New versions of these handlers may be deployed as new code is added, and two handlers can temporarily exist at the same time (for example, OrderHandler(1), OrderHandler(2)). The callback contract must be able to whitelist and simultaneously accept callbacks from multiple handlers.
* Instead of maintaining a separate whitelist for each handler type, validate the role of `msg.sender` in the RoleStore — for example, `RoleStore.hasRole(msg.sender, Role.CONTROLLER)`. This checks that `msg.sender` is a valid handler.
* If the user can choose which ExchangeRouter to interact with, don't assume the callback params are a fixed format. During transitions between old and new contracts, callbacks for functions such as `afterOrderCancellation` could be in either format. If only a specific ExchangeRouter can trigger the callback, this is not an issue.
* Addresses of contracts such as the ExchangeRouter, Oracle, or Reader change as new logic is added.
* When contracts such as the ExchangeRouter, Oracle, or Reader are updated, effort is made to keep function parameters the same. However, this may not always be possible (for example, if a new order property requires changing the `ExchangeRouter.createOrder` params).
* The RoleStore and DataStore for deployments must not change. If they are changed, a migration of funds from the previous contracts to the new contracts is likely needed.
* While the code is structured to minimize the risk of [read-only reentrancy](https://officercia.mirror.xyz/DBzFiDuxmDOTQEbfXhvLdK0DXVpKu1Nkurk0Cqk3QKc)
, guard against this possibility.
* Token airdrops may occur to accounts of GM token holders. Integrating contracts holding GM tokens must be able to claim these tokens, otherwise the tokens are locked. One approach is to allow claiming of tokens that aren't market tokens — check using the `Keys.MARKET_LIST` value.
* ETH transfers are sent with `NATIVE_TOKEN_TRANSFER_GAS_LIMIT` for the gas limit. If the transfer fails due to insufficient gas or other errors, ETH is sent as WETH instead.
* Accounts may receive ETH for ADLs or liquidations. If the account can't receive ETH, WETH is sent instead.
* Positive price impact is capped by the amount of tokens in the impact pools and by configured values.
* Negative price impact may be capped by configured values.
* If negative price impact is capped, the additional amount is kept in the claimable collateral pool. Claim it manually using `ExchangeRouter.claimCollateral`.
* Positive funding fees must be manually claimed using `ExchangeRouter.claimFundingFees`.
* Affiliate rewards must be manually claimed using `ExchangeRouter.claimAffiliateRewards`.
* Markets or features may be disabled.
* Execution continues even if a callback reverts.
* Ensure callbacks have sufficient gas.
* Subaccounts can create, update, and cancel any order for an account.
* Subaccounts can spend WNT and collateral from the account.
* UI fees can be changed.
* Referral discounts can be changed.
* Funds for blacklisted addresses are kept within the protocol.
* The index token is not always the long token.
* Fee rates change depending on whether there is a positive or negative impact.
### Deposits[](https://docs.gmx.io/docs/api/contracts/known-issues/#deposits "Direct link to Deposits")
These items apply to deposit integrations.
* Consider PnL factor when estimating GM price.
* Handle deposit cancellations.
* Ensure only handlers with the `CONTROLLER` role can call the `afterDepositExecution` and `afterDepositCancellation` callback functions.
* Ensure only the correct deposit execution can call callback functions.
* Consider markets with the same long and short token — swaps aren't supported for these markets.
* Consider positive and negative price impact.
* There is a request cancellation period for a configured delay during which deposit requests can't be cancelled.
* Output amounts are subject to price impact and fees.
* Deposits aren't allowed above the `MAX_PNL_FACTOR_FOR_DEPOSITS`.
* The first deposit in any market must go to the `RECEIVER_FOR_FIRST_DEPOSIT`.
### Withdrawals[](https://docs.gmx.io/docs/api/contracts/known-issues/#withdrawals "Direct link to Withdrawals")
These items apply to withdrawal integrations.
* Two minimum outputs must be used for withdrawals.
* Handle withdrawal cancellations.
* Ensure only handlers with the `CONTROLLER` role can call the `afterWithdrawalExecution` and `afterWithdrawalCancellation` callback functions.
* Ensure only the correct withdrawal execution can call callback functions.
* Consider markets with the same long and short token — swaps aren't supported for these markets.
* Consider positive and negative price impact.
* There is a request cancellation period for a configured delay during which withdrawal requests can't be cancelled.
* Output amounts are subject to price impact and fees.
* Withdrawals aren't allowed above the `MAX_PNL_FACTOR_FOR_WITHDRAWALS`.
### Orders[](https://docs.gmx.io/docs/api/contracts/known-issues/#orders "Direct link to Orders")
These items apply to order integrations.
* Handle order cancellations.
* Liquidations and ADLs can trigger the saved callback contract.
* Orders can become frozen.
* Ensure only handlers with the `CONTROLLER` role can call the `afterOrderExecution`, `afterOrderCancellation`, and `afterOrderFrozen` callback functions.
* Ensure only the correct order execution can call callback functions.
* Consider markets with the same long and short token — swaps aren't supported for these markets.
* Consider positive and negative price impact.
* Saved callback contracts can be changed.
* There is a request cancellation period for a configured delay during which order requests can't be cancelled.
* Output amounts are subject to price impact and fees.
* The position impact pool is distributed to liquidity providers over time.
* If computing price impact, consult the virtual inventory.
* Trader PnL is capped above the `MAX_PNL_FACTOR_FOR_TRADERS`.
* Negative price impact can be capped on position decreases.
* Decrease order `sizeDelta` and `collateralDelta` are auto-updated if they exceed what the position can handle.
* Consider `willPositionCollateralBeSufficient` validation.
* Consider `decreasePositionSwapTypes`.
* Consider the minimum collateral amount.
* Referrals are still paid out during liquidation.
* It is possible for positions to have zero collateral.
* Positions with zero size can't exist.
* [Tokens](https://docs.gmx.io/docs/api/contracts/known-issues/#tokens)
* [Keepers](https://docs.gmx.io/docs/api/contracts/known-issues/#keepers)
* [Price impact](https://docs.gmx.io/docs/api/contracts/known-issues/#price-impact)
* [Market token price](https://docs.gmx.io/docs/api/contracts/known-issues/#market-token-price)
* [Virtual inventory](https://docs.gmx.io/docs/api/contracts/known-issues/#virtual-inventory)
* [Blockchain](https://docs.gmx.io/docs/api/contracts/known-issues/#blockchain)
* [GLV](https://docs.gmx.io/docs/api/contracts/known-issues/#glv)
* [Factories](https://docs.gmx.io/docs/api/contracts/known-issues/#factories)
* [Notes](https://docs.gmx.io/docs/api/contracts/known-issues/#notes)
* [Deployment](https://docs.gmx.io/docs/api/contracts/known-issues/#deployment)
* [Configuration](https://docs.gmx.io/docs/api/contracts/known-issues/#configuration)
* [Upgrades](https://docs.gmx.io/docs/api/contracts/known-issues/#upgrades)
* [Integrations](https://docs.gmx.io/docs/api/contracts/known-issues/#integrations)
* [General](https://docs.gmx.io/docs/api/contracts/known-issues/#general)
* [Deposits](https://docs.gmx.io/docs/api/contracts/known-issues/#deposits)
* [Withdrawals](https://docs.gmx.io/docs/api/contracts/known-issues/#withdrawals)
* [Orders](https://docs.gmx.io/docs/api/contracts/known-issues/#orders)
---
# Overview | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/contracts/overview/#__docusaurus_skipToContent_fallback)
On this page
Docs for the GMX contracts. This section focuses on the contracts most integrations interact with directly, not an exhaustive page for every deployed contract.
Important notes[](https://docs.gmx.io/docs/api/contracts/overview/#important-notes "Direct link to Important notes")
----------------------------------------------------------------------------------------------------------------------
Review these points before integrating with the contracts.
warning
See the [Known issues](https://docs.gmx.io/docs/api/contracts/known-issues/)
page for the full list of known issues and integration considerations.
These docs provide an overview. Check the actual contract code for the exact implementation and for any edge cases when building an application or integration.
Contracts such as readers and events may not be audited. Check the scopes of the audits for more information, and take extra caution when using or depending on these contracts.
Subscribe to the channels on the [Updates and Support](https://docs.gmx.io/docs/api/updates-support/)
page for important contract update notifications.
How it works[](https://docs.gmx.io/docs/api/contracts/overview/#how-it-works "Direct link to How it works")
-------------------------------------------------------------------------------------------------------------
The protocol separates concerns across four contract categories (bank, data storage, logic, and event contracts) to enable upgrades without fund migration. Most user actions follow a two-phase execution model where the user submits a request and a keeper executes it with oracle prices. For a detailed explanation of the architecture and keeper network, see [Architecture](https://docs.gmx.io/docs/api/contracts/architecture/)
.
The [contracts repo](https://github.com/gmx-io/gmx-synthetics/tree/updates)
provides the production-branch source code. The [test](https://github.com/gmx-io/gmx-synthetics/tree/updates/test)
folder contains examples for interacting with the contracts.
Deployments[](https://docs.gmx.io/docs/api/contracts/overview/#deployments "Direct link to Deployments")
----------------------------------------------------------------------------------------------------------
Key contract addresses for all supported chains (Arbitrum, Avalanche, Botanix, MegaETH) and testnets are listed on the [Contract addresses](https://docs.gmx.io/docs/api/contracts/addresses/)
page.
The full deployment list with all 130+ contracts per chain is in the [gmx-synthetics docs folder](https://github.com/gmx-io/gmx-synthetics/tree/updates/docs)
. The machine-readable `contracts.json` currently covers mainnet deployments, while testnet deployments are published in the per-network markdown files in that folder.
### Testnet[](https://docs.gmx.io/docs/api/contracts/overview/#testnet "Direct link to Testnet")
The Arbitrum Sepolia deployment is typically the most current testnet. See [Contract addresses — Testnet](https://docs.gmx.io/docs/api/contracts/addresses/#testnet)
for key testnet addresses.
For a frontend that connects to testnet, see the [Testnet frontend](https://docs.gmx.io/docs/api/frontend-integration/#testnet-frontend)
section.
Reading values[](https://docs.gmx.io/docs/api/contracts/overview/#reading-values "Direct link to Reading values")
-------------------------------------------------------------------------------------------------------------------
You can read on-chain values using three contracts:
* [Reader](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/reader/Reader.sol)
* [GlvReader](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/reader/GlvReader.sol)
* [DataStore](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/data/DataStore.sol)
The `Reader` contract provides convenience functions for retrieving information such as markets and positions lists.
Most integrations only need a small set of entry points:
* `ExchangeRouter` for creating orders, deposits, withdrawals, and shifts
* `GlvRouter` for GLV-specific deposits and withdrawals
* `Reader` for GM markets, positions, and pricing data
* `GlvReader` for GLV-specific reads
The wider protocol architecture includes many additional handlers, vaults, storage contracts, and utility contracts. See [Architecture](https://docs.gmx.io/docs/api/contracts/architecture/)
for how those pieces fit together.
For delegated trading, gasless relay flows, and GMX Account cross-chain routers, see [Advanced entry points](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/)
.
You can also retrieve additional information using the `DataStore` and `Keys` contracts. The [test](https://github.com/gmx-io/gmx-synthetics/tree/updates/test)
folder contains `DataStore` usage examples, and the [keys](https://github.com/gmx-io/gmx-synthetics/blob/updates/utils/keys.ts)
file shows how to construct keys for `DataStore` reads.
To retrieve multiple values in a single query, use a [Multicall contract](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/mock/Multicall3.sol)
. See [Contract addresses](https://docs.gmx.io/docs/api/contracts/addresses/)
for the `Multicall3` address on each chain.
For detailed function references, see the [Reader](https://docs.gmx.io/docs/api/contracts/reader/)
and [GLV Reader](https://docs.gmx.io/docs/api/contracts/glv-reader/)
pages.
For retrieving prices, see the [REST API](https://docs.gmx.io/docs/api/rest-api/oracle-prices/)
docs.
For token compatibility, known limitations, and integration considerations, see the [Known issues](https://docs.gmx.io/docs/api/contracts/known-issues/)
page.
* [Important notes](https://docs.gmx.io/docs/api/contracts/overview/#important-notes)
* [How it works](https://docs.gmx.io/docs/api/contracts/overview/#how-it-works)
* [Deployments](https://docs.gmx.io/docs/api/contracts/overview/#deployments)
* [Testnet](https://docs.gmx.io/docs/api/contracts/overview/#testnet)
* [Reading values](https://docs.gmx.io/docs/api/contracts/overview/#reading-values)
---
# Reader | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/contracts/reader/#__docusaurus_skipToContent_fallback)
On this page
The Reader contract provides convenience functions for retrieving information such as markets, positions, and pricing data.
This page focuses on the most commonly used read helpers. For the full public surface, see [`Reader.sol`](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/reader/Reader.sol)
.
Examples below assume you already have contract instances such as `reader`, `dataStore`, and `referralStorage`, plus any required market or price structs.
Market list[](https://docs.gmx.io/docs/api/contracts/reader/#market-list "Direct link to Market list")
--------------------------------------------------------------------------------------------------------
Use `Reader.getMarkets` to retrieve a paginated list of all markets. Each market is represented by a `Market.Props` struct.
### Reader.getMarkets[](https://docs.gmx.io/docs/api/contracts/reader/#readergetmarkets "Direct link to Reader.getMarkets")
function getMarkets(DataStore dataStore, uint256 start, uint256 end) external view returns (Market.Props[] memory)
**Example (TypeScript / ethers):**
const markets = await reader.getMarkets(dataStore.address, 0, 20);
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `start` | `uint256` | Start index for pagination |
| `end` | `uint256` | End index for pagination |
**Returns:** Array of `Market.Props`.
### Market.Props[](https://docs.gmx.io/docs/api/contracts/reader/#marketprops "Direct link to Market.Props")
| Field | Type | Description |
| --- | --- | --- |
| `marketToken` | `address` | Address of the GM token for this market |
| `indexToken` | `address` | Address of the index token (for example, ETH for the ETH/USD market) |
| `longToken` | `address` | Address of the long collateral token |
| `shortToken` | `address` | Address of the short collateral token |
Detailed market list[](https://docs.gmx.io/docs/api/contracts/reader/#detailed-market-list "Direct link to Detailed market list")
-----------------------------------------------------------------------------------------------------------------------------------
Use `Reader.getMarketInfoList` to retrieve markets with additional runtime data including borrowing rates, funding rates, and whether the market is disabled.
### Reader.getMarketInfoList[](https://docs.gmx.io/docs/api/contracts/reader/#readergetmarketinfolist "Direct link to Reader.getMarketInfoList")
function getMarketInfoList( DataStore dataStore, MarketUtils.MarketPrices[] memory marketPricesList, uint256 start, uint256 end) external view returns (ReaderUtils.MarketInfo[] memory)
**Example (TypeScript / ethers):**
const marketInfoList = await reader.getMarketInfoList(dataStore.address, marketPricesList, 0, 20);
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `marketPricesList` | `MarketUtils.MarketPrices[]` | Current prices for each market, in the same order as the markets being queried |
| `start` | `uint256` | Start index for pagination |
| `end` | `uint256` | End index for pagination |
**Returns:** Array of `ReaderUtils.MarketInfo`, which includes the market props, borrowing rates, funding rates, and a flag indicating whether the market is disabled.
### MarketUtils.MarketPrices[](https://docs.gmx.io/docs/api/contracts/reader/#marketutilsmarketprices "Direct link to MarketUtils.MarketPrices")
| Field | Type | Description |
| --- | --- | --- |
| `indexTokenPrice` | `Price.Props` | Current price range for the index token |
| `longTokenPrice` | `Price.Props` | Current price range for the long token |
| `shortTokenPrice` | `Price.Props` | Current price range for the short token |
### Price.Props[](https://docs.gmx.io/docs/api/contracts/reader/#priceprops "Direct link to Price.Props")
| Field | Type | Description |
| --- | --- | --- |
| `min` | `uint256` | Minimum (bid) price |
| `max` | `uint256` | Maximum (ask) price |
Getting GM token price[](https://docs.gmx.io/docs/api/contracts/reader/#getting-gm-token-price "Direct link to Getting GM token price")
-----------------------------------------------------------------------------------------------------------------------------------------
Use `Reader.getMarketTokenPrice` to retrieve the current GM token price along with detailed pool information: pool value, PnL, token amounts, borrowing fees, and the impact pool.
### Reader.getMarketTokenPrice[](https://docs.gmx.io/docs/api/contracts/reader/#readergetmarkettokenprice "Direct link to Reader.getMarketTokenPrice")
function getMarketTokenPrice( DataStore dataStore, Market.Props memory market, Price.Props memory indexTokenPrice, Price.Props memory longTokenPrice, Price.Props memory shortTokenPrice, bytes32 pnlFactorType, bool maximize) external view returns (int256, MarketPoolValueInfo.Props memory)
**Example (TypeScript / ethers):**
const [gmPrice, poolInfo] = await reader.getMarketTokenPrice( dataStore.address, market, indexTokenPrice, longTokenPrice, shortTokenPrice, pnlFactorType, true);
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `market` | `Market.Props` | Market data struct (see [Market list](https://docs.gmx.io/docs/api/contracts/reader/#market-list)
) |
| `indexTokenPrice` | `Price.Props` | Current price range for the index token |
| `longTokenPrice` | `Price.Props` | Current price range for the long token |
| `shortTokenPrice` | `Price.Props` | Current price range for the short token |
| `pnlFactorType` | `bytes32` | Which PnL factor cap to apply. Use `Keys.MAX_PNL_FACTOR_FOR_TRADERS` for trading contexts, `Keys.MAX_PNL_FACTOR_FOR_DEPOSITS` for deposit simulation, or `Keys.MAX_PNL_FACTOR_FOR_WITHDRAWALS` for withdrawal simulation. |
| `maximize` | `bool` | Pass `true` to use maximum prices (gives the higher GM token price), `false` to use minimum prices |
**Returns:** A tuple of `(int256 price, MarketPoolValueInfo.Props poolInfo)` where `price` is the GM token price and `poolInfo` contains pool value, PnL, token amounts, borrowing fees, and the impact pool balance.
Position list[](https://docs.gmx.io/docs/api/contracts/reader/#position-list "Direct link to Position list")
--------------------------------------------------------------------------------------------------------------
Use `Reader.getAccountPositions` to retrieve all open positions for a given account. The function returns raw position data without fee or pricing calculations.
### Reader.getAccountPositions[](https://docs.gmx.io/docs/api/contracts/reader/#readergetaccountpositions "Direct link to Reader.getAccountPositions")
function getAccountPositions( DataStore dataStore, address account, uint256 start, uint256 end) external view returns (Position.Props[] memory)
**Example (TypeScript / ethers):**
const positions = await reader.getAccountPositions(dataStore.address, account.address, 0, 20);
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `account` | `address` | The account address to retrieve positions for |
| `start` | `uint256` | Start index for pagination |
| `end` | `uint256` | End index for pagination |
**Returns:** Array of `Position.Props`, each containing the raw position state (size, collateral, entry price, and so on).
Detailed position list[](https://docs.gmx.io/docs/api/contracts/reader/#detailed-position-list "Direct link to Detailed position list")
-----------------------------------------------------------------------------------------------------------------------------------------
Use `Reader.getAccountPositionInfoList` to retrieve all open positions for a given account with full fee and pricing context. This function uses the account address and market list directly rather than position keys.
note
`Reader.getAccountPositionInfoList` uses an account plus market list rather than explicit `positionKeys`. If you need to query specific keys directly, use `Reader.getPositionInfoList`.
### Reader.getAccountPositionInfoList[](https://docs.gmx.io/docs/api/contracts/reader/#readergetaccountpositioninfolist "Direct link to Reader.getAccountPositionInfoList")
function getAccountPositionInfoList( DataStore dataStore, IReferralStorage referralStorage, address account, address[] memory markets, MarketUtils.MarketPrices[] memory marketPrices, address uiFeeReceiver, uint256 start, uint256 end) external view returns (ReaderPositionUtils.PositionInfo[] memory)
**Example (TypeScript / ethers):**
const positionInfoList = await reader.getAccountPositionInfoList( dataStore.address, referralStorage.address, account.address, markets, marketPrices, ethers.constants.AddressZero, 0, 20);
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `referralStorage` | `address` | Address of the ReferralStorage contract |
| `account` | `address` | The account address to retrieve positions for |
| `markets` | `address[]` | Array of perp market addresses covering every position you expect to retrieve. Must contain only perpetual markets (not swap-only markets). |
| `marketPrices` | `MarketUtils.MarketPrices[]` | Current prices for each market in the same order as `markets`. If a returned position's market is missing from this list, the call reverts. |
| `uiFeeReceiver` | `address` | Address of the UI fee receiver used in fee calculations. Pass the zero address if not applicable. |
| `start` | `uint256` | Start index for pagination |
| `end` | `uint256` | End index for pagination |
**Returns:** Array of `ReaderPositionUtils.PositionInfo`, each including the position, fees, execution price, and PnL.
Position information[](https://docs.gmx.io/docs/api/contracts/reader/#position-information "Direct link to Position information")
-----------------------------------------------------------------------------------------------------------------------------------
Use `Reader.getPositionInfo` to retrieve full details for a single position, including fees, execution price, and PnL.
### Reader.getPositionInfo[](https://docs.gmx.io/docs/api/contracts/reader/#readergetpositioninfo "Direct link to Reader.getPositionInfo")
function getPositionInfo( DataStore dataStore, IReferralStorage referralStorage, bytes32 positionKey, MarketUtils.MarketPrices memory prices, uint256 sizeDeltaUsd, address uiFeeReceiver, bool usePositionSizeAsSizeDeltaUsd) public view returns (ReaderPositionUtils.PositionInfo memory)
**Example (TypeScript / ethers):**
const positionInfo = await reader.getPositionInfo( dataStore.address, referralStorage.address, positionKey, prices, 0, ethers.constants.AddressZero, false);
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `referralStorage` | `address` | Address of the ReferralStorage contract |
| `positionKey` | `bytes32` | Key identifying the position |
| `prices` | `MarketUtils.MarketPrices` | Current prices for the index, long, and short tokens |
| `sizeDeltaUsd` | `uint256` | Used to calculate fees and execution price when simulating a position decrease. Pass `0` if not simulating a size change. |
| `uiFeeReceiver` | `address` | Address of the UI fee receiver for fee calculations. Pass the zero address if not applicable. |
| `usePositionSizeAsSizeDeltaUsd` | `bool` | Pass `true` to use the full position size as `sizeDeltaUsd` (for example, when simulating a full close) |
**Returns:** `ReaderPositionUtils.PositionInfo` containing the position data, fees, execution price, and PnL.
Detailed position list by key[](https://docs.gmx.io/docs/api/contracts/reader/#detailed-position-list-by-key "Direct link to Detailed position list by key")
--------------------------------------------------------------------------------------------------------------------------------------------------------------
Use `Reader.getPositionInfoList` to retrieve detailed position data when you already have an array of position keys.
### Reader.getPositionInfoList[](https://docs.gmx.io/docs/api/contracts/reader/#readergetpositioninfolist "Direct link to Reader.getPositionInfoList")
function getPositionInfoList( DataStore dataStore, IReferralStorage referralStorage, bytes32[] memory positionKeys, MarketUtils.MarketPrices[] memory prices, address uiFeeReceiver) external view returns (ReaderPositionUtils.PositionInfo[] memory)
**Example (TypeScript / ethers):**
const positionInfoList = await reader.getPositionInfoList( dataStore.address, referralStorage.address, positionKeys, prices, ethers.constants.AddressZero);
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `referralStorage` | `address` | Address of the ReferralStorage contract |
| `positionKeys` | `bytes32[]` | Position keys to query |
| `prices` | `MarketUtils.MarketPrices[]` | Current prices for the markets of the requested positions, in the same order as `positionKeys` |
| `uiFeeReceiver` | `address` | Address of the UI fee receiver used in fee calculations. Pass the zero address if not applicable. |
**Returns:** Array of `ReaderPositionUtils.PositionInfo` values in the same order as `positionKeys`.
Execution price for increasing or decreasing a position[](https://docs.gmx.io/docs/api/contracts/reader/#execution-price-for-increasing-or-decreasing-a-position "Direct link to Execution price for increasing or decreasing a position")
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Use `Reader.getExecutionPrice` to estimate the execution price for increasing or decreasing a position, accounting for price impact.
### Reader.getExecutionPrice[](https://docs.gmx.io/docs/api/contracts/reader/#readergetexecutionprice "Direct link to Reader.getExecutionPrice")
function getExecutionPrice( DataStore dataStore, address marketKey, MarketUtils.MarketPrices memory prices, uint256 positionSizeInUsd, uint256 positionSizeInTokens, int256 sizeDeltaUsd, int256 pendingImpactAmount, bool isLong) external view returns (ReaderPricingUtils.ExecutionPriceResult memory)
**Example (TypeScript / ethers):**
const executionPriceResult = await reader.getExecutionPrice( dataStore.address, marketKey, prices, positionSizeInUsd, positionSizeInTokens, sizeDeltaUsd, pendingImpactAmount, true);
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `marketKey` | `address` | Address of the market |
| `prices` | `MarketUtils.MarketPrices` | Current prices for the index, long, and short tokens |
| `positionSizeInUsd` | `uint256` | Current size of the open position in USD. Pass `0` if there is no existing position. |
| `positionSizeInTokens` | `uint256` | Current size of the open position in index tokens. Pass `0` if there is no existing position. |
| `sizeDeltaUsd` | `int256` | Size change in USD. Positive to increase, negative to decrease. |
| `pendingImpactAmount` | `int256` | Pending price impact amount already accumulated for this position |
| `isLong` | `bool` | Pass `true` for a long position, `false` for short |
**Returns:** `ReaderPricingUtils.ExecutionPriceResult` containing the execution price and price impact amounts.
Output amount for swaps[](https://docs.gmx.io/docs/api/contracts/reader/#output-amount-for-swaps "Direct link to Output amount for swaps")
--------------------------------------------------------------------------------------------------------------------------------------------
Use `Reader.getSwapAmountOut` to estimate how many tokens you receive for a swap, along with the price impact and swap fees.
### Reader.getSwapAmountOut[](https://docs.gmx.io/docs/api/contracts/reader/#readergetswapamountout "Direct link to Reader.getSwapAmountOut")
function getSwapAmountOut( DataStore dataStore, Market.Props memory market, MarketUtils.MarketPrices memory prices, address tokenIn, uint256 amountIn, address uiFeeReceiver) external view returns (uint256, int256, SwapPricingUtils.SwapFees memory fees)
**Example (TypeScript / ethers):**
const [amountOut, impactAmount, fees] = await reader.getSwapAmountOut( dataStore.address, market, prices, tokenIn, amountIn, ethers.constants.AddressZero);
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `market` | `Market.Props` | Market to route the swap through |
| `prices` | `MarketUtils.MarketPrices` | Current prices for the index, long, and short tokens |
| `tokenIn` | `address` | Address of the input token |
| `amountIn` | `uint256` | Amount of the input token |
| `uiFeeReceiver` | `address` | Address of the UI fee receiver. Pass the zero address if not applicable. |
**Returns:** A tuple of `(uint256 amountOut, int256 impactAmount, SwapPricingUtils.SwapFees fees)` — the output token amount, price impact amount, and fee breakdown.
Output amount for deposits[](https://docs.gmx.io/docs/api/contracts/reader/#output-amount-for-deposits "Direct link to Output amount for deposits")
-----------------------------------------------------------------------------------------------------------------------------------------------------
Use `Reader.getDepositAmountOut` to estimate how many GM tokens you receive for a deposit.
### Reader.getDepositAmountOut[](https://docs.gmx.io/docs/api/contracts/reader/#readergetdepositamountout "Direct link to Reader.getDepositAmountOut")
function getDepositAmountOut( DataStore dataStore, Market.Props memory market, MarketUtils.MarketPrices memory prices, uint256 longTokenAmount, uint256 shortTokenAmount, address uiFeeReceiver, ISwapPricingUtils.SwapPricingType swapPricingType, bool includeVirtualInventoryImpact) external view returns (uint256)
**Example (TypeScript / ethers):**
const marketTokensOut = await reader.getDepositAmountOut( dataStore.address, market, prices, longTokenAmount, shortTokenAmount, ethers.constants.AddressZero, swapPricingType, true);
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `market` | `Market.Props` | The market to deposit into |
| `prices` | `MarketUtils.MarketPrices` | Current prices for the index, long, and short tokens |
| `longTokenAmount` | `uint256` | Amount of the long token to deposit |
| `shortTokenAmount` | `uint256` | Amount of the short token to deposit |
| `uiFeeReceiver` | `address` | Address of the UI fee receiver. Pass the zero address if not applicable. |
| `swapPricingType` | `ISwapPricingUtils.SwapPricingType` | Pricing method to use for the internal swap component of the deposit |
| `includeVirtualInventoryImpact` | `bool` | Pass `true` to include virtual inventory impact in the price impact calculation |
**Returns:** `uint256` — the estimated number of GM tokens minted.
Output amount for withdrawals[](https://docs.gmx.io/docs/api/contracts/reader/#output-amount-for-withdrawals "Direct link to Output amount for withdrawals")
--------------------------------------------------------------------------------------------------------------------------------------------------------------
Use `Reader.getWithdrawalAmountOut` to estimate how many long and short tokens you receive when withdrawing GM tokens.
### Reader.getWithdrawalAmountOut[](https://docs.gmx.io/docs/api/contracts/reader/#readergetwithdrawalamountout "Direct link to Reader.getWithdrawalAmountOut")
function getWithdrawalAmountOut( DataStore dataStore, Market.Props memory market, MarketUtils.MarketPrices memory prices, uint256 marketTokenAmount, address uiFeeReceiver, ISwapPricingUtils.SwapPricingType swapPricingType) external view returns (uint256, uint256)
**Example (TypeScript / ethers):**
const [longTokenAmountOut, shortTokenAmountOut] = await reader.getWithdrawalAmountOut( dataStore.address, market, prices, marketTokenAmount, ethers.constants.AddressZero, swapPricingType);
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `market` | `Market.Props` | The market to withdraw from |
| `prices` | `MarketUtils.MarketPrices` | Current prices for the index, long, and short tokens |
| `marketTokenAmount` | `uint256` | Amount of GM tokens to burn |
| `uiFeeReceiver` | `address` | Address of the UI fee receiver. Pass the zero address if not applicable. |
| `swapPricingType` | `ISwapPricingUtils.SwapPricingType` | Pricing method to use for the internal swap component of the withdrawal |
**Returns:** A tuple of `(uint256 longTokenAmount, uint256 shortTokenAmount)` — the estimated amounts of long and short tokens returned.
Direct lookups[](https://docs.gmx.io/docs/api/contracts/reader/#direct-lookups "Direct link to Direct lookups")
-----------------------------------------------------------------------------------------------------------------
Use these methods when you already have a key, salt, or account and want the raw stored value without additional pricing or fee calculations.
### Reader.getMarket[](https://docs.gmx.io/docs/api/contracts/reader/#readergetmarket "Direct link to Reader.getMarket")
function getMarket(DataStore dataStore, address key) external view returns (Market.Props memory)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `key` | `address` | Market token address used as the market key |
**Returns:** `Market.Props` for the requested market.
### Reader.getMarketBySalt[](https://docs.gmx.io/docs/api/contracts/reader/#readergetmarketbysalt "Direct link to Reader.getMarketBySalt")
function getMarketBySalt(DataStore dataStore, bytes32 salt) external view returns (Market.Props memory)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `salt` | `bytes32` | Deterministic market deployment salt |
**Returns:** `Market.Props` for the requested market.
### Reader.getDeposit[](https://docs.gmx.io/docs/api/contracts/reader/#readergetdeposit "Direct link to Reader.getDeposit")
function getDeposit(DataStore dataStore, bytes32 key) external view returns (Deposit.Props memory)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `key` | `bytes32` | Deposit request key |
**Returns:** Raw `Deposit.Props` for the requested deposit.
### Reader.getWithdrawal[](https://docs.gmx.io/docs/api/contracts/reader/#readergetwithdrawal "Direct link to Reader.getWithdrawal")
function getWithdrawal(DataStore dataStore, bytes32 key) external view returns (Withdrawal.Props memory)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `key` | `bytes32` | Withdrawal request key |
**Returns:** Raw `Withdrawal.Props` for the requested withdrawal.
### Reader.getShift[](https://docs.gmx.io/docs/api/contracts/reader/#readergetshift "Direct link to Reader.getShift")
function getShift(DataStore dataStore, bytes32 key) external view returns (Shift.Props memory)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `key` | `bytes32` | Shift request key |
**Returns:** Raw `Shift.Props` for the requested shift.
### Reader.getPosition[](https://docs.gmx.io/docs/api/contracts/reader/#readergetposition "Direct link to Reader.getPosition")
function getPosition(DataStore dataStore, bytes32 key) external view returns (Position.Props memory)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `key` | `bytes32` | Position key |
**Returns:** Raw `Position.Props` for the requested position.
### Reader.getOrder[](https://docs.gmx.io/docs/api/contracts/reader/#readergetorder "Direct link to Reader.getOrder")
function getOrder(DataStore dataStore, bytes32 key) external view returns (Order.Props memory)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `key` | `bytes32` | Order key |
**Returns:** Raw `Order.Props` for the requested order.
Account and position state helpers[](https://docs.gmx.io/docs/api/contracts/reader/#account-and-position-state-helpers "Direct link to Account and position state helpers")
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Use these methods when you need raw account orders, PnL diagnostics, or liquidation checks rather than the higher-level position info helpers above.
### Reader.getPositionPnlUsd[](https://docs.gmx.io/docs/api/contracts/reader/#readergetpositionpnlusd "Direct link to Reader.getPositionPnlUsd")
function getPositionPnlUsd( DataStore dataStore, Market.Props memory market, MarketUtils.MarketPrices memory prices, bytes32 positionKey, uint256 sizeDeltaUsd) external view returns (int256, int256, uint256)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `market` | `Market.Props` | Market for the position |
| `prices` | `MarketUtils.MarketPrices` | Current prices for the market |
| `positionKey` | `bytes32` | Position key |
| `sizeDeltaUsd` | `uint256` | Position size delta to evaluate when computing PnL |
**Returns:** A tuple of `(positionPnlUsd, cappedPositionPnlUsd, sizeDeltaInTokens)`.
### Reader.isPositionLiquidatable[](https://docs.gmx.io/docs/api/contracts/reader/#readerispositionliquidatable "Direct link to Reader.isPositionLiquidatable")
function isPositionLiquidatable( DataStore dataStore, IReferralStorage referralStorage, bytes32 positionKey, Market.Props memory market, MarketUtils.MarketPrices memory prices, bool shouldValidateMinCollateralUsd, bool forLiquidation) public view returns (bool, string memory, PositionUtils.IsPositionLiquidatableInfo memory)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `referralStorage` | `address` | Address of the ReferralStorage contract |
| `positionKey` | `bytes32` | Position key |
| `market` | `Market.Props` | Market for the position |
| `prices` | `MarketUtils.MarketPrices` | Current prices for the market |
| `shouldValidateMinCollateralUsd` | `bool` | Whether to enforce the minimum collateral USD checks |
| `forLiquidation` | `bool` | Pass `true` when checking liquidation conditions, `false` for a soft check |
**Returns:** A tuple of `(isLiquidatable, reason, info)` with the liquidation result, reason string, and detailed diagnostics.
### Reader.getAccountOrders[](https://docs.gmx.io/docs/api/contracts/reader/#readergetaccountorders "Direct link to Reader.getAccountOrders")
function getAccountOrders( DataStore dataStore, address account, uint256 start, uint256 end) external view returns (ReaderUtils.OrderInfo[] memory)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `account` | `address` | Account to retrieve orders for |
| `start` | `uint256` | Start index for pagination |
| `end` | `uint256` | End index for pagination |
**Returns:** Array of `ReaderUtils.OrderInfo` values for the account.
Market state and PnL helpers[](https://docs.gmx.io/docs/api/contracts/reader/#market-state-and-pnl-helpers "Direct link to Market state and PnL helpers")
-----------------------------------------------------------------------------------------------------------------------------------------------------------
Use these methods when you need one-market diagnostics without going through the paginated market list helpers.
### Reader.getMarketInfo[](https://docs.gmx.io/docs/api/contracts/reader/#readergetmarketinfo "Direct link to Reader.getMarketInfo")
function getMarketInfo( DataStore dataStore, MarketUtils.MarketPrices memory prices, address marketKey) public view returns (ReaderUtils.MarketInfo memory)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `prices` | `MarketUtils.MarketPrices` | Current prices for the market |
| `marketKey` | `address` | Market token address |
**Returns:** `ReaderUtils.MarketInfo` for the requested market.
### Reader.getPendingPositionImpactPoolDistributionAmount[](https://docs.gmx.io/docs/api/contracts/reader/#readergetpendingpositionimpactpooldistributionamount "Direct link to Reader.getPendingPositionImpactPoolDistributionAmount")
function getPendingPositionImpactPoolDistributionAmount( DataStore dataStore, address market) external view returns (uint256, uint256)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `market` | `address` | Market token address |
**Returns:** A tuple of pending long-token and short-token impact pool distribution amounts.
### Reader.getNetPnl[](https://docs.gmx.io/docs/api/contracts/reader/#readergetnetpnl "Direct link to Reader.getNetPnl")
function getNetPnl( DataStore dataStore, Market.Props memory market, Price.Props memory indexTokenPrice, bool maximize) external view returns (int256)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `market` | `Market.Props` | Market to evaluate |
| `indexTokenPrice` | `Price.Props` | Index token price range |
| `maximize` | `bool` | Whether to use the maximizing price path |
**Returns:** Net market PnL as an `int256`.
### Reader.getPnl[](https://docs.gmx.io/docs/api/contracts/reader/#readergetpnl "Direct link to Reader.getPnl")
function getPnl( DataStore dataStore, Market.Props memory market, Price.Props memory indexTokenPrice, bool isLong, bool maximize) external view returns (int256)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `market` | `Market.Props` | Market to evaluate |
| `indexTokenPrice` | `Price.Props` | Index token price range |
| `isLong` | `bool` | Pass `true` for long-side PnL |
| `maximize` | `bool` | Whether to use the maximizing price path |
**Returns:** Long-side or short-side PnL as an `int256`.
### Reader.getOpenInterestWithPnl[](https://docs.gmx.io/docs/api/contracts/reader/#readergetopeninterestwithpnl "Direct link to Reader.getOpenInterestWithPnl")
function getOpenInterestWithPnl( DataStore dataStore, Market.Props memory market, Price.Props memory indexTokenPrice, bool isLong, bool maximize) external view returns (int256)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `market` | `Market.Props` | Market to evaluate |
| `indexTokenPrice` | `Price.Props` | Index token price range |
| `isLong` | `bool` | Pass `true` for long-side open interest |
| `maximize` | `bool` | Whether to use the maximizing price path |
**Returns:** Open interest with PnL included, as an `int256`.
### Reader.getPnlToPoolFactor[](https://docs.gmx.io/docs/api/contracts/reader/#readergetpnltopoolfactor "Direct link to Reader.getPnlToPoolFactor")
function getPnlToPoolFactor( DataStore dataStore, address marketAddress, MarketUtils.MarketPrices memory prices, bool isLong, bool maximize) external view returns (int256)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `marketAddress` | `address` | Market token address |
| `prices` | `MarketUtils.MarketPrices` | Current prices for the market |
| `isLong` | `bool` | Pass `true` for the long side |
| `maximize` | `bool` | Whether to use the maximizing price path |
**Returns:** Current PnL-to-pool factor as an `int256`.
Pricing and risk helpers[](https://docs.gmx.io/docs/api/contracts/reader/#pricing-and-risk-helpers "Direct link to Pricing and risk helpers")
-----------------------------------------------------------------------------------------------------------------------------------------------
Use these methods when you need direct swap-impact or ADL diagnostics without calling the larger quote helpers.
### Reader.getSwapPriceImpact[](https://docs.gmx.io/docs/api/contracts/reader/#readergetswappriceimpact "Direct link to Reader.getSwapPriceImpact")
function getSwapPriceImpact( DataStore dataStore, address marketKey, address tokenIn, address tokenOut, uint256 amountIn, Price.Props memory tokenInPrice, Price.Props memory tokenOutPrice) external view returns (int256, int256, int256)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `marketKey` | `address` | Market token address |
| `tokenIn` | `address` | Input token address |
| `tokenOut` | `address` | Output token address |
| `amountIn` | `uint256` | Input token amount |
| `tokenInPrice` | `Price.Props` | Input token price range |
| `tokenOutPrice` | `Price.Props` | Output token price range |
**Returns:** A tuple of swap price impact values as signed integers.
### Reader.getAdlState[](https://docs.gmx.io/docs/api/contracts/reader/#readergetadlstate "Direct link to Reader.getAdlState")
function getAdlState( DataStore dataStore, address market, bool isLong, MarketUtils.MarketPrices memory prices) external view returns (uint256, bool, int256, uint256)
**Parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `dataStore` | `address` | Address of the DataStore contract |
| `market` | `address` | Market token address |
| `isLong` | `bool` | Pass `true` for the long side |
| `prices` | `MarketUtils.MarketPrices` | Current prices for the market |
**Returns:** A tuple describing the ADL state, including the ADL phase, whether ADL is enabled, the PnL factor, and the minimum PnL factor for ADL.
* [Market list](https://docs.gmx.io/docs/api/contracts/reader/#market-list)
* [Reader.getMarkets](https://docs.gmx.io/docs/api/contracts/reader/#readergetmarkets)
* [Market.Props](https://docs.gmx.io/docs/api/contracts/reader/#marketprops)
* [Detailed market list](https://docs.gmx.io/docs/api/contracts/reader/#detailed-market-list)
* [Reader.getMarketInfoList](https://docs.gmx.io/docs/api/contracts/reader/#readergetmarketinfolist)
* [MarketUtils.MarketPrices](https://docs.gmx.io/docs/api/contracts/reader/#marketutilsmarketprices)
* [Price.Props](https://docs.gmx.io/docs/api/contracts/reader/#priceprops)
* [Getting GM token price](https://docs.gmx.io/docs/api/contracts/reader/#getting-gm-token-price)
* [Reader.getMarketTokenPrice](https://docs.gmx.io/docs/api/contracts/reader/#readergetmarkettokenprice)
* [Position list](https://docs.gmx.io/docs/api/contracts/reader/#position-list)
* [Reader.getAccountPositions](https://docs.gmx.io/docs/api/contracts/reader/#readergetaccountpositions)
* [Detailed position list](https://docs.gmx.io/docs/api/contracts/reader/#detailed-position-list)
* [Reader.getAccountPositionInfoList](https://docs.gmx.io/docs/api/contracts/reader/#readergetaccountpositioninfolist)
* [Position information](https://docs.gmx.io/docs/api/contracts/reader/#position-information)
* [Reader.getPositionInfo](https://docs.gmx.io/docs/api/contracts/reader/#readergetpositioninfo)
* [Detailed position list by key](https://docs.gmx.io/docs/api/contracts/reader/#detailed-position-list-by-key)
* [Reader.getPositionInfoList](https://docs.gmx.io/docs/api/contracts/reader/#readergetpositioninfolist)
* [Execution price for increasing or decreasing a position](https://docs.gmx.io/docs/api/contracts/reader/#execution-price-for-increasing-or-decreasing-a-position)
* [Reader.getExecutionPrice](https://docs.gmx.io/docs/api/contracts/reader/#readergetexecutionprice)
* [Output amount for swaps](https://docs.gmx.io/docs/api/contracts/reader/#output-amount-for-swaps)
* [Reader.getSwapAmountOut](https://docs.gmx.io/docs/api/contracts/reader/#readergetswapamountout)
* [Output amount for deposits](https://docs.gmx.io/docs/api/contracts/reader/#output-amount-for-deposits)
* [Reader.getDepositAmountOut](https://docs.gmx.io/docs/api/contracts/reader/#readergetdepositamountout)
* [Output amount for withdrawals](https://docs.gmx.io/docs/api/contracts/reader/#output-amount-for-withdrawals)
* [Reader.getWithdrawalAmountOut](https://docs.gmx.io/docs/api/contracts/reader/#readergetwithdrawalamountout)
* [Direct lookups](https://docs.gmx.io/docs/api/contracts/reader/#direct-lookups)
* [Reader.getMarket](https://docs.gmx.io/docs/api/contracts/reader/#readergetmarket)
* [Reader.getMarketBySalt](https://docs.gmx.io/docs/api/contracts/reader/#readergetmarketbysalt)
* [Reader.getDeposit](https://docs.gmx.io/docs/api/contracts/reader/#readergetdeposit)
* [Reader.getWithdrawal](https://docs.gmx.io/docs/api/contracts/reader/#readergetwithdrawal)
* [Reader.getShift](https://docs.gmx.io/docs/api/contracts/reader/#readergetshift)
* [Reader.getPosition](https://docs.gmx.io/docs/api/contracts/reader/#readergetposition)
* [Reader.getOrder](https://docs.gmx.io/docs/api/contracts/reader/#readergetorder)
* [Account and position state helpers](https://docs.gmx.io/docs/api/contracts/reader/#account-and-position-state-helpers)
* [Reader.getPositionPnlUsd](https://docs.gmx.io/docs/api/contracts/reader/#readergetpositionpnlusd)
* [Reader.isPositionLiquidatable](https://docs.gmx.io/docs/api/contracts/reader/#readerispositionliquidatable)
* [Reader.getAccountOrders](https://docs.gmx.io/docs/api/contracts/reader/#readergetaccountorders)
* [Market state and PnL helpers](https://docs.gmx.io/docs/api/contracts/reader/#market-state-and-pnl-helpers)
* [Reader.getMarketInfo](https://docs.gmx.io/docs/api/contracts/reader/#readergetmarketinfo)
* [Reader.getPendingPositionImpactPoolDistributionAmount](https://docs.gmx.io/docs/api/contracts/reader/#readergetpendingpositionimpactpooldistributionamount)
* [Reader.getNetPnl](https://docs.gmx.io/docs/api/contracts/reader/#readergetnetpnl)
* [Reader.getPnl](https://docs.gmx.io/docs/api/contracts/reader/#readergetpnl)
* [Reader.getOpenInterestWithPnl](https://docs.gmx.io/docs/api/contracts/reader/#readergetopeninterestwithpnl)
* [Reader.getPnlToPoolFactor](https://docs.gmx.io/docs/api/contracts/reader/#readergetpnltopoolfactor)
* [Pricing and risk helpers](https://docs.gmx.io/docs/api/contracts/reader/#pricing-and-risk-helpers)
* [Reader.getSwapPriceImpact](https://docs.gmx.io/docs/api/contracts/reader/#readergetswappriceimpact)
* [Reader.getAdlState](https://docs.gmx.io/docs/api/contracts/reader/#readergetadlstate)
---
# Simulations | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/contracts/simulations/#__docusaurus_skipToContent_fallback)
On this page
The `ExchangeRouter` and `GlvRouter` contracts expose public simulation functions that let you dry-run an execution against a set of supplied prices before submitting a real request for keeper execution. Running a simulation catches validation errors — such as price impact limits or insufficient output amounts — without spending gas on a failed transaction.
For the full `CreateOrderParams` and `CreateDepositParams` structures, see [ExchangeRouter](https://docs.gmx.io/docs/api/contracts/exchange-router/)
. For contract addresses, see [Contract addresses](https://docs.gmx.io/docs/api/contracts/addresses/)
.
How simulations work[](https://docs.gmx.io/docs/api/contracts/simulations/#how-simulations-work "Direct link to How simulations work")
----------------------------------------------------------------------------------------------------------------------------------------
Simulation functions use the `withSimulatedOraclePrices` modifier in `OracleModule`. The modifier injects synthetic price data into the oracle, executes the handler logic through the router/controller path, then unconditionally reverts with `EndOfOracleSimulation`. Because the transaction always reverts, no state changes are persisted.
The caller interprets the revert reason: if the error is `EndOfOracleSimulation`, the simulation succeeded and the supplied prices passed validation. Any other revert reason indicates an error that would also occur on-chain. In practice, this is a preflight tool for users and integrators; actual request execution is still performed by keeper-only handler functions.
In practice, simulations are usually called in the same `multicall` flow that creates the request. You create the deposit, withdrawal, or order first, then call the corresponding `simulateExecuteLatest...` function with the prices you want to test against.
**Example (TypeScript / ethers):**
const currentTimestamp = (await provider.getBlock("latest")).timestamp + 2;await expect( exchangeRouter.multicall( [ exchangeRouter.interface.encodeFunctionData("sendWnt", [depositVault.address, executionFee]), exchangeRouter.interface.encodeFunctionData("sendTokens", [usdc.address, depositVault.address, shortTokenAmount]), exchangeRouter.interface.encodeFunctionData("createDeposit", [depositParams]), exchangeRouter.interface.encodeFunctionData("simulateExecuteLatestDeposit", [ { primaryTokens: [wnt.address, usdc.address], primaryPrices: [ { min: wethPrice, max: wethPrice }, { min: usdcPrice, max: usdcPrice }, ], minTimestamp: currentTimestamp, maxTimestamp: currentTimestamp, }, ]), ], { value: executionFee } )).to.be.revertedWithCustomError(errorsContract, "EndOfOracleSimulation");
If the call reverts with `EndOfOracleSimulation`, the simulated execution passed. If it reverts with any other error, treat that as the actual validation error for the supplied prices.
Available simulation functions[](https://docs.gmx.io/docs/api/contracts/simulations/#available-simulation-functions "Direct link to Available simulation functions")
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
The latest-request helpers use the latest created request key. In practice, call the simulation immediately after creating the request in the same `multicall`, so it targets the action you just created.
### ExchangeRouter functions[](https://docs.gmx.io/docs/api/contracts/simulations/#exchangerouter-functions "Direct link to ExchangeRouter functions")
| Function | Action type |
| --- | --- |
| `simulateExecuteLatestDeposit(SimulatePricesParams)` | GM deposit |
| `simulateExecuteLatestWithdrawal(SimulatePricesParams, SwapPricingType)` | GM withdrawal |
| `simulateExecuteLatestShift(SimulatePricesParams)` | GM pool shift |
| `simulateExecuteLatestOrder(SimulatePricesParams)` | Perpetual or swap order |
| `simulateExecuteLatestJitOrder(GlvShiftUtils.CreateGlvShiftParams[], SimulatePricesParams)` | JIT order |
### GlvRouter functions[](https://docs.gmx.io/docs/api/contracts/simulations/#glvrouter-functions "Direct link to GlvRouter functions")
| Function | Action type |
| --- | --- |
| `simulateExecuteGlvDeposit(bytes32, SimulatePricesParams)` | GLV deposit by explicit key |
| `simulateExecuteLatestGlvDeposit(SimulatePricesParams)` | Latest GLV deposit |
| `simulateExecuteGlvWithdrawal(bytes32, SimulatePricesParams)` | GLV withdrawal by explicit key |
| `simulateExecuteLatestGlvWithdrawal(SimulatePricesParams)` | Latest GLV withdrawal |
SimulatePricesParams[](https://docs.gmx.io/docs/api/contracts/simulations/#simulatepricesparams "Direct link to SimulatePricesParams")
----------------------------------------------------------------------------------------------------------------------------------------
struct SimulatePricesParams { address[] primaryTokens; // token addresses to price Price.Props[] primaryPrices; // { min, max } price for each token uint256 minTimestamp; // lower bound of the price window uint256 maxTimestamp; // upper bound of the price window}
Supply current oracle prices for all tokens involved in the action. The `minTimestamp` and `maxTimestamp` fields must bracket the expected execution timestamp; a common pattern is to set both to `block.timestamp + 120`.
### Field notes[](https://docs.gmx.io/docs/api/contracts/simulations/#field-notes "Direct link to Field notes")
| Field | Description |
| --- | --- |
| `primaryTokens` | Token addresses to assign simulated prices to. Include every token the action depends on. |
| `primaryPrices` | Simulated oracle prices for each token, in the same order as `primaryTokens`. Each price uses `{ min, max }`. |
| `minTimestamp` | Lower bound for the simulated oracle timestamp window. |
| `maxTimestamp` | Upper bound for the simulated oracle timestamp window. |
* [How simulations work](https://docs.gmx.io/docs/api/contracts/simulations/#how-simulations-work)
* [Available simulation functions](https://docs.gmx.io/docs/api/contracts/simulations/#available-simulation-functions)
* [ExchangeRouter functions](https://docs.gmx.io/docs/api/contracts/simulations/#exchangerouter-functions)
* [GlvRouter functions](https://docs.gmx.io/docs/api/contracts/simulations/#glvrouter-functions)
* [SimulatePricesParams](https://docs.gmx.io/docs/api/contracts/simulations/#simulatepricesparams)
* [Field notes](https://docs.gmx.io/docs/api/contracts/simulations/#field-notes)
---
# GetAnnualized | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/gmx-api/get-annualized/#__docusaurus_skipToContent_fallback)
GetAnnualized
=============
GET
/performance/annualized
-----------------------
GetAnnualized
Request[](https://docs.gmx.io/docs/api/gmx-api/get-annualized/#request "Direct link to request")
--------------------------------------------------------------------------------------------------
Responses[](https://docs.gmx.io/docs/api/gmx-api/get-annualized/#responses "Direct link to Responses")
--------------------------------------------------------------------------------------------------------
* 200
* 400
* 500
Success
Invalid period
Internal Server Error
---
# GetApy | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/gmx-api/get-apy/#__docusaurus_skipToContent_fallback)
GetApy
======
GET
https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/api/v1/apy
------------------------------------------------------------
GetApy
Request[](https://docs.gmx.io/docs/api/gmx-api/get-apy/#request "Direct link to request")
-------------------------------------------------------------------------------------------
### Query Parameters
**period** ApiParameterPeriod
**Possible values:** \[`1d`, `7d`, `30d`, `90d`, `180d`, `1y`, `total`\]
Responses[](https://docs.gmx.io/docs/api/gmx-api/get-apy/#responses "Direct link to Responses")
-------------------------------------------------------------------------------------------------
* 200
* 400
* 500
Success
* application/json
* Schema
* Example (auto)
**Schema**
**glvs** objectrequired
Construct a type with a set of properties K of type T
object
**property name\*** ApyEntry
**bonusApr**numberrequired
**baseApy**numberrequired
**apy**numberrequired
**markets** objectrequired
Construct a type with a set of properties K of type T
object
**property name\*** ApyEntry
**bonusApr**numberrequired
**baseApy**numberrequired
**apy**numberrequired
{ "glvs": {}, "markets": {}}
Invalid period
Internal Server Error
* python
* nodejs
* curl
* HTTP.CLIENT
* REQUESTS
import requestsurl = "https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/api/v1/apy"payload = {}headers = { 'Accept': 'application/json'}response = requests.request("GET", url, headers=headers, data=payload)print(response.text)
RequestCollapse all
Base URL
Edit
https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/api/v1
ParametersShow optional parameters
period — query
\---1d7d30d90d180d1ytotal
---
# GetPositionsInfo | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/gmx-api/get-positions-info/#__docusaurus_skipToContent_fallback)
GetPositionsInfo
================
GET
https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/api/v1/positions
------------------------------------------------------------------
GetPositionsInfo
Request[](https://docs.gmx.io/docs/api/gmx-api/get-positions-info/#request "Direct link to request")
------------------------------------------------------------------------------------------------------
### Query Parameters
**address** stringrequired
**includeRelatedOrders** boolean
Responses[](https://docs.gmx.io/docs/api/gmx-api/get-positions-info/#responses "Direct link to Responses")
------------------------------------------------------------------------------------------------------------
* 200
* 400
* 500
Success
* application/json
* Schema
* Example (auto)
**Schema**
* Array \[\
\
\
**relatedOrders** object\[\]\
\
* Array \[\
\
\
**dataList**string\[\]required\
\
**autoCancel**booleanrequired\
\
**isFrozen**booleanrequired\
\
**shouldUnwrapNativeToken**booleanrequired\
\
**isLong**booleanrequired\
\
**srcChainId**stringrequired\
\
**validFromTime**stringrequired\
\
**updatedAtTime**stringrequired\
\
**minOutputAmount**stringrequired\
\
**callbackGasLimit**stringrequired\
\
**executionFee**stringrequired\
\
**acceptablePrice**stringrequired\
\
**triggerPrice**stringrequired\
\
**initialCollateralDeltaAmount**stringrequired\
\
**sizeDeltaUsd**stringrequired\
\
**decreasePositionSwapType**numberrequired\
\
**orderType**numberrequired\
\
**swapPath**string\[\]required\
\
**initialCollateralTokenAddress**stringrequired\
\
**marketAddress**stringrequired\
\
**uiFeeReceiver**stringrequired\
\
**callbackContract**stringrequired\
\
**cancellationReceiver**stringrequired\
\
**receiver**stringrequired\
\
**account**stringrequired\
\
**key**stringrequired\
\
* \]\
\
\
**pendingClaimableFundingFeesUsd**stringrequired\
\
**pendingFundingFeesUsd**stringrequired\
\
**uiFeeUsd**stringrequired\
\
**closingFeeUsd**stringrequired\
\
**netValue**stringrequired\
\
**leverageWithoutPnl**string\
\
**leverageWithPnl**string\
\
**leverage**string\
\
**closePriceImpactDeltaUsd**stringrequired\
\
**pendingImpactUsd**stringrequired\
\
**priceImpactDiffUsd**stringrequired\
\
**netPriceImapctDeltaUsd**stringrequired\
\
**pnlAfterFeesPercentage**stringrequired\
\
**pnlAfterFees**stringrequired\
\
**pnlPercentage**stringrequired\
\
**hasLowCollateral**booleanrequired\
\
**remainingCollateralAmount**stringrequired\
\
**remainingCollateralUsd**stringrequired\
\
**collateralUsd**stringrequired\
\
**liquidationPrice**string\
\
**entryPrice**string\
\
**markPrice**stringrequired\
\
**poolName**stringrequired\
\
**indexName**stringrequired\
\
**data**stringrequired\
\
**pendingImpactAmount**stringrequired\
\
**uiFeeAmount**stringrequired\
\
**traderDiscountAmount**stringrequired\
\
**positionFeeAmount**stringrequired\
\
**pnl**stringrequired\
\
**isOpening**boolean\
\
**claimableShortTokenAmount**stringrequired\
\
**claimableLongTokenAmount**stringrequired\
\
**fundingFeeAmount**stringrequired\
\
**isLong**booleanrequired\
\
**decreasedAtTime**stringrequired\
\
**increasedAtTime**stringrequired\
\
**pendingBorrowingFeesUsd**stringrequired\
\
**collateralAmount**stringrequired\
\
**sizeInTokens**stringrequired\
\
**sizeInUsd**stringrequired\
\
**collateralTokenAddress**stringrequired\
\
**marketAddress**stringrequired\
\
**account**stringrequired\
\
**contractKey**stringrequired\
\
**key**stringrequired\
\
* \]
[ { "relatedOrders": [ { "dataList": [ "string" ], "autoCancel": true, "isFrozen": true, "shouldUnwrapNativeToken": true, "isLong": true, "srcChainId": "string", "validFromTime": "string", "updatedAtTime": "string", "minOutputAmount": "string", "callbackGasLimit": "string", "executionFee": "string", "acceptablePrice": "string", "triggerPrice": "string", "initialCollateralDeltaAmount": "string", "sizeDeltaUsd": "string", "decreasePositionSwapType": 0, "orderType": 0, "swapPath": [ "string" ], "initialCollateralTokenAddress": "string", "marketAddress": "string", "uiFeeReceiver": "string", "callbackContract": "string", "cancellationReceiver": "string", "receiver": "string", "account": "string", "key": "string" } ], "pendingClaimableFundingFeesUsd": "string", "pendingFundingFeesUsd": "string", "uiFeeUsd": "string", "closingFeeUsd": "string", "netValue": "string", "leverageWithoutPnl": "string", "leverageWithPnl": "string", "leverage": "string", "closePriceImpactDeltaUsd": "string", "pendingImpactUsd": "string", "priceImpactDiffUsd": "string", "netPriceImapctDeltaUsd": "string", "pnlAfterFeesPercentage": "string", "pnlAfterFees": "string", "pnlPercentage": "string", "hasLowCollateral": true, "remainingCollateralAmount": "string", "remainingCollateralUsd": "string", "collateralUsd": "string", "liquidationPrice": "string", "entryPrice": "string", "markPrice": "string", "poolName": "string", "indexName": "string", "data": "string", "pendingImpactAmount": "string", "uiFeeAmount": "string", "traderDiscountAmount": "string", "positionFeeAmount": "string", "pnl": "string", "isOpening": true, "claimableShortTokenAmount": "string", "claimableLongTokenAmount": "string", "fundingFeeAmount": "string", "isLong": true, "decreasedAtTime": "string", "increasedAtTime": "string", "pendingBorrowingFeesUsd": "string", "collateralAmount": "string", "sizeInTokens": "string", "sizeInUsd": "string", "collateralTokenAddress": "string", "marketAddress": "string", "account": "string", "contractKey": "string", "key": "string" }]
Bad Request - Invalid address
Internal Server Error
* python
* nodejs
* curl
* HTTP.CLIENT
* REQUESTS
import requestsurl = "https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/api/v1/positions"payload = {}headers = { 'Accept': 'application/json'}response = requests.request("GET", url, headers=headers, data=payload)print(response.text)
RequestCollapse all
Base URL
Edit
https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/api/v1
Parameters
address — queryrequired
Show optional parameters
includeRelatedOrders — query
\---truefalse
---
# GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/gmx-api/get-rates/#__docusaurus_skipToContent_fallback)
GetRates
========
GET
/rates
------
GetRates
Request[](https://docs.gmx.io/docs/api/gmx-api/get-rates/#request "Direct link to request")
---------------------------------------------------------------------------------------------
Responses[](https://docs.gmx.io/docs/api/gmx-api/get-rates/#responses "Direct link to Responses")
---------------------------------------------------------------------------------------------------
* 200
* 400
* 500
Success
Invalid period or averageBy
Internal Server Error
---
# GMX Docs
[Skip to main content](https://docs.gmx.io/docs/archived/liquidity-v1/#__docusaurus_skipToContent_fallback)
On this page
GLP was the liquidity provider token for V1. Since July 2025, GLP has been phased out and no longer provides liquidity as V1 trading is disabled, so buying GLP tokens is no longer possible. You may only redeem existing GLP via the [sell GLP](https://v1.app.gmx.io/#/sell_glp)
page.
If you have been holding GLP, you may have claims available, please check [distributions section](https://app.gmx.io/#/earn/distributions)
for any claims.
GLP Token Addresses[](https://docs.gmx.io/docs/archived/liquidity-v1/#glp-token-addresses "Direct link to GLP Token Addresses")
---------------------------------------------------------------------------------------------------------------------------------
* Arbitrum: [0x1aDDD80E6039594eE970E5872D247bf0414C8903](https://arbiscan.io/token/0x1aDDD80E6039594eE970E5872D247bf0414C8903)
* Avalanche: [0x9e295B5B976a184B14aD8cd72413aD846C299660](https://snowtrace.io/address/0x9e295B5B976a184B14aD8cd72413aD846C299660)
* [GLP Token Addresses](https://docs.gmx.io/docs/archived/liquidity-v1/#glp-token-addresses)
---
# GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/overview/#__docusaurus_skipToContent_fallback)
On this page
GMX exposes several integration points for developers, integrators, and AI agents building on the protocol. Start with the integration surface that matches your task instead of trying to use one API for everything.
For AI agent frameworks with pre-built trading skills, see [AI Agents](https://docs.gmx.io/docs/ai-agents/overview/)
.
Available APIs[](https://docs.gmx.io/docs/api/overview/#available-apis "Direct link to Available APIs")
---------------------------------------------------------------------------------------------------------
GMX offers four integration points depending on the type of data or action you need.
### REST APIs[](https://docs.gmx.io/docs/api/overview/#rest-apis "Direct link to REST APIs")
GMX provides two REST API generations. API v2 is under active development and will become the primary HTTP integration point.
| | API v1 — [REST API](https://docs.gmx.io/docs/category/api-v1-rest-api/) | API v2 — [OpenAPI Reference](https://docs.gmx.io/docs/category/api-v2-openapi-reference/) |
| --- | --- | --- |
| **Base URLs** | `gmxinfra.io` | `gmx-api-*.ondigitalocean.app` |
| **Data** | Oracle prices, markets, liquidity | Markets, tickers, tokens, positions, orders, rates, APY, and performance |
| **Status** | Stable | Expanding — will become the primary HTTP API |
### Other integration points[](https://docs.gmx.io/docs/api/overview/#other-integration-points "Direct link to Other integration points")
* **[Contracts](https://docs.gmx.io/docs/category/contracts/)
** — Interact directly with ExchangeRouter, Reader, and GlvReader contracts on-chain.
* **[GraphQL](https://docs.gmx.io/docs/api/graphql/)
** — Historical on-chain data via Subsquid endpoints.
Start here[](https://docs.gmx.io/docs/api/overview/#start-here "Direct link to Start here")
---------------------------------------------------------------------------------------------
* **[Integration guide](https://docs.gmx.io/docs/api/integration-guide/)
** — "I want to do X" workflows, cache and retry guidance, and when to use REST, GraphQL, or the SDK
* **[Troubleshooting](https://docs.gmx.io/docs/api/troubleshooting/)
** — What to do when reads look stale, validation fails, or write-path state does not appear yet
* **[API v1 (REST API)](https://docs.gmx.io/docs/category/api-v1-rest-api/)
** — Manual docs for prices, markets, liquidity, and fallback URLs
* **[API v2 (OpenAPI Reference)](https://docs.gmx.io/docs/category/api-v2-openapi-reference/)
** — Generated endpoint schemas for the current API v2 read surface
TypeScript SDK[](https://docs.gmx.io/docs/api/overview/#typescript-sdk "Direct link to TypeScript SDK")
---------------------------------------------------------------------------------------------------------
The [`@gmx-io/sdk`](https://docs.gmx.io/docs/sdk/overview/)
package provides a high-level TypeScript interface that wraps these APIs. It ships two clients: **SDK v1** (`GmxSdk`) for full read/write access via RPC, and **SDK v2** (`GmxApiSdk`) for lightweight read-only access over HTTP. The current SDK v2 surface covers markets, tickers, tokens, pairs, rates, APY, performance, positions, orders, OHLCV, buyback stats, and staking power. See the [SDK docs](https://docs.gmx.io/docs/sdk/overview/)
for details.
The generated API v2 reference covers the current checked-in HTTP endpoints. The SDK pages document additional client coverage such as `fetchBuybackWeeklyStats()` and `fetchStakingPower()` that is available in code but not yet listed in the generated reference.
Supported networks[](https://docs.gmx.io/docs/api/overview/#supported-networks "Direct link to Supported networks")
---------------------------------------------------------------------------------------------------------------------
GMX V2 is deployed on the following networks.
* Arbitrum One
* Avalanche C-Chain
* Botanix
* MegaETH
Not every API surface is available on every deployed network. Check the specific REST, GraphQL, SDK, or generated API v2 page you plan to use before wiring a production integration.
For contract and API update announcements, see [Updates and Support](https://docs.gmx.io/docs/api/updates-support/)
.
AI agent integration[](https://docs.gmx.io/docs/api/overview/#ai-agent-integration "Direct link to AI agent integration")
---------------------------------------------------------------------------------------------------------------------------
GMX's oracle-based pricing and two-phase execution model make it well-suited for autonomous trading agents. For pre-built agent plugins that bundle SDK references, API endpoints, contract addresses, and order specifications, see the [AI Agents](https://docs.gmx.io/docs/ai-agents/overview/)
section. This documentation site also generates LLM-friendly bundles at [`llms.txt`](https://docs.gmx.io/llms.txt)
and [`llms-full.txt`](https://docs.gmx.io/llms-full.txt)
for direct model consumption.
* [Available APIs](https://docs.gmx.io/docs/api/overview/#available-apis)
* [REST APIs](https://docs.gmx.io/docs/api/overview/#rest-apis)
* [Other integration points](https://docs.gmx.io/docs/api/overview/#other-integration-points)
* [Start here](https://docs.gmx.io/docs/api/overview/#start-here)
* [TypeScript SDK](https://docs.gmx.io/docs/api/overview/#typescript-sdk)
* [Supported networks](https://docs.gmx.io/docs/api/overview/#supported-networks)
* [AI agent integration](https://docs.gmx.io/docs/api/overview/#ai-agent-integration)
---
# GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/integration-guide/#__docusaurus_skipToContent_fallback)
On this page
Use this page when you want exact integration steps. The hand-written API pages explain which surfaces exist and how they behave operationally. The API v2 OpenAPI reference is generated and is best used for endpoint schemas and response fields, not for workflow guidance. Use [Troubleshooting](https://docs.gmx.io/docs/api/troubleshooting/)
when reads do not match expected state.
Choose the right integration surface[](https://docs.gmx.io/docs/api/integration-guide/#choose-the-right-integration-surface "Direct link to Choose the right integration surface")
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Start by choosing the narrowest surface that solves your problem.
| Need | Recommended surface | Notes |
| --- | --- | --- |
| Live oracle prices, market snapshots, liquidity, and APY | [API v1 REST pages](https://docs.gmx.io/docs/category/api-v1-rest-api/) | Stable public HTTP endpoints on `gmxinfra.io` |
| Read markets, tickers, tokens, pairs, rates, APY, performance, positions, orders, OHLCV, buyback stats, or staking power over HTTP from TypeScript | [SDK v2](https://docs.gmx.io/docs/sdk/v2/)
or the generated API v2 reference | Read-only and expanding |
| Historical trade and order activity | [GraphQL](https://docs.gmx.io/docs/api/graphql/) | Indexed data, not write-path state |
| Submit, cancel, or simulate orders | [SDK v1](https://docs.gmx.io/docs/sdk/v1/)
or direct contract calls | Use the SDK or contracts, not the public read-only API guides |
| GM or GLV token prices for use in external protocols | [Chainlink Data Feeds](https://data.chain.link/) | Search for GM or GLV feeds on data.chain.link |
What is available now[](https://docs.gmx.io/docs/api/integration-guide/#what-is-available-now "Direct link to What is available now")
---------------------------------------------------------------------------------------------------------------------------------------
The current hand-written docs and checked-out code support the following split:
| Surface | Read | Write | Description |
| --- | --- | --- | --- |
| [API v1 REST](https://docs.gmx.io/docs/category/api-v1-rest-api/)
(`gmxinfra.io`) | ✅ | ❌ | Public market, price, liquidity, APY, and performance reads. Manual docs cover the stable public HTTP endpoints. |
| [API v2 HTTP reference](https://docs.gmx.io/docs/category/api-v2-openapi-reference/) | ✅ | ❌ | Generated schema reference for current API v2 reads. Covers markets, tokens, positions, orders, rates, APY, and performance. The checked-in generated reference does not yet list the staking or buyback endpoints used by SDK v2. API v2 is in active development and is expected to become the primary API in the coming weeks, expanding to support read and write operations for virtually any action. |
| [GraphQL](https://docs.gmx.io/docs/api/graphql/) | ✅ | ❌ | Historical indexed activity. Best for history, not write-path confirmation. |
| [SDK v1](https://docs.gmx.io/docs/sdk/v1/)
(`GmxSdk`) | ✅ | ✅ | Full TypeScript integration with reads and writes. Uses RPC, oracle, and Subsquid connections directly. |
| [SDK v2](https://docs.gmx.io/docs/sdk/v2/)
(`GmxApiSdk`) | ✅ | ❌ | Read-only TypeScript integration over HTTP. SDK v2 is in active development alongside API v2 and is expected to become the primary SDK in the coming weeks, expanding to support read and write operations for virtually any action. |
| [Direct contracts](https://docs.gmx.io/docs/api/contracts/overview/) | ✅ | ✅ | Lowest-level integration and custom transaction flows. Highest control and highest implementation burden. |
The generated API v2 reference does not currently list every endpoint surfaced by SDK v2. Use the [SDK v2 docs](https://docs.gmx.io/docs/sdk/v2/)
for the typed client surface, including `fetchBuybackWeeklyStats()` and `fetchStakingPower()`.
Build a live market overview[](https://docs.gmx.io/docs/api/integration-guide/#build-a-live-market-overview "Direct link to Build a live market overview")
------------------------------------------------------------------------------------------------------------------------------------------------------------
Use API v1 when you need public market snapshots and fallback URLs. Use `/markets` for a slower-changing market list, and `/markets/info` for a near-live market state snapshot.
const endpoints = [ "https://arbitrum-api.gmxinfra.io/markets/info", "https://arbitrum-api-fallback.gmxinfra.io/markets/info", "https://arbitrum-api-fallback.gmxinfra2.io/markets/info",];async function fetchMarketsInfo() { let lastError: Error | undefined; for (const endpoint of endpoints) { try { const response = await fetch(endpoint, { headers: { Accept: "application/json" }, }); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } return await response.json(); } catch (error) { lastError = error as Error; } } throw lastError ?? new Error("All market endpoints failed");}const markets = await fetchMarketsInfo();console.log("Loaded markets:", markets.length);
Use this refresh strategy:
1. Call `/markets` when you need the market catalog and can tolerate a `60` second cache window.
2. Call `/markets/info` when you need liquidity, open interest, funding, borrowing, token amounts, and `isDisabled`. This is also the correct endpoint for **near-live funding rates**.
3. Treat `/markets/info` as a snapshot, not a guarantee of the latest block. The current implementation caches the route for `1` second and refreshes market values on a `5000` ms pull interval, so build for near-live rather than same-block state.
4. Use `/rates` for **historical** funding and borrowing rate data. This endpoint returns hourly snapshots from the Squid indexer, not realtime values. Use it for rate averages, trends, and historical analysis.
Read positions and related orders for one account[](https://docs.gmx.io/docs/api/integration-guide/#read-positions-and-related-orders-for-one-account "Direct link to Read positions and related orders for one account")
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Use SDK v2 if you are already in TypeScript and want bigint-aware responses. Use the generated API v2 reference if you need raw HTTP schemas.
Install `@gmx-io/sdk`, then import `GmxApiSdk` from `@gmx-io/sdk/v2`. The `v2` path is a subpath export, not a separate package.
import { GmxApiSdk } from "@gmx-io/sdk/v2";const apiSdk = new GmxApiSdk({ chainId: 42161 });const positions = await apiSdk.fetchPositionsInfo({ address: "0x9f7198eb1b9Ccc0Eb7A07eD228d8FbC12963ea33", includeRelatedOrders: true,});const orders = await apiSdk.fetchOrders({ address: "0x9f7198eb1b9Ccc0Eb7A07eD228d8FbC12963ea33",});console.log({ positions, orders,});
Use this flow when you render account state:
1. Fetch positions with `includeRelatedOrders: true` if your page shows open positions and their linked orders together.
2. Fetch standalone orders only if you also need an account-wide orders view.
3. After submitting a write through SDK v1 or direct contracts, poll these read endpoints until the expected state appears instead of assuming immediate consistency.
Read historical trade activity[](https://docs.gmx.io/docs/api/integration-guide/#read-historical-trade-activity "Direct link to Read historical trade activity")
------------------------------------------------------------------------------------------------------------------------------------------------------------------
Use GraphQL for historical, indexed activity. Do not try to reconstruct history from live REST snapshots.
query RecentTrades($account: String!) { tradeActions(where: { account_eq: $account }, limit: 50, orderBy: timestamp_DESC) { eventName account timestamp transactionHash sizeDeltaUsd collateralDeltaAmount }}
The current GraphQL schema exposes `transactionHash` and top-level `timestamp`. See [GraphQL](https://docs.gmx.io/docs/api/graphql/)
for schema usage notes and migration context.
For referral analytics, the GraphQL schema also exposes the `affiliateStats` and `traderReferralStats` resolvers, plus per-hour stats entities (`AffiliateReferralTradeStatsByHour`, `TraderReferralTradeStatsByHour`, `AffiliateTraderStatsByHour`). Use these instead of stitching `tradeActions` for affiliate dashboards or trader rebate views — both resolvers accept `from`/`to` time windows and return pre-aggregated volume, rebate, discount, and trader-flow figures. See [GraphQL — Referral analytics](https://docs.gmx.io/docs/api/graphql/#2026-03-31--referral-analytics-added)
for the full schema and example queries.
Operational notes[](https://docs.gmx.io/docs/api/integration-guide/#operational-notes "Direct link to Operational notes")
---------------------------------------------------------------------------------------------------------------------------
### Freshness and caching[](https://docs.gmx.io/docs/api/integration-guide/#freshness-and-caching "Direct link to Freshness and caching")
* `GET /markets` uses a `60` second HTTP cache in the current implementation.
* `GET /markets/info` uses a `1` second HTTP cache in the current implementation.
* The backend currently caches `prices`, `tokensData`, and `marketsInfo` for `1` second, `userReferralInfo` for `5` seconds, and `onchainSettings` for `60` seconds.
* Avoid joining data from unrelated polls when you need one coherent snapshot. Prefer composite endpoints such as `/markets/info` or `fetchPositionsInfo({ includeRelatedOrders: true })`.
### Retries, timeouts, and fallback URLs[](https://docs.gmx.io/docs/api/integration-guide/#retries-timeouts-and-fallback-urls "Direct link to Retries, timeouts, and fallback URLs")
* The current API server timeout is `60000` ms.
* SDK v2 uses a simple HTTP client and does not add retry or fallback logic for you.
* Use the [Fallback URLs](https://docs.gmx.io/docs/api/rest-api/fallback-urls/)
page for API v1 market and oracle reads.
* If you receive a timeout, network error, `429`, or `5xx`, retry with backoff and fail over where you have fallback endpoints.
### Surface-specific operational model[](https://docs.gmx.io/docs/api/integration-guide/#surface-specific-operational-model "Direct link to Surface-specific operational model")
* API v1 REST uses endpoint-specific cache windows, and fallback URLs are documented for some public reads.
* API v2 reference documents read-only HTTP endpoints, but the generated reference does not define your retry policy.
* GraphQL is indexed data. Expect lag relative to live chain state.
* SDK v1 mixes live RPC, oracle, and indexed reads. Default SDK-created HTTP transports disable retries.
* SDK v2 is a read-only HTTP client and does not add fallback or retry logic for you.
* Direct contracts give you the most control, but your app owns retry, nonce, gas, and receipt strategy.
### Idempotency and race conditions[](https://docs.gmx.io/docs/api/integration-guide/#idempotency-and-race-conditions "Direct link to Idempotency and race conditions")
* These public API docs cover read paths. They do not provide idempotency keys for writes.
* After a write, do not assume your first follow-up read will reflect final state. Submission, indexing, and keeper execution can land at different times.
* If you need "position plus linked orders" on one screen, prefer a single positions call with `includeRelatedOrders: true` over stitching data from independent polls.
Next steps[](https://docs.gmx.io/docs/api/integration-guide/#next-steps "Direct link to Next steps")
------------------------------------------------------------------------------------------------------
* Use [API Overview](https://docs.gmx.io/docs/api/overview/)
to decide between REST, GraphQL, contracts, and the SDK.
* Use [API v1 REST API](https://docs.gmx.io/docs/category/api-v1-rest-api/)
for public market, price, and liquidity endpoints.
* Use the generated [API v2 OpenAPI Reference](https://docs.gmx.io/docs/category/api-v2-openapi-reference/)
for endpoint-level request and response schemas.
* Use [Troubleshooting](https://docs.gmx.io/docs/api/troubleshooting/)
if your reads look stale, a query fails validation, or a write does not show up yet.
* Use [SDK v1](https://docs.gmx.io/docs/sdk/v1/)
when your application needs write flows such as creating or canceling orders.
* [Choose the right integration surface](https://docs.gmx.io/docs/api/integration-guide/#choose-the-right-integration-surface)
* [What is available now](https://docs.gmx.io/docs/api/integration-guide/#what-is-available-now)
* [Build a live market overview](https://docs.gmx.io/docs/api/integration-guide/#build-a-live-market-overview)
* [Read positions and related orders for one account](https://docs.gmx.io/docs/api/integration-guide/#read-positions-and-related-orders-for-one-account)
* [Read historical trade activity](https://docs.gmx.io/docs/api/integration-guide/#read-historical-trade-activity)
* [Operational notes](https://docs.gmx.io/docs/api/integration-guide/#operational-notes)
* [Freshness and caching](https://docs.gmx.io/docs/api/integration-guide/#freshness-and-caching)
* [Retries, timeouts, and fallback URLs](https://docs.gmx.io/docs/api/integration-guide/#retries-timeouts-and-fallback-urls)
* [Surface-specific operational model](https://docs.gmx.io/docs/api/integration-guide/#surface-specific-operational-model)
* [Idempotency and race conditions](https://docs.gmx.io/docs/api/integration-guide/#idempotency-and-race-conditions)
* [Next steps](https://docs.gmx.io/docs/api/integration-guide/#next-steps)
---
# @gmx-io/gmx-public-api | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/gmx-api/gmx-io-gmx-public-api/#__docusaurus_skipToContent_fallback)
On this page
GMX Public API overview with Swagger/OpenAPI links and base URLs.
GMX Public API (Swagger)[](https://docs.gmx.io/docs/api/gmx-api/gmx-io-gmx-public-api/#gmx-public-api-swagger "Direct link to GMX Public API (Swagger)")
----------------------------------------------------------------------------------------------------------------------------------------------------------
* Swagger/OpenAPI spec: [GMX Public API Swagger](https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/swagger.json)
* Human-readable API docs: [GMX Public API Docs](https://docs.gmx.io/docs/api/gmx-api/gmx-io-gmx-public-api/)
Base URLs[](https://docs.gmx.io/docs/api/gmx-api/gmx-io-gmx-public-api/#base-urls "Direct link to Base URLs")
---------------------------------------------------------------------------------------------------------------
| Network | URL |
| --- | --- |
| Arbitrum | `https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/api/v1` |
| Avalanche | `https://gmx-api-avalanche-vxjas.ondigitalocean.app/api/v1` |
* [GMX Public API (Swagger)](https://docs.gmx.io/docs/api/gmx-api/gmx-io-gmx-public-api/#gmx-public-api-swagger)
* [Base URLs](https://docs.gmx.io/docs/api/gmx-api/gmx-io-gmx-public-api/#base-urls)
---
# GetLiquidityInfo | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/gmx-api/get-liquidity-info/#__docusaurus_skipToContent_fallback)
GetLiquidityInfo
================
GET
https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/api/v1/jit/liquidity\_info
----------------------------------------------------------------------------
GetLiquidityInfo
Request[](https://docs.gmx.io/docs/api/gmx-api/get-liquidity-info/#request "Direct link to request")
------------------------------------------------------------------------------------------------------
Responses[](https://docs.gmx.io/docs/api/gmx-api/get-liquidity-info/#responses "Direct link to Responses")
------------------------------------------------------------------------------------------------------------
* 200
* 500
Success
* application/json
* Schema
* Example (auto)
**Schema**
**liquidityInfos** object\[\]required
* Array \[\
\
\
**glvShiftParams** object\[\]required\
\
* Array \[\
\
\
**minMarketTokens**stringrequired\
\
**marketTokenAmount**stringrequired\
\
**toMarket**stringrequired\
\
**fromMarket**stringrequired\
\
**glv**stringrequired\
\
* \]\
\
\
**maxReservedUsdWithJitShort**stringrequired\
\
**maxReservedUsdWithJitLong**stringrequired\
\
**market**stringrequired\
\
**glv**stringrequired\
\
* \]
{ "liquidityInfos": [ { "glvShiftParams": [ { "minMarketTokens": "string", "marketTokenAmount": "string", "toMarket": "string", "fromMarket": "string", "glv": "string" } ], "maxReservedUsdWithJitShort": "string", "maxReservedUsdWithJitLong": "string", "market": "string", "glv": "string" } ]}
Internal Server Error
* python
* nodejs
* curl
* HTTP.CLIENT
* REQUESTS
import requestsurl = "https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/api/v1/jit/liquidity_info"payload = {}headers = { 'Accept': 'application/json'}response = requests.request("GET", url, headers=headers, data=payload)print(response.text)
RequestCollapse all
Base URL
Edit
https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/api/v1
---
# GetTokens | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/gmx-api/get-tokens/#__docusaurus_skipToContent_fallback)
GetTokens
=========
GET
https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/api/v1/tokens
---------------------------------------------------------------
GetTokens
Request[](https://docs.gmx.io/docs/api/gmx-api/get-tokens/#request "Direct link to request")
----------------------------------------------------------------------------------------------
Responses[](https://docs.gmx.io/docs/api/gmx-api/get-tokens/#responses "Direct link to Responses")
----------------------------------------------------------------------------------------------------
* 200
* 500
Success
* application/json
* Schema
* Example (auto)
**Schema**
* Array \[\
\
\
**isStaking**boolean\
\
**isPlatformTradingToken**boolean\
\
**isPlatformToken**boolean\
\
**isV1Available**boolean\
\
**isChartDisabled**boolean\
\
**isTempHidden**boolean\
\
**isSynthetic**boolean\
\
**isStable**boolean\
\
**isShortable**boolean\
\
**isWrapped**boolean\
\
**isNative**boolean\
\
**isUsdg**boolean\
\
**contractVersion**string\
\
**isPermitDisabled**boolean\
\
**isPermitSupported**boolean\
\
**categories**string\[\]\
\
**imageUrl**string\
\
**reservesUrl**string\
\
**explorerUrl**string\
\
**explorerSymbol**string\
\
**metamaskSymbol**string\
\
**wrappedAddress**string\
\
**visualPrefix**string\
\
**visualMultiplier**number\
\
**priceDecimals**number\
\
**address**stringrequired\
\
**decimals**numberrequired\
\
**baseSymbol**string\
\
**assetSymbol**string\
\
**symbol**stringrequired\
\
**name**stringrequired\
\
* \]
[ { "isStaking": true, "isPlatformTradingToken": true, "isPlatformToken": true, "isV1Available": true, "isChartDisabled": true, "isTempHidden": true, "isSynthetic": true, "isStable": true, "isShortable": true, "isWrapped": true, "isNative": true, "isUsdg": true, "contractVersion": "string", "isPermitDisabled": true, "isPermitSupported": true, "categories": [ "string" ], "imageUrl": "string", "reservesUrl": "string", "explorerUrl": "string", "explorerSymbol": "string", "metamaskSymbol": "string", "wrappedAddress": "string", "visualPrefix": "string", "visualMultiplier": 0, "priceDecimals": 0, "address": "string", "decimals": 0, "baseSymbol": "string", "assetSymbol": "string", "symbol": "string", "name": "string" }]
Internal Server Error
* python
* nodejs
* curl
* HTTP.CLIENT
* REQUESTS
import requestsurl = "https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/api/v1/tokens"payload = {}headers = { 'Accept': 'application/json'}response = requests.request("GET", url, headers=headers, data=payload)print(response.text)
RequestCollapse all
Base URL
Edit
https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/api/v1
---
# GetTokensInfo | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/gmx-api/get-tokens-info/#__docusaurus_skipToContent_fallback)
GetTokensInfo
=============
GET
https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/api/v1/tokens/info
--------------------------------------------------------------------
GetTokensInfo
Request[](https://docs.gmx.io/docs/api/gmx-api/get-tokens-info/#request "Direct link to request")
---------------------------------------------------------------------------------------------------
Responses[](https://docs.gmx.io/docs/api/gmx-api/get-tokens-info/#responses "Direct link to Responses")
---------------------------------------------------------------------------------------------------------
* 200
* 500
Success
* application/json
* Schema
* Example (auto)
**Schema**
* Array \[\
\
\
**hasPriceFeedProvider**boolean\
\
**totalSupply**string\
\
**balance**string\
\
**balanceType**number\
\
**sourceChainBalance**string\
\
**gmxAccountBalance**string\
\
**walletBalance**string\
\
**prices** objectrequired\
\
**maxPrice**stringrequired\
\
**minPrice**stringrequired\
\
**isStaking**boolean\
\
**isPlatformTradingToken**boolean\
\
**isPlatformToken**boolean\
\
**isV1Available**boolean\
\
**isChartDisabled**boolean\
\
**isTempHidden**boolean\
\
**isSynthetic**boolean\
\
**isStable**boolean\
\
**isShortable**boolean\
\
**isWrapped**boolean\
\
**isNative**boolean\
\
**isUsdg**boolean\
\
**contractVersion**string\
\
**isPermitDisabled**boolean\
\
**isPermitSupported**boolean\
\
**categories**string\[\]\
\
**imageUrl**string\
\
**reservesUrl**string\
\
**explorerUrl**string\
\
**explorerSymbol**string\
\
**metamaskSymbol**string\
\
**wrappedAddress**string\
\
**visualPrefix**string\
\
**visualMultiplier**number\
\
**priceDecimals**number\
\
**address**stringrequired\
\
**decimals**numberrequired\
\
**baseSymbol**string\
\
**assetSymbol**string\
\
**symbol**stringrequired\
\
**name**stringrequired\
\
* \]
[ { "hasPriceFeedProvider": true, "totalSupply": "string", "balance": "string", "balanceType": 0, "sourceChainBalance": "string", "gmxAccountBalance": "string", "walletBalance": "string", "prices": { "maxPrice": "string", "minPrice": "string" }, "isStaking": true, "isPlatformTradingToken": true, "isPlatformToken": true, "isV1Available": true, "isChartDisabled": true, "isTempHidden": true, "isSynthetic": true, "isStable": true, "isShortable": true, "isWrapped": true, "isNative": true, "isUsdg": true, "contractVersion": "string", "isPermitDisabled": true, "isPermitSupported": true, "categories": [ "string" ], "imageUrl": "string", "reservesUrl": "string", "explorerUrl": "string", "explorerSymbol": "string", "metamaskSymbol": "string", "wrappedAddress": "string", "visualPrefix": "string", "visualMultiplier": 0, "priceDecimals": 0, "address": "string", "decimals": 0, "baseSymbol": "string", "assetSymbol": "string", "symbol": "string", "name": "string" }]
Internal Server Error
* python
* nodejs
* curl
* HTTP.CLIENT
* REQUESTS
RequestCollapse all
Base URL
Edit
https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/api/v1
---
# Troubleshooting | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/troubleshooting/#__docusaurus_skipToContent_fallback)
On this page
Use this page when API reads do not match what you expect. Most issues fall into one of four buckets: invalid request parameters, stale snapshots, using the wrong surface for the job, or expecting immediate read-after-write consistency.
`400 Bad Request`[](https://docs.gmx.io/docs/api/troubleshooting/#400-bad-request "Direct link to 400-bad-request")
---------------------------------------------------------------------------------------------------------------------
The current read endpoints validate several inputs and return `400` for bad parameters.
Common cases:
* `/orders` and `/positions` require a valid account address.
* `/markets/tickers` validates `addresses` and `symbols` filters.
* `/rates` validates `period` and `averageBy`.
* `/apy` and `/performance/*` validate `period`.
If you receive a `400`, validate the exact query string before retrying. Retrying the same invalid input will not succeed.
A value looks stale[](https://docs.gmx.io/docs/api/troubleshooting/#a-value-looks-stale "Direct link to A value looks stale")
-------------------------------------------------------------------------------------------------------------------------------
Start by checking whether you are reading from a cached or indexed surface.
* Use `/markets/info` when you need near-live market state.
* Use `/markets` when a `60` second cache window is acceptable.
* Use GraphQL for historical activity, not for the latest write-path state.
* Use a single composite read where possible instead of stitching unrelated polls together.
If you need one coherent account snapshot, prefer one positions call with `includeRelatedOrders: true` over multiple loosely coordinated reads.
A write succeeded on-chain, but the API still does not show it[](https://docs.gmx.io/docs/api/troubleshooting/#a-write-succeeded-on-chain-but-the-api-still-does-not-show-it "Direct link to A write succeeded on-chain, but the API still does not show it")
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
That is usually a surface mismatch, not a broken API call.
* Public API guides in this section describe read surfaces.
* Writes belong to [SDK v1](https://docs.gmx.io/docs/sdk/v1/)
or direct contracts.
* After a write, wait for the transaction receipt first, then poll the read surface you care about until the state appears.
Do not assume the first follow-up HTTP or GraphQL read will reflect final state. Submission, keeper execution, and indexing can complete at different times.
Positions and orders do not line up[](https://docs.gmx.io/docs/api/troubleshooting/#positions-and-orders-do-not-line-up "Direct link to Positions and orders do not line up")
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
If your UI shows position state together with linked orders, fetch them from the same logical snapshot.
Recommended pattern:
import { GmxApiSdk } from "@gmx-io/sdk/v2";const apiSdk = new GmxApiSdk({ chainId: 42161 });const positions = await apiSdk.fetchPositionsInfo({ address: "0x9f7198eb1b9Ccc0Eb7A07eD228d8FbC12963ea33", includeRelatedOrders: true,});
Use a separate account-wide orders read only when you need a dedicated orders screen.
There is no documented public SLA[](https://docs.gmx.io/docs/api/troubleshooting/#there-is-no-documented-public-sla "Direct link to There is no documented public SLA")
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
The current manual docs do not publish a public SLA for these surfaces. Build your client as if network errors, timeouts, or stale snapshots can happen.
Recommended client behavior:
1. Use endpoint-specific fallback URLs where they are documented.
2. Add retries with backoff for safe read operations.
3. Keep write confirmation logic separate from read polling logic.
4. Log the exact surface you queried so you can distinguish API v1 REST, API v2, GraphQL, and SDK-backed reads during incident review.
Next steps[](https://docs.gmx.io/docs/api/troubleshooting/#next-steps "Direct link to Next steps")
----------------------------------------------------------------------------------------------------
* Use the [Integration guide](https://docs.gmx.io/docs/api/integration-guide/)
for workflow selection.
* Use [Fallback URLs](https://docs.gmx.io/docs/api/rest-api/fallback-urls/)
for API v1 public read failover.
* [`400 Bad Request`](https://docs.gmx.io/docs/api/troubleshooting/#400-bad-request)
* [A value looks stale](https://docs.gmx.io/docs/api/troubleshooting/#a-value-looks-stale)
* [A write succeeded on-chain, but the API still does not show it](https://docs.gmx.io/docs/api/troubleshooting/#a-write-succeeded-on-chain-but-the-api-still-does-not-show-it)
* [Positions and orders do not line up](https://docs.gmx.io/docs/api/troubleshooting/#positions-and-orders-do-not-line-up)
* [There is no documented public SLA](https://docs.gmx.io/docs/api/troubleshooting/#there-is-no-documented-public-sla)
* [Next steps](https://docs.gmx.io/docs/api/troubleshooting/#next-steps)
---
# GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/graphql/#__docusaurus_skipToContent_fallback)
On this page
GMX provides GraphQL endpoints powered by Subsquid for querying indexed on-chain data.
| Network | URL |
| --- | --- |
| **Arbitrum One** | `https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql` |
| **Avalanche C-Chain** | `https://gmx.squids.live/gmx-synthetics-avalanche:prod/api/graphql` |
| **Botanix** | `https://gmx.squids.live/gmx-synthetics-botanix:prod/api/graphql` |
| **MegaETH** | `https://gmx.squids.live/gmx-synthetics-megaeth:prod/api/graphql` |
Schema changes[](https://docs.gmx.io/docs/api/graphql/#schema-changes "Direct link to Schema changes")
--------------------------------------------------------------------------------------------------------
### 2026-03-31 — Referral analytics added[](https://docs.gmx.io/docs/api/graphql/#2026-03-31--referral-analytics-added "Direct link to 2026-03-31 — Referral analytics added")
The GraphQL schema now exposes referral analytics for both affiliates and traders. Five new entities track referral code ownership and hourly trade statistics, and two new query resolvers aggregate that data into time-windowed summaries with period-over-period comparisons.
**New entities.**
| Entity | What it provides |
| --- | --- |
| `ReferralCodeOwner` | Maps a referral code to its `owner` address, with `updatedAtTimestamp`, `updatedAtBlock`, and `updatedTxnHash` |
| `TraderReferral` | Records which `referralCode` and `affiliate` a trader is associated with, plus update metadata |
| `AffiliateReferralTradeStatsByHour` | Hourly trade stats for an affiliate: `volumeUsd`, `tradesCount`, and `rebatesUsd` |
| `TraderReferralTradeStatsByHour` | Hourly trade stats for a trader using a referral code: `volumeUsd` and `discountsUsd` |
| `AffiliateTraderStatsByHour` | Hourly net trader flow for an affiliate: `tradersGained`, `tradersLost`, and `tradersNet` |
**New query resolvers.**
These are custom server-extension resolvers, not standard entity queries. Call them by name with a `where` argument:
| Resolver | Input fields | What it returns |
| --- | --- | --- |
| `affiliateStats` | `affiliate` (required), `from?`, `to?` | Time-windowed volume, trade count, rebates, and trader flow for an affiliate, with optional period comparison |
| `traderReferralStats` | `trader` (required), `from?`, `to?` | Time-windowed volume and discounts for a trader using a referral code, with optional period comparison |
Both resolvers align timestamps to hourly buckets and choose a bucket size automatically based on the requested window length.
**Example queries.**
# Affiliate dashboard: volume, rebates, and trader flow for a 7-day windowquery AffiliateStats($affiliate: String!) { affiliateStats(where: { affiliate: $affiliate, from: 1743292800, to: 1743897600 }) { affiliate from to bucketSizeSeconds hasComparison summary { volumeUsd volumeUsdDelta rebatesUsd rebatesUsdDelta tradersNet tradersNetDelta } points { timestamp volumeUsd rebatesUsd tradersGained tradersLost tradersNet } }}
# Trader dashboard: volume and discounts earned through a referral codequery TraderReferralStats($trader: String!) { traderReferralStats(where: { trader: $trader, from: 1743292800, to: 1743897600 }) { trader from to bucketSizeSeconds summary { volumeUsd discountsUsd } points { timestamp volumeUsd discountsUsd } }}
### 2026-03-10 - Staking power and account analytics added[](https://docs.gmx.io/docs/api/graphql/#2026-03-10---staking-power-and-account-analytics-added "Direct link to 2026-03-10 - Staking power and account analytics added")
The GraphQL schema now exposes staking power analytics plus expanded daily account aggregates for PnL and capital-tracking queries.
**New entities.**
| Entity | What it provides |
| --- | --- |
| `StakingPower` | Per-account staking power state, including `accumulatedPower`, `currentStakedBalance`, `historicalMaxStaked`, `lastPowerResetAt`, and `powerResetCount` |
| `NetworkStakingPower` | Network-wide staking power totals through `totalAccumulatedPower`, `totalCurrentStaked`, and `lastUpdateTimestamp` |
**Expanded analytics fields.**
| Entity | Added fields |
| --- | --- |
| `AccountStat` | `account`, `period`, `dayTimestamp`, `netCapitalDelta`, `maxNetCapitalRunningDelta` |
| `Position` | `maxCapital` |
These additions let you query staking-power history and daily account-level capital changes without replaying raw position-change events yourself.
**Example query.**
query AccountAnalytics($account: String!) { stakingPower(id: $account) { accumulatedPower currentStakedBalance historicalMaxStaked lastPowerResetAt powerResetCount } accountStats( where: { account_eq: $account, period_eq: "1d" } orderBy: dayTimestamp_DESC limit: 7 ) { dayTimestamp netCapitalDelta maxNetCapitalRunningDelta volume realizedPnl }}
### 2026-02-24 — Transaction entity removed[](https://docs.gmx.io/docs/api/graphql/#2026-02-24--transaction-entity-removed "Direct link to 2026-02-24 — Transaction entity removed")
The `Transaction` entity type has been removed from the GraphQL schema. This change is live on all main endpoints. A backward-compatible endpoint is available until March 1, 2026:
https://gmx.squids.live/gmx-synthetics-arbitrum@786bd0/api/graphql
**Field changes.** Entities that previously referenced `transaction: Transaction!` now expose a flat `transactionHash: String!` field. The `timestamp` field that was nested inside `Transaction` is now a top-level field on each entity.
| Entity | Old field | New field |
| --- | --- | --- |
| `TradeAction` | `transaction: Transaction!` | `transactionHash: String!` |
| `ClaimAction` | `transaction: Transaction!` | `transactionHash: String!` |
| `Order` | `createdTxn: Transaction!` | `createdTxnHash: String!` |
| `Order` | `cancelledTxn: Transaction` | `cancelledTxnHash: String` |
| `Order` | `executedTxn: Transaction` | `executedTxnHash: String` |
| `SwapFeesInfo` | `transaction: Transaction!` | `transactionHash: String!` |
| `SwapInfo` | `transaction: Transaction!` | `transactionHash: String!` |
| `PositionFeesEntity` | `transaction: Transaction!` | `transactionHash: String!` |
| `Distribution` | `transaction: Transaction!` | `transactionHash: String!` |
**Sort field changes.** Sort values that referenced the `transaction` relation are replaced with direct field sorts:
| Old sort value | New sort value |
| --- | --- |
| `transaction_timestamp_DESC` | `timestamp_DESC` |
| `transaction_timestamp_ASC` | `timestamp_ASC` |
**Example migration.** A `TradeAction` query before and after:
# BeforetradeActions(limit: 50, orderBy: transaction_timestamp_DESC) { eventName transaction { timestamp hash }}# AftertradeActions(limit: 50, orderBy: timestamp_DESC) { eventName timestamp transactionHash}
* [Schema changes](https://docs.gmx.io/docs/api/graphql/#schema-changes)
* [2026-03-31 — Referral analytics added](https://docs.gmx.io/docs/api/graphql/#2026-03-31--referral-analytics-added)
* [2026-03-10 - Staking power and account analytics added](https://docs.gmx.io/docs/api/graphql/#2026-03-10---staking-power-and-account-analytics-added)
* [2026-02-24 — Transaction entity removed](https://docs.gmx.io/docs/api/graphql/#2026-02-24--transaction-entity-removed)
---
# GetSnapshots | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/gmx-api/get-snapshots/#__docusaurus_skipToContent_fallback)
GetSnapshots
============
GET
https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/api/v1/performance/snapshots
------------------------------------------------------------------------------
GetSnapshots
Request[](https://docs.gmx.io/docs/api/gmx-api/get-snapshots/#request "Direct link to request")
-------------------------------------------------------------------------------------------------
### Query Parameters
**period** ApiParameterPeriod
**Possible values:** \[`1d`, `7d`, `30d`, `90d`, `180d`, `1y`, `total`\]
**address** string
Responses[](https://docs.gmx.io/docs/api/gmx-api/get-snapshots/#responses "Direct link to Responses")
-------------------------------------------------------------------------------------------------------
* 200
* 400
* 500
Success
* application/json
* Schema
* Example (auto)
**Schema**
* Array \[\
\
\
**snapshots** object\[\]required\
\
* Array \[\
\
\
**performance**string\
\
**snapshotTimestamp**numberrequired\
\
* \]\
\
\
**entity**stringrequired\
\
**address**stringrequired\
\
* \]
[ { "snapshots": [ { "performance": "string", "snapshotTimestamp": 0 } ], "entity": "string", "address": "string" }]
Invalid period
Internal Server Error
* python
* nodejs
* curl
* HTTP.CLIENT
* REQUESTS
import requestsurl = "https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/api/v1/performance/snapshots"payload = {}headers = { 'Accept': 'application/json'}response = requests.request("GET", url, headers=headers, data=payload)print(response.text)
RequestCollapse all
Base URL
Edit
https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/api/v1
ParametersShow optional parameters
period — query
\---1d7d30d90d180d1ytotal
address — query
---
# GetOhlcv | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/gmx-api/get-ohlcv/#__docusaurus_skipToContent_fallback)
GetOhlcv
========
GET
/prices/ohlcv
-------------
GetOhlcv
Request[](https://docs.gmx.io/docs/api/gmx-api/get-ohlcv/#request "Direct link to request")
---------------------------------------------------------------------------------------------
Responses[](https://docs.gmx.io/docs/api/gmx-api/get-ohlcv/#responses "Direct link to Responses")
---------------------------------------------------------------------------------------------------
* 200
* 400
* 500
Success
Bad Request - Invalid parameters
Internal Server Error
---
# GetMarkets | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/gmx-api/get-markets/#__docusaurus_skipToContent_fallback)
GetMarkets
==========
GET
/markets
--------
GetMarkets
Request[](https://docs.gmx.io/docs/api/gmx-api/get-markets/#request "Direct link to request")
-----------------------------------------------------------------------------------------------
Responses[](https://docs.gmx.io/docs/api/gmx-api/get-markets/#responses "Direct link to Responses")
-----------------------------------------------------------------------------------------------------
* 200
* 500
Success
Internal Server Error
---
# Fallback URLs | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/rest-api/fallback-urls/#__docusaurus_skipToContent_fallback)
When the primary API endpoint is unavailable for a chain, use the corresponding fallback endpoint below.
| Network | Fallback 1 | Fallback 2 |
| --- | --- | --- |
| Arbitrum | `https://arbitrum-api-fallback.gmxinfra.io` | `https://arbitrum-api-fallback.gmxinfra2.io` |
| Avalanche | `https://avalanche-api-fallback.gmxinfra.io` | `https://avalanche-api-fallback.gmxinfra2.io` |
| Botanix | `https://botanix-api-fallback.gmxinfra.io` | `https://botanix-api-fallback.gmxinfra2.io` |
---
# Markets | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/rest-api/markets/#__docusaurus_skipToContent_fallback)
On this page
REST endpoints for trading market information.
Use this page when you need public market reads from API v1 REST. For exact “which surface should I use” guidance, start with the [API integration guide](https://docs.gmx.io/docs/api/integration-guide/)
.
Trading markets and GM tokens[](https://docs.gmx.io/docs/api/rest-api/markets/#trading-markets-and-gm-tokens "Direct link to Trading markets and GM tokens")
--------------------------------------------------------------------------------------------------------------------------------------------------------------
To retrieve a list of tradable markets and their associated tokens (for example, GM tokens for liquidity pools):
| Network | URL |
| --- | --- |
| Arbitrum | `https://arbitrum-api.gmxinfra.io/markets` |
| Avalanche | `https://avalanche-api.gmxinfra.io/markets` |
| Botanix | `https://botanix-api.gmxinfra.io/markets` |
This endpoint caches responses for 60 seconds.
Trading markets and GM info[](https://docs.gmx.io/docs/api/rest-api/markets/#trading-markets-and-gm-info "Direct link to Trading markets and GM info")
--------------------------------------------------------------------------------------------------------------------------------------------------------
To retrieve detailed information about tradable markets and their tokens — including liquidity, open interest, token amounts, funding/borrowing/net rates, `isDisabled` status, and listing date:
| Network | URL |
| --- | --- |
| Arbitrum | `https://arbitrum-api.gmxinfra.io/markets/info` |
| Avalanche | `https://avalanche-api.gmxinfra.io/markets/info` |
| Botanix | `https://botanix-api.gmxinfra.io/markets/info` |
The `/markets/info` endpoint refreshes market values on a `5000` ms pull interval and caches responses with a `1` second TTL. Treat it as a near-live snapshot, not as same-block state.
Operational notes[](https://docs.gmx.io/docs/api/rest-api/markets/#operational-notes "Direct link to Operational notes")
--------------------------------------------------------------------------------------------------------------------------
* Use `/markets` for a market catalog or configuration view. The current implementation caches this route for `60` seconds.
* Use `/markets/info` for near-live liquidity, open interest, funding, borrowing, token amounts, and `isDisabled` state. The current implementation caches this route for `1` second.
* Use `/markets/tickers` when you need filtered ticker reads. Invalid `addresses` or `symbols` query values return `400`.
* If you need fallback behavior, use the alternate public URLs documented on [Fallback URLs](https://docs.gmx.io/docs/api/rest-api/fallback-urls/)
.
Funding rate data freshness[](https://docs.gmx.io/docs/api/rest-api/markets/#funding-rate-data-freshness "Direct link to Funding rate data freshness")
--------------------------------------------------------------------------------------------------------------------------------------------------------
The `/rates` endpoint returns **hourly snapshots** produced by the Squid indexer — it is not realtime data. Each snapshot is timestamped at the start of the hour. Use `/rates` for historical rate analysis, averages, and trend charts.
For **near-live funding rates**, use `/markets/info` instead. It refreshes market values on a `5000` ms pull interval and includes current funding and borrowing rates alongside liquidity and open interest.
* [Trading markets and GM tokens](https://docs.gmx.io/docs/api/rest-api/markets/#trading-markets-and-gm-tokens)
* [Trading markets and GM info](https://docs.gmx.io/docs/api/rest-api/markets/#trading-markets-and-gm-info)
* [Operational notes](https://docs.gmx.io/docs/api/rest-api/markets/#operational-notes)
* [Funding rate data freshness](https://docs.gmx.io/docs/api/rest-api/markets/#funding-rate-data-freshness)
---
# Liquidity | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/rest-api/liquidity/#__docusaurus_skipToContent_fallback)
On this page
REST endpoints for APY, performance, and GLV information.
Use this page for public liquidity and yield reads. For a broader comparison with SDK and GraphQL surfaces, start with the [API integration guide](https://docs.gmx.io/docs/api/integration-guide/)
.
Fee APYs[](https://docs.gmx.io/docs/api/rest-api/liquidity/#fee-apys "Direct link to Fee APYs")
-------------------------------------------------------------------------------------------------
To retrieve fee APYs for GM pools and GLV vaults:
| Network | URL |
| --- | --- |
| Arbitrum | `https://arbitrum-api.gmxinfra.io/apy?period=total` |
| Avalanche | `https://avalanche-api.gmxinfra.io/apy?period=total` |
| Botanix | `https://botanix-api.gmxinfra.io/apy?period=total` |
Accepted query parameters:
* `period`: `1d`, `7d`, `30d`, `90d`, `180d`, `1y`, `total`. Defaults to `7d`.
Performance[](https://docs.gmx.io/docs/api/rest-api/liquidity/#performance "Direct link to Performance")
----------------------------------------------------------------------------------------------------------
To retrieve annualized performance for GM pools and GLV vaults:
| Network | URL |
| --- | --- |
| Arbitrum | `https://arbitrum-api.gmxinfra.io/performance/annualized?period=total` |
| Avalanche | `https://avalanche-api.gmxinfra.io/performance/annualized?period=total` |
| Botanix | `https://botanix-api.gmxinfra.io/performance/annualized?period=total` |
Accepted query parameters:
* `period`: `7d`, `30d`, `90d`, `180d`, `1y`, `total`. Defaults to `90d`. The `1d` period is not supported and returns a 400 error.
* `address`: Address of a specific GM pool or GLV vault to retrieve data for only that entity.
GLV tokens[](https://docs.gmx.io/docs/api/rest-api/liquidity/#glv-tokens "Direct link to GLV tokens")
-------------------------------------------------------------------------------------------------------
To retrieve a list of GMX Liquidity Vault (GLV) tokens:
| Network | URL |
| --- | --- |
| Arbitrum | `https://arbitrum-api.gmxinfra.io/glvs/` |
| Avalanche | `https://avalanche-api.gmxinfra.io/glvs/` |
| Botanix | `https://botanix-api.gmxinfra.io/glvs/` |
GLV info[](https://docs.gmx.io/docs/api/rest-api/liquidity/#glv-info "Direct link to GLV info")
-------------------------------------------------------------------------------------------------
To retrieve extended information for GLV vaults, including market exposure, GM pool balances in USD, `isDisabled` status, and listing date:
| Network | URL |
| --- | --- |
| Arbitrum | `https://arbitrum-api.gmxinfra.io/glvs/info` |
| Avalanche | `https://avalanche-api.gmxinfra.io/glvs/info` |
| Botanix | `https://botanix-api.gmxinfra.io/glvs/info` |
Operational notes[](https://docs.gmx.io/docs/api/rest-api/liquidity/#operational-notes "Direct link to Operational notes")
----------------------------------------------------------------------------------------------------------------------------
* `/apy` currently caches responses for `1800` seconds and returns `400` for an invalid `period`.
* `/performance/annualized` and `/performance/snapshots` currently cache by day and return `400` for unsupported periods such as `1d`.
* Use these routes for yield and performance reporting, not for near-live position or order state.
* If you need write-path status after a transaction, use [SDK v1](https://docs.gmx.io/docs/sdk/v1/)
or direct contracts and then poll the relevant read surface.
* [Fee APYs](https://docs.gmx.io/docs/api/rest-api/liquidity/#fee-apys)
* [Performance](https://docs.gmx.io/docs/api/rest-api/liquidity/#performance)
* [GLV tokens](https://docs.gmx.io/docs/api/rest-api/liquidity/#glv-tokens)
* [GLV info](https://docs.gmx.io/docs/api/rest-api/liquidity/#glv-info)
* [Operational notes](https://docs.gmx.io/docs/api/rest-api/liquidity/#operational-notes)
---
# Contracts for V1 | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/archived/contracts-v1/#__docusaurus_skipToContent_fallback)
On this page
Docs for the GMX V1 contracts.
Important Notes[](https://docs.gmx.io/docs/archived/contracts-v1/#important-notes "Direct link to Important Notes")
---------------------------------------------------------------------------------------------------------------------
Important
GMX V1 contracts have been sunset, and trading or providing liquidity is no longer supported.
Important
Please note that these docs are meant just as an overview, please check the actual contract code for the exact implementation and for any possible edge cases if building an application, integration or similar using the contracts.
Please subscribe to the channels in the [Updates and Support](https://docs.gmx.io/docs/api/updates-support/)
page for important contract update notifications.
Overview[](https://docs.gmx.io/docs/archived/contracts-v1/#overview "Direct link to Overview")
------------------------------------------------------------------------------------------------
A technical overview of GMX V1 can be found in this [Notion Doc](https://gmx-io.notion.site/GMX-Technical-Overview-47fc5ed832e243afb9e97e8a4a036353)
.
Arbitrum[](https://docs.gmx.io/docs/archived/contracts-v1/#arbitrum "Direct link to Arbitrum")
------------------------------------------------------------------------------------------------
* GMX: [0xfc5A1A6EB076a2C7aD06eD22C90d7E710E35ad0a](https://arbiscan.io/address/0xfc5A1A6EB076a2C7aD06eD22C90d7E710E35ad0a)
* Vault: [0x489ee077994B6658eAfA855C308275EAd8097C4A](https://arbiscan.io/address/0x489ee077994B6658eAfA855C308275EAd8097C4A)
* Router: [0xaBBc5F99639c9B6bCb58544ddf04EFA6802F4064](https://arbiscan.io/address/0xaBBc5F99639c9B6bCb58544ddf04EFA6802F4064)
* PositionRouter: [0xb87a436B93fFE9D75c5cFA7bAcFff96430b09868](https://arbiscan.io/address/0xb87a436B93fFE9D75c5cFA7bAcFff96430b09868)
* OrderBook: [0x09f77e8a13de9a35a7231028187e9fd5db8a2acb](https://arbiscan.io/address/0x09f77e8a13de9a35a7231028187e9fd5db8a2acb)
* Reader: [0x22199a49A999c351eF7927602CFB187ec3cae489](https://arbiscan.io/address/0x22199a49A999c351eF7927602CFB187ec3cae489)
* RewardReader: [0x8BFb8e82Ee4569aee78D03235ff465Bd436D40E0](https://arbiscan.io/address/0x8BFb8e82Ee4569aee78D03235ff465Bd436D40E0)
* OrderBookReader: [0xa27C20A7CF0e1C68C0460706bB674f98F362Bc21](https://arbiscan.io/address/0xa27C20A7CF0e1C68C0460706bB674f98F362Bc21)
* StakedGmx: [0xd2D1162512F927a7e282Ef43a362659E4F2a728F](https://arbiscan.io/address/0xd2D1162512F927a7e282Ef43a362659E4F2a728F)
* StakedGlp: [0x5402B5F40310bDED796c7D0F3FF6683f5C0cFfdf](https://arbiscan.io/address/0x5402B5F40310bDED796c7D0F3FF6683f5C0cFfdf)
* GlpManager: [0x3963FfC9dff443c2A94f21b129D429891E32ec18](https://arbiscan.io/address/0x3963FfC9dff443c2A94f21b129D429891E32ec18)
* RewardRouter: [0x5E4766F932ce00aA4a1A82d3Da85adf15C5694A1](https://arbiscan.io/address/0x5E4766F932ce00aA4a1A82d3Da85adf15C5694A1)
* GlpRewardRouter: [0xB95DB5B167D75e6d04227CfFFA61069348d271F5](https://arbiscan.io/address/0xB95DB5B167D75e6d04227CfFFA61069348d271F5)
* ReferralStorage: [0xe6fab3F0c7199b0d34d7FbE83394fc0e0D06e99d](https://arbiscan.io/address/0xe6fab3F0c7199b0d34d7FbE83394fc0e0D06e99d)
* GMX-ETH Uniswap Pool: [0x80A9ae39310abf666A87C743d6ebBD0E8C42158E](https://arbiscan.io/address/0x80A9ae39310abf666A87C743d6ebBD0E8C42158E)
Avalanche[](https://docs.gmx.io/docs/archived/contracts-v1/#avalanche "Direct link to Avalanche")
---------------------------------------------------------------------------------------------------
* GMX: [0x62edc0692BD897D2295872a9FFCac5425011c661](https://snowtrace.io/address/0x62edc0692BD897D2295872a9FFCac5425011c661)
* Vault: [0x9ab2De34A33fB459b538c43f251eB825645e8595](https://snowtrace.io/address/0x9ab2De34A33fB459b538c43f251eB825645e8595)
* Router: [0x5F719c2F1095F7B9fc68a68e35B51194f4b6abe8](https://snowtrace.io/address/0x5F719c2F1095F7B9fc68a68e35B51194f4b6abe8)
* PositionRouter: [0xffF6D276Bc37c61A23f06410Dce4A400f66420f8](https://snowtrace.io/address/0xffF6D276Bc37c61A23f06410Dce4A400f66420f8)
* OrderBook: [0x4296e307f108B2f583FF2F7B7270ee7831574Ae5](https://snowtrace.io/address/0x4296e307f108B2f583FF2F7B7270ee7831574Ae5)
* Reader: [0x67b789D48c926006F5132BFCe4e976F0A7A63d5D](https://snowtrace.io/address/0x67b789D48c926006F5132BFCe4e976F0A7A63d5D)
* RewardReader: [0x04Fc11Bd28763872d143637a7c768bD96E44c1b6](https://snowtrace.io/address/0x04Fc11Bd28763872d143637a7c768bD96E44c1b6)
* OrderBookReader: [0xccFE3E576f8145403d3ce8f3c2f6519Dae40683B](https://snowtrace.io/address/0xccFE3E576f8145403d3ce8f3c2f6519Dae40683B)
* StakedGmx: [0x4d268a7d4C16ceB5a606c173Bd974984343fea13](https://snowtrace.io/address/0x4d268a7d4C16ceB5a606c173Bd974984343fea13)
* StakedGlp: [0xaE64d55a6f09E4263421737397D1fdFA71896a69](https://snowtrace.io/address/0xaE64d55a6f09E4263421737397D1fdFA71896a69)
* GlpManager: [0xD152c7F25db7F4B95b7658323c5F33d176818EE4](https://snowtrace.io/address/0xD152c7F25db7F4B95b7658323c5F33d176818EE4)
* RewardRouter: [0x091eD806490Cc58Fd514441499e58984cCce0630](https://snowtrace.io/address/0x091eD806490Cc58Fd514441499e58984cCce0630)
* GlpRewardRouter: [0xB70B91CE0771d3f4c81D87660f71Da31d48eB3B3](https://snowtrace.io/address/0xB70B91CE0771d3f4c81D87660f71Da31d48eB3B3)
* ReferralStorage: [0x827ED045002eCdAbEb6e2b0d1604cf5fC3d322F8](https://snowtrace.io/address/0x827ED045002eCdAbEb6e2b0d1604cf5fC3d322F8)
* GMX-AVAX Trader Joe Pool: [0x0c91a070f862666bBcce281346BE45766d874D98](https://snowtrace.io/address/0x0c91a070f862666bBcce281346BE45766d874D98)
Swap[](https://docs.gmx.io/docs/archived/contracts-v1/#swap "Direct link to Swap")
------------------------------------------------------------------------------------
To execute a swap:
* Approve the Router contract for the token and amount you would like to swap
* Call Router.swap with parameters:
* \_path: \[tokenIn, tokenOut\]
* \_amountIn: amount of tokenIn to swap
* \_minOut: minimum expected output amount
* \_receiver: address of the receiver of tokenOut
* The function will revert if the amount of tokenOut sent to the receiver is less than \_minOut
To get swap amounts before execution:
* Call Reader.getMaxAmountIn with parameters:
* \_vault: address of the vault
* \_tokenIn: address of token that will be given
* \_tokenOut: address of token to be received
* The max amount of tokenIn that can be swapped will be returned
* Call Reader.getAmountOut with parameters:
* \_vault: address of the vault
* \_tokenIn: address of token that will be given
* \_tokenOut: address of token to be received
* \_amountIn: amount of tokenIn to swap
* Two values will be returned, the first is the amount out after fees, and the second is the fee amount
* The fee amount will be in terms of tokenOut
Tokens have a usdgAmount in the Vault contract used for some calculations, this amount is updated on minting of GLP, redemption of GLP and swaps based on the price of the token at the time. Due to price fluctuations this value may drift slightly from the actual USD value of the tokens in the pool, the usdgAmount is periodically updated to re-align values.
Query Available Amounts[](https://docs.gmx.io/docs/archived/contracts-v1/#query-available-amounts "Direct link to Query Available Amounts")
---------------------------------------------------------------------------------------------------------------------------------------------
The maximum sum of all position sizes is limited by the amount of tokens there are in the pool and any additional caps.
To calculate the available amount of liquidity for long positions:
* indexToken: the address of the token to long
* Available amount in tokens: Vault.poolAmounts(indexToken) - Vault.reservedAmounts(indexToken)
* Available amount in USD: PositionRouter.maxGlobalLongSizes(indexToken) - Vault.guaranteedUsd(indexToken)
* The available liquidity will be the lower of these two values
* PositionRouter.maxGlobalLongSizes(indexToken) can be zero, in which case there is no additional cap, and available liquidity is based only on the available amount of tokens
To calculate the available amount of liquidity for short positions:
* indexToken: the address of the token to short
* collateralToken: the address of the stablecoin token to be used as collateral
* Available amount in tokens: Vault.poolAmounts(collateralToken) - Vault.reservedAmounts(collateralToken)
* Available amount in USD: PositionRouter.maxGlobalShortSizes(indexToken) - Vault.globalShortSizes(indexToken)
* The available liquidity will be the lower of these two values
* PositionRouter.maxGlobalShortSizes(indexToken) can be zero, in which case there is no additional cap, and available liquidity is based only on the available amount of tokens
Opening / Increasing a Position[](https://docs.gmx.io/docs/archived/contracts-v1/#opening--increasing-a-position "Direct link to Opening / Increasing a Position")
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
To open or increase the size of an existing position:
* Approve the PositionRouter as a Router plugin for your account
* Router.approvePlugin(PositionRouter address)
* Approve the Router contract for the token and amount you would deposit as collateral for the position
* Call PositionRouter.createIncreasePosition with parameters:
* \_path: \[collateralToken\] or \[tokenIn, collateralToken\] if a swap is needed
* \_indexToken: the address of the token you want to long or short
* \_amountIn: the amount of tokenIn you want to deposit as collateral
* \_minOut: the min amount of collateralToken to swap for
* \_sizeDelta: the USD value of the change in position size
* \_isLong: whether to long or short
* \_acceptablePrice: the USD value of the max (for longs) or min (for shorts) index price acceptable when executing the request
* \_executionFee: can be set to PositionRouter.minExecutionFee
* \_referralCode: [referral code](https://docs.gmx.io/docs/referrals/)
for affiliate rewards and rebates
* \_callbackTarget: an optional callback contract, this contract will be called on request execution or cancellation
* After this transaction is sent a keeper will execute the request, the request will either be executed or cancelled
* If the position cannot be increased for reasons such as the \_acceptablePrice not being fulfillable or there being insufficient liquidity then the request will be cancelled and funds will be sent back to the msg.sender that called PositionRouter.createIncreasePosition
* \_minOut can be zero if no swap is required
* USD values for \_sizeDelta and \_price are multiplied by (10 \*\* 30), so for example to open a long position of size 1000 USD, the value 1000 \* (10 \*\* 30) should be used
Note that if the position increase request is created with PositionRouter.createIncreasePositionETH then in case of cancellation the PositionRouter would send ETH to the receiver using `receiver.send(amount)`, this has a limit of 2300 gas. If the receiver is a contract and the receive function invoked on the transfer requires more than 2300 gas, this call can fail which would cause the ETH to be left in the PositionRouter.
WETH and PositionRouter.createIncreasePosition should be used instead to avoid this issue.
Closing / Decreasing a Position[](https://docs.gmx.io/docs/archived/contracts-v1/#closing--decreasing-a-position "Direct link to Closing / Decreasing a Position")
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
To close or decrease an existing position:
* Call PositionRouter.createDecreasePosition with parameters:
* \_path: \[collateralToken\] or \[collateralToken, tokenOut\] if a swap is needed
* \_indexToken: the index token of the position
* \_collateralDelta: the amount of collateral in USD value to withdraw
* \_sizeDelta: the USD value of the change in position size
* \_isLong: whether the position is a long or short
* \_receiver: the address to receive the withdrawn tokens
* \_acceptablePrice: the USD value of the min (for longs) or max (for shorts) index price acceptable when executing the request
* \_minOut: the min output token amount
* \_executionFee: can be set to PositionRouter.minExecutionFee
* \_withdrawETH: only applicable if WETH will be withdrawn, the WETH will be unwrapped to ETH if this is set to true
* \_callbackTarget: an optional callback contract, this contract will be called on request execution or cancellation
* After this transaction is sent a keeper will execute the request, the request will either be executed or cancelled
* If the position cannot be decreased for reasons such as the \_acceptablePrice not being fulfillable then the request will be cancelled and there will be no change to the position
* \_minOut can be zero if no swap is required
Note that if `_withdrawETH` is `true` then the position decrease request would send ETH to the receiver using `receiver.send(amount)`, this has a limit of 2300 gas. If the receiver is a contract and the receive function invoked on the transfer requires more than 2300 gas, this call can fail which would cause the ETH to be left in the PositionRouter.
Set `_withdrawETH` to `false` instead to avoid this issue.
Positions List[](https://docs.gmx.io/docs/archived/contracts-v1/#positions-list "Direct link to Positions List")
------------------------------------------------------------------------------------------------------------------
A list of position details can be retrieved by calling Reader.getPositions with params:
* \_vault: the vault contract address
* \_account: the account of the user
* \_collateralTokens: an array of collateralTokens
* \_indexTokens: an array of indexTokens
* \_isLong: an array of whether the position is a long position
The returned positions will be in the order of the query, for example, given the following inputs:
* \_collateralTokens: \[WBTC.address, WETH.address, USDC.address\]
* \_indexTokens: \[WBTC.address, WETH.address, WBTC.address\]
* \_isLong: \[true, true, false\]
The position details would be returned for:
* Long BTC position, positionIndex: 0
* Long ETH position, positionIndex: 1
* Short BTC position, positionIndex: 2
The returned array would be a list of values ordered by the positions:
* size
* position size in USD
* value at: positionIndex \* 9
* collateral
* position collateral in USD
* value at: positionIndex \* 9 + 1
* averagePrice
* average entry price of the position in USD
* value at: positionIndex \* 9 + 2
* entryFundingRate
* a snapshot of the cumulative funding rate at the time the position was entered
* value at: positionIndex \* 9 + 3
* hasRealisedProfit
* 1 if the position has a positive realised profit, 0 otherwise
* value at: positionIndex \* 9 + 4
* realisedPnl
* the realised PnL for the position in USD
* value at: positionIndex \* 9 + 5
* lastIncreasedTime
* timestamp of the last time the position was increased
* value at: positionIndex \* 9 + 6
* hasProfit
* 1 if the position is currently in profit, 0 otherwise
* value at: positionIndex \* 9 + 7
* delta
* amount of current profit or loss of the position in USD
* value at: positionIndex \* 9 + 8
Buying / Selling GLP[](https://docs.gmx.io/docs/archived/contracts-v1/#buying--selling-glp "Direct link to Buying / Selling GLP")
-----------------------------------------------------------------------------------------------------------------------------------
Buying and selling GLP can be done through the GlpRewardRouter.
To buy GLP, call mintAndStakeGlp with params:
* \_token: the token to buy GLP with
* \_amount: the amount of token to use for the purchase
* \_minUsdg: the minimum acceptable USD value of the GLP purchased
* \_minGlp: the minimum acceptable GLP amount
To sell GLP, call unstakeAndRedeemGlp with params:
* \_tokenOut: the token to sell GLP for
* \_glpAmount: the amount of GLP to sell
* \_minOut: the minimum acceptable amount of tokenOut to be received
* \_receiver: the address to send tokenOut to
Note that GLP can only be redeemed up to the reservedAmount, which is based on the amount of open interest, if the pool has been fully redeemed up to the reservedAmount then redeemers will need to wait for positions to close before further redemptions can be done, in this scenario the borrowing fee APR would be very high so liquidity providers will be incentivised to mint GLP and traders will be incentivised to close positions
GLP Price[](https://docs.gmx.io/docs/archived/contracts-v1/#glp-price "Direct link to GLP Price")
---------------------------------------------------------------------------------------------------
The price of GLP can be retrieved using the `getPrice(_maximise)` function of the GlpManager.
* To get the price of GLP for buying GLP use `GlpManager.getPrice(true)`
* To get the price of GLP for selling GLP use `GlpManager.getPrice(false)`
The price of GLP factors in the pending PnL of the open long and short positions.
If you are calculating the pending PnL for shorts manually please use the `glpManager.shortsTracker.globalShortAveragePrices` value instead of the `vault.globalShortAveragePrices` value.
Transferring Staked GLP[](https://docs.gmx.io/docs/archived/contracts-v1/#transferring-staked-glp "Direct link to Transferring Staked GLP")
---------------------------------------------------------------------------------------------------------------------------------------------
When GLP is bought it is automatically staked and when it is sold it is automatically unstaked, for integrations adding GLP the StakedGlp contract can be used to transfer staked GLP tokens.
StakedGlp behaves like a regular ERC20 token, the user can call approve on it to approve your contract, then your contract can call transferFrom to transfer the GLP tokens to any receiving account or contract. When transferring, the StakedGlp contract will unstake GLP from the user and stake the GLP for the receiving account, the receiving account or contract would then start earning rewards which can be compounded or claimed by calling handleRewards on the RewardRouter contract.
Staking[](https://docs.gmx.io/docs/archived/contracts-v1/#staking "Direct link to Staking")
---------------------------------------------------------------------------------------------
The RewardRouter contract handles the necessary actions needed for staking in a single transaction.
When staking GMX:
* The RewardRouter deposits the GMX token into the StakedGmxTracker contract
* The StakedGmxTracker issues itself as a token for each token deposited
* esGMX can similarly be deposited into the StakedGmxTracker
* The StakedGmxTracker distributes esGMX to staked tokens
* After this step, the RewardRouter deposits the StakedGmxTracker tokens into the BonusGmxTracker
* The BonusGmxTracker distributes Multiplier Points to staked tokens
* Finally the BonusGmxTracker tokens are deposited into the FeeGmxTracker which distributes ETH or AVAX to staked tokens
When buying GLP:
* The RewardRouter sends the funds to be deposited to the GlpManager and mints GLP tokens
* The RewardRouter then deposits the GLP tokens to the FeeGlpTracker which distributes ETH or AVAX to the staked tokens
* Finally the RewardRouter deposits the FeeGlpTracker tokens into the StakedGlpTracker which distributes esGMX to staked tokens
Addresses for contracts can be found in the [interface code](https://github.com/gmx-io/gmx-interface/blob/master/src/config/contracts.ts)
.
To get the deposit balances for an account you can use RewardTracker.depositBalances(account, token), or RewardReader.getDepositBalances(account, depositTokens, rewardTrackers).
To get claimable rewards you can use RewardReader.getStakingInfo(account rewardTrackers), this returns an array of uint256 values in the order:
* Claimable rewards
* Amount of reward token distribution per second
* Average staked amount for account
* Total rewards distributed to account
* Total staked tokens in the rewardTracker
* [Important Notes](https://docs.gmx.io/docs/archived/contracts-v1/#important-notes)
* [Overview](https://docs.gmx.io/docs/archived/contracts-v1/#overview)
* [Arbitrum](https://docs.gmx.io/docs/archived/contracts-v1/#arbitrum)
* [Avalanche](https://docs.gmx.io/docs/archived/contracts-v1/#avalanche)
* [Swap](https://docs.gmx.io/docs/archived/contracts-v1/#swap)
* [Query Available Amounts](https://docs.gmx.io/docs/archived/contracts-v1/#query-available-amounts)
* [Opening / Increasing a Position](https://docs.gmx.io/docs/archived/contracts-v1/#opening--increasing-a-position)
* [Closing / Decreasing a Position](https://docs.gmx.io/docs/archived/contracts-v1/#closing--decreasing-a-position)
* [Positions List](https://docs.gmx.io/docs/archived/contracts-v1/#positions-list)
* [Buying / Selling GLP](https://docs.gmx.io/docs/archived/contracts-v1/#buying--selling-glp)
* [GLP Price](https://docs.gmx.io/docs/archived/contracts-v1/#glp-price)
* [Transferring Staked GLP](https://docs.gmx.io/docs/archived/contracts-v1/#transferring-staked-glp)
* [Staking](https://docs.gmx.io/docs/archived/contracts-v1/#staking)
---
# Updates and Support | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/updates-support/#__docusaurus_skipToContent_fallback)
For contract and API updates, subscribe to the [@GMX\_Technical\_Announcements](https://t.me/GMX_Technical_Announcements)
Telegram channel.
Important changes will likely be posted there, but that channel may not cover all updates. Other channels worth monitoring:
* [GMX Substack](https://gmxio.substack.com/)
* [GMX Repositories](https://github.com/gmx-io)
* [@GMX\_Announcements](https://t.me/GMX_Announcements)
For API or SDK support, join the [GMX Discord](https://discord.com/invite/H5PeQru3Aa)
to create a support ticket.
---
# GetMarketsTickers | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/gmx-api/get-markets-tickers/#__docusaurus_skipToContent_fallback)
GetMarketsTickers
=================
GET
https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/api/v1/markets/tickers
------------------------------------------------------------------------
GetMarketsTickers
Request[](https://docs.gmx.io/docs/api/gmx-api/get-markets-tickers/#request "Direct link to request")
-------------------------------------------------------------------------------------------------------
### Query Parameters
**addresses** string\[\]
**symbols** string\[\]
Responses[](https://docs.gmx.io/docs/api/gmx-api/get-markets-tickers/#responses "Direct link to Responses")
-------------------------------------------------------------------------------------------------------------
* 200
* 400
* 500
Success
* application/json
* Schema
* Example (auto)
**Schema**
* Array \[\
\
\
**netRateShort**stringrequired\
\
**netRateLong**stringrequired\
\
**borrowingRateShort**stringrequired\
\
**borrowingRateLong**stringrequired\
\
**fundingRateShort**stringrequired\
\
**fundingRateLong**stringrequired\
\
**poolAmountShortUsd**stringrequired\
\
**poolAmountLongUsd**stringrequired\
\
**availableLiquidityShort**stringrequired\
\
**availableLiquidityLong**stringrequired\
\
**shortInterestUsdMark**stringrequired\
\
**longInterestUsdMark**stringrequired\
\
**shortInterestUsd**stringrequired\
\
**longInterestUsd**stringrequired\
\
**shortInterestInTokens**stringrequired\
\
**longInterestInTokens**stringrequired\
\
**priceChangePercent24hBps**stringrequired\
\
**priceChange24h**stringrequired\
\
**close24h**stringrequired\
\
**open24h**stringrequired\
\
**low24h**stringrequired\
\
**high24h**stringrequired\
\
**markPrice**stringrequired\
\
**maxPrice**stringrequired\
\
**minPrice**stringrequired\
\
**marketTokenAddress**stringrequired\
\
**symbol**stringrequired\
\
* \]
[ { "netRateShort": "string", "netRateLong": "string", "borrowingRateShort": "string", "borrowingRateLong": "string", "fundingRateShort": "string", "fundingRateLong": "string", "poolAmountShortUsd": "string", "poolAmountLongUsd": "string", "availableLiquidityShort": "string", "availableLiquidityLong": "string", "shortInterestUsdMark": "string", "longInterestUsdMark": "string", "shortInterestUsd": "string", "longInterestUsd": "string", "shortInterestInTokens": "string", "longInterestInTokens": "string", "priceChangePercent24hBps": "string", "priceChange24h": "string", "close24h": "string", "open24h": "string", "low24h": "string", "high24h": "string", "markPrice": "string", "maxPrice": "string", "minPrice": "string", "marketTokenAddress": "string", "symbol": "string" }]
Bad Request - Invalid market addresses or symbols
Internal Server Error
* python
* nodejs
* curl
* HTTP.CLIENT
* REQUESTS
RequestCollapse all
Base URL
Edit
https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/api/v1
ParametersShow optional parameters
addresses — query
Add item
symbols — query
Add item
---
# GetMarketsInfo | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/gmx-api/get-markets-info/#__docusaurus_skipToContent_fallback)
GetMarketsInfo
==============
GET
/markets/info
-------------
GetMarketsInfo
Request[](https://docs.gmx.io/docs/api/gmx-api/get-markets-info/#request "Direct link to request")
----------------------------------------------------------------------------------------------------
Responses[](https://docs.gmx.io/docs/api/gmx-api/get-markets-info/#responses "Direct link to Responses")
----------------------------------------------------------------------------------------------------------
* 200
* 500
Success
Internal Server Error
---
# Oracle Prices | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/rest-api/oracle-prices/#__docusaurus_skipToContent_fallback)
On this page
REST endpoints for oracle information.
Use this page for public price and token reads. For workflow guidance across REST, GraphQL, and SDK surfaces, start with the [API integration guide](https://docs.gmx.io/docs/api/integration-guide/)
.
Ping[](https://docs.gmx.io/docs/api/rest-api/oracle-prices/#ping "Direct link to Ping")
-----------------------------------------------------------------------------------------
Use the ping endpoint to check whether the oracle API is healthy. The endpoint verifies database connectivity and returns a JSON response.
| Network | URL |
| --- | --- |
| Arbitrum | `https://arbitrum-api.gmxinfra.io/ping` |
| Avalanche | `https://avalanche-api.gmxinfra.io/ping` |
| Botanix | `https://botanix-api.gmxinfra.io/ping` |
**Success response** (`200 OK`):
{ "ok": true }
**Error response** (`500 Internal Server Error`):
{ "errors": ["db is unavailable"] }
Tickers[](https://docs.gmx.io/docs/api/rest-api/oracle-prices/#tickers "Direct link to Tickers")
--------------------------------------------------------------------------------------------------
The tickers endpoint returns the latest price data for all supported tokens. Use this endpoint for real-time price display in your application.
| Network | URL |
| --- | --- |
| Arbitrum | `https://arbitrum-api.gmxinfra.io/prices/tickers` |
| Avalanche | `https://avalanche-api.gmxinfra.io/prices/tickers` |
| Botanix | `https://botanix-api.gmxinfra.io/prices/tickers` |
**Response** — an array of ticker objects:
[ { "tokenSymbol": "ETH", "tokenAddress": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", "minPrice": "1799910000000000000000000000000000", "maxPrice": "1800090000000000000000000000000000", "medianPrice": "1800000000000000000000000000000000", "oracleDecimals": 8, "updatedAt": 1708956120 }]
Prices are represented as strings scaled to 30 decimal places. Divide by `10^(30 - tokenDecimals - oracleDecimals)` to get the USD price.
Signed prices[](https://docs.gmx.io/docs/api/rest-api/oracle-prices/#signed-prices "Direct link to Signed prices")
--------------------------------------------------------------------------------------------------------------------
The signed prices endpoint returns the latest oracle-signed price data for each supported token. Include these signed prices in your transaction payloads when interacting with GMX contracts on-chain.
| Network | URL |
| --- | --- |
| Arbitrum | `https://arbitrum-api.gmxinfra.io/signed_prices/latest` |
| Avalanche | `https://avalanche-api.gmxinfra.io/signed_prices/latest` |
| Botanix | `https://botanix-api.gmxinfra.io/signed_prices/latest` |
**Response**:
{ "signedPrices": [ { "tokenSymbol": "ETH", "tokenAddress": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", "minPrice": "1799910000000000000000000000000000", "maxPrice": "1800090000000000000000000000000000", "medianPrice": "1800000000000000000000000000000000", "oracleDecimals": 8, "signer": "0xabc...def", "signature": "0x...", "signatureWithoutBlockHash": "0x...", "tokenOracleType": 0, "salt": "0x...", "minBlockNumber": 123456789, "minBlockTimestamp": 1708956000, "minBlockHash": "0x...", "maxBlockNumber": 123456799, "maxBlockTimestamp": 1708956120, "maxBlockHash": "0x...", "createdAt": 1708956120.5 } ]}
Candlesticks[](https://docs.gmx.io/docs/api/rest-api/oracle-prices/#candlesticks "Direct link to Candlesticks")
-----------------------------------------------------------------------------------------------------------------
The candlesticks endpoint returns OHLC price data for a given token and time period. Candles are returned in descending order (most recent first).
| Network | Base URL |
| --- | --- |
| Arbitrum | `https://arbitrum-api.gmxinfra.io/prices/candles` |
| Avalanche | `https://avalanche-api.gmxinfra.io/prices/candles` |
| Botanix | `https://botanix-api.gmxinfra.io/prices/candles` |
**Required query parameters:**
* `tokenSymbol` — the token symbol, for example `ETH` or `BTC`
* `period` — one of `1m`, `5m`, `15m`, `1h`, `4h`, or `1d`
**Optional query parameters:**
* `limit` — maximum number of candles to return. Defaults to `1000`. Minimum: `1`. Maximum: `10000`.
**Example request:**
GET https://arbitrum-api.gmxinfra.io/prices/candles?tokenSymbol=ETH&period=1d&limit=2
**Response:**
{ "period": "1d", "candles": [ [1701388800, 2150.25, 2180.5, 2145.0, 2175.3], [1701302400, 2120.1, 2155.0, 2110.0, 2150.25] ]}
Each candle is an array of five values in this order:
1. `timestamp` — Unix timestamp (seconds) of the candle period start
2. `open` — opening price
3. `high` — highest price during the period
4. `low` — lowest price during the period
5. `close` — closing price
Tokens[](https://docs.gmx.io/docs/api/rest-api/oracle-prices/#tokens "Direct link to Tokens")
-----------------------------------------------------------------------------------------------
The tokens endpoint returns a list of all tokens supported by the oracle on a given network.
| Network | URL |
| --- | --- |
| Arbitrum | `https://arbitrum-api.gmxinfra.io/tokens` |
| Avalanche | `https://avalanche-api.gmxinfra.io/tokens` |
| Botanix | `https://botanix-api.gmxinfra.io/tokens` |
Operational notes[](https://docs.gmx.io/docs/api/rest-api/oracle-prices/#operational-notes "Direct link to Operational notes")
--------------------------------------------------------------------------------------------------------------------------------
* `/prices/tickers`, `/signed_prices/latest`, and `/prices/candles` use a `10` second route timeout in the current oracle-keeper implementation.
* `/prices/tickers` uses a short in-process cache of `0.3` seconds in the current implementation.
* `/signed_prices/latest` is cached for `1` second in the current implementation.
* `/prices/candles` is cached for `15` seconds for `1m` and `5m` periods, and `60` seconds for larger periods.
* `/tokens` returns the configured token list for the network. If you need richer token data with current prices, use API v2 or SDK v2, which read from `/tokens/info`.
* If you need retries or fallback behavior, implement that in your app. These docs do not publish a public SLA.
* [Ping](https://docs.gmx.io/docs/api/rest-api/oracle-prices/#ping)
* [Tickers](https://docs.gmx.io/docs/api/rest-api/oracle-prices/#tickers)
* [Signed prices](https://docs.gmx.io/docs/api/rest-api/oracle-prices/#signed-prices)
* [Candlesticks](https://docs.gmx.io/docs/api/rest-api/oracle-prices/#candlesticks)
* [Tokens](https://docs.gmx.io/docs/api/rest-api/oracle-prices/#tokens)
* [Operational notes](https://docs.gmx.io/docs/api/rest-api/oracle-prices/#operational-notes)
---
# Unknown
\# GMX Docs
> LLM-friendly documentation index and full-text bundle for GMX.
This file contains links to documentation sections following the llmstxt.org standard.
## Table of Contents
- \[GMX\](https://docs.gmx.io/docs/intro.md): GMX is a decentralized spot and perpetual exchange on Arbitrum, Avalanche, Botanix, and MegaETH. It supports perpetual trades with up to 100x lever...
- \[AI Agents\](https://docs.gmx.io/docs/ai-agents/overview.md): GMX is built for both humans and AI agents. The protocol's oracle-based pricing, deterministic execution, and comprehensive APIs make it the ideal ...
- \[Plugins and Skills\](https://docs.gmx.io/docs/ai-agents/plugins-and-skills.md): The \[\`gmx-io/gmx-ai\`\](https://github.com/gmx-io/gmx-ai) repository provides pre-built agent skills that give AI coding agents the ability to trade ...
- \[Frontend Integration\](https://docs.gmx.io/docs/api/frontend-integration.md): The GMX protocol consists of smart contracts deployed on blockchains.
- \[Integration guide\](https://docs.gmx.io/docs/api/integration-guide.md): Use this page when you want exact integration steps. The hand-written API pages explain which surfaces exist and how they behave operationally. The...
- \[API Overview\](https://docs.gmx.io/docs/api/overview.md): GMX exposes several integration points for developers, integrators, and AI agents building on the protocol. Start with the integration surface that...
- \[Troubleshooting\](https://docs.gmx.io/docs/api/troubleshooting.md): Use this page when API reads do not match what you expect. Most issues fall into one of four buckets: invalid request parameters, stale snapshots, ...
- \[Updates and Support\](https://docs.gmx.io/docs/api/updates-support.md): For contract and API updates, subscribe to the \[@GMX\_Technical\_Announcements\](https://t.me/GMX\_Technical\_Announcements) Telegram channel.
- \[@gmx-io/gmx-public-api\](https://docs.gmx.io/docs/api/gmx-api/gmx-io-gmx-public-api.md): GMX public API overview, Swagger spec links, and base URLs.
- \[Changelog\](https://docs.gmx.io/docs/sdk/changelog.md): This release expands the \`GmxApiSdk\` read surface to cover more GMX HTTP endpoints and exports the matching typed response helpers.
- \[SDK Overview\](https://docs.gmx.io/docs/sdk/overview.md): The GMX SDK (\`@gmx-io/sdk\`) is a TypeScript library for integrating GMX perpetuals and spot trading into your application. It wraps the GMX smart c...
- \[Examples\](https://docs.gmx.io/docs/sdk/v1/examples.md): Use this page for focused runnable snippets. If you want end-to-end trading flows or operational guidance, start with the \[Integration guide\](./int...
- \[api\](https://docs.gmx.io/docs/sdk/v1/exports/configs/api.md): This module exposes the SDK's GMX REST API endpoint lookup helpers.
- \[batch\](https://docs.gmx.io/docs/sdk/v1/exports/configs/batch.md): This module exposes batching defaults used by the SDK's viem transports and paginated Subsquid helpers.
- \[chainIds\](https://docs.gmx.io/docs/sdk/v1/exports/configs/chainIds.md): This module exports the raw numeric chain ID constants used across the SDK, without the richer metadata from \[\`configs/chains\`\](./chains.md).
- \[chains\](https://docs.gmx.io/docs/sdk/v1/exports/configs/chains.md): This module provides chain configuration constants, types, and utilities for the GMX protocol. It includes chain IDs, names, gas configurations, ex...
- \[contracts\](https://docs.gmx.io/docs/sdk/v1/exports/configs/contracts.md): This module provides contract addresses for the GMX protocol across different blockchain networks. It includes addresses for V1, V2 (Synthetics), G...
- \[dataStore\](https://docs.gmx.io/docs/sdk/v1/exports/configs/dataStore.md): This module is the SDK's public registry of GMX \`DataStore\` key constants and key-builder helpers.
- \[express\](https://docs.gmx.io/docs/sdk/v1/exports/configs/express.md): This module exports constants and helpers for express trading, subaccounts, and Gelato-relayed flows.
- \[factors\](https://docs.gmx.io/docs/sdk/v1/exports/configs/factors.md): This module provides constants for various impact thresholds, slippage limits, and basis point calculations used throughout the GMX protocol. These...
- \[gasLimits\](https://docs.gmx.io/docs/sdk/v1/exports/configs/gasLimits.md): This module exports the SDK's static gas-limit defaults.
- \[markets\](https://docs.gmx.io/docs/sdk/v1/exports/configs/markets.md): This module provides market configuration data for the GMX protocol across different blockchain networks. It contains predefined market configurati...
- \[multichain\](https://docs.gmx.io/docs/sdk/v1/exports/configs/multichain.md): This module exports chain guards used by the SDK's multichain funding logic.
- \[oracleKeeper\](https://docs.gmx.io/docs/sdk/v1/exports/configs/oracleKeeper.md): This module provides utilities for retrieving Oracle Keeper URLs for different blockchain networks supported by the GMX protocol. Oracle Keepers ar...
- \[tokens\](https://docs.gmx.io/docs/sdk/v1/exports/configs/tokens.md): This module provides comprehensive token configuration and utilities for the GMX protocol across different blockchain networks. It includes token d...
- \[twap\](https://docs.gmx.io/docs/sdk/v1/exports/configs/twap.md): This module exports TWAP configuration defaults.
- \[uniswapV3\](https://docs.gmx.io/docs/sdk/v1/exports/configs/uniswapV3.md): This module exposes Uniswap v3 deployment metadata used by external-swap integrations.
- \[venus\](https://docs.gmx.io/docs/sdk/v1/exports/configs/venus.md): This module exposes Venus deployment metadata used by integrations that need Venus token support.
- \[Useful modules\](https://docs.gmx.io/docs/sdk/v1/exports/exports.md): The GMX SDK exports constants, types, and utility functions that you can import directly without going through the \`GmxSdk\` class. These exports ar...
- \[24h types\](https://docs.gmx.io/docs/sdk/v1/exports/types/24h.md): This type-only entrypoint exports candle data used by the SDK's 24-hour market views.
- \[chains types\](https://docs.gmx.io/docs/sdk/v1/exports/types/chains.md): This type-only entrypoint exports chain configuration shapes.
- \[fees types\](https://docs.gmx.io/docs/sdk/v1/exports/types/fees.md): This type-only entrypoint exports fee and gas-limit model types.
- \[markets types\](https://docs.gmx.io/docs/sdk/v1/exports/types/markets.md): This type-only entrypoint exports the SDK's market and market-info model types.
- \[orders types\](https://docs.gmx.io/docs/sdk/v1/exports/types/orders.md): This type-only entrypoint exports order enums and enriched order model types.
- \[positions types\](https://docs.gmx.io/docs/sdk/v1/exports/types/positions.md): This type-only entrypoint exports raw and enriched position model types.
- \[prices types\](https://docs.gmx.io/docs/sdk/v1/exports/types/prices.md): This type-only entrypoint exports OHLCV candle shapes and request params for the SDK's price candle API helpers.
- \[referrals types\](https://docs.gmx.io/docs/sdk/v1/exports/types/referrals.md): This type-only entrypoint exports the SDK's referral data shapes.
- \[sdk types\](https://docs.gmx.io/docs/sdk/v1/exports/types/sdk.md): This type-only entrypoint exports the v1 client config interface.
- \[sidecarOrders types\](https://docs.gmx.io/docs/sdk/v1/exports/types/sidecarOrders.md): This type-only entrypoint exports sidecar stop-loss, take-profit, and limit-order entry types.
- \[subsquid types\](https://docs.gmx.io/docs/sdk/v1/exports/types/subsquid.md): This type-only entrypoint re-exports the generated GraphQL schema types from the SDK's Subsquid codegen.
- \[swap types\](https://docs.gmx.io/docs/sdk/v1/exports/types/swap.md): This type-only entrypoint exports the swap-strategy model types used by the trade helpers.
- \[tokens types\](https://docs.gmx.io/docs/sdk/v1/exports/types/tokens.md): This type-only entrypoint exports token metadata, pricing, and balance model types.
- \[trade types\](https://docs.gmx.io/docs/sdk/v1/exports/types/trade.md): This type-only entrypoint exports the main trade calculation enums and result types.
- \[tradeHistory types\](https://docs.gmx.io/docs/sdk/v1/exports/types/tradeHistory.md): This type-only entrypoint exports the SDK's normalized trade-history action types.
- \[twap types\](https://docs.gmx.io/docs/sdk/v1/exports/types/twap.md): This type-only entrypoint exports TWAP timing and order-part parameter types.
- \[LruCache\](https://docs.gmx.io/docs/sdk/v1/exports/utils/LruCache.md): This module exports a small in-memory least-recently-used cache.
- \[abort\](https://docs.gmx.io/docs/sdk/v1/exports/utils/abort.md): This module exports abort-signal composition helpers.
- \[bigmath\](https://docs.gmx.io/docs/sdk/v1/exports/utils/bigmath.md): This module provides mathematical utility functions for working with BigInt values, offering operations like absolute value, multiplication with di...
- \[buildUrl\](https://docs.gmx.io/docs/sdk/v1/exports/utils/buildUrl.md): This module exports the URL builder used by the SDK's HTTP helpers.
- \[chains\](https://docs.gmx.io/docs/sdk/v1/exports/utils/chains.md): This module is a type-only re-export for chain configuration shapes used by the SDK.
- \[common\](https://docs.gmx.io/docs/sdk/v1/exports/utils/common.md): This module exports small shared helpers used across the SDK.
- \[errors\](https://docs.gmx.io/docs/sdk/v1/exports/utils/errors.md): This module exposes helpers for extracting and decoding transaction errors, especially viem and GMX custom errors.
- \[estimateOraclePriceCount\](https://docs.gmx.io/docs/sdk/v1/exports/utils/fees/estimateOraclePriceCount.md): This module provides utilities for estimating the number of oracle prices required for various GMX protocol operations. These functions help calcul...
- \[executionFee\](https://docs.gmx.io/docs/sdk/v1/exports/utils/fees/executionFee.md): This module provides utilities for calculating execution fees and estimating gas limits for various GMX protocol operations. It handles fee calcula...
- \[fees\](https://docs.gmx.io/docs/sdk/v1/exports/utils/fees/fees.md): This module provides utilities for calculating various fees in the GMX protocol, including swap fees, position fees, funding fees, borrowing fees, ...
- \[getNaiveEstimatedGasBySwapCount\](https://docs.gmx.io/docs/sdk/v1/exports/utils/fees/getNaiveEstimatedGasBySwapCount.md): This module provides a utility function for calculating estimated gas costs based on the number of swaps in a transaction.
- \[priceImpact\](https://docs.gmx.io/docs/sdk/v1/exports/utils/fees/priceImpact.md): This module provides utilities for calculating price impact in GMX protocol operations, including position trades and swaps. It handles price impac...
- \[gelatoRelay\](https://docs.gmx.io/docs/sdk/v1/exports/utils/gelatoRelay.md): This module exports Gelato relayer helpers and re-exported status types from \`@gelatocloud/gasless\`.
- \[graphqlFetcher\](https://docs.gmx.io/docs/sdk/v1/exports/utils/graphqlFetcher.md): This module exports the SDK's default GraphQL POST fetch helper.
- \[hash\](https://docs.gmx.io/docs/sdk/v1/exports/utils/hash.md): This module exports low-level hashing helpers used for SDK key generation.
- \[indexers\](https://docs.gmx.io/docs/sdk/v1/exports/utils/indexers.md): This module exports helper types and functions for building GraphQL filter bodies and paginating indexer reads.
- \[markets\](https://docs.gmx.io/docs/sdk/v1/exports/utils/markets.md): This module provides utilities for working with GMX markets, including market naming, pricing, liquidity calculations, and PnL computations. It han...
- \[numbers\](https://docs.gmx.io/docs/sdk/v1/exports/utils/numbers.md): This module provides comprehensive utilities for handling numeric operations, formatting, and conversions in the GMX protocol. It includes function...
- \[objects\](https://docs.gmx.io/docs/sdk/v1/exports/utils/objects.md): This module exports dictionary helpers used across the SDK.
- \[orders\](https://docs.gmx.io/docs/sdk/v1/exports/utils/orders.md): This module provides utilities for working with GMX orders, including type checking functions, order information processing, and order classificati...
- \[positions\](https://docs.gmx.io/docs/sdk/v1/exports/utils/positions.md): This module provides utilities for working with trading positions in the GMX protocol. It includes functions for calculating position metrics, PnL,...
- \[prices\](https://docs.gmx.io/docs/sdk/v1/exports/utils/prices.md): This module provides utilities for calculating prices, price impacts, and acceptable price ranges for GMX trading operations. This page also covers...
- \[referrals\](https://docs.gmx.io/docs/sdk/v1/exports/utils/referrals.md): This module exports referral-code helpers and referral-related data types.
- \[sidecarOrders\](https://docs.gmx.io/docs/sdk/v1/exports/utils/sidecarOrders.md): This module is a type-only re-export for sidecar stop-loss, take-profit, and limit-order entry shapes.
- \[findReachableTokens\](https://docs.gmx.io/docs/sdk/v1/exports/utils/swap/findReachableTokens.md): This module provides functionality to find all tokens that can be reached from each token in a markets graph through swap operations, respecting ma...
- \[findSwapPathsBetweenTokens\](https://docs.gmx.io/docs/sdk/v1/exports/utils/swap/findSwapPathsBetweenTokens.md): This module computes all valid intermediate-token sequences for swapping between any two tokens in a \`MarketsGraph\`. The result is a precomputed lo...
- \[preparedSwapData\](https://docs.gmx.io/docs/sdk/v1/exports/utils/swap/preparedSwapData.md): This module provides pre-computed swap data structures for efficient token swapping operations across different chains. It contains adjacency graph...
- \[swap\](https://docs.gmx.io/docs/sdk/v1/exports/utils/swap/swap.md): This module provides utilities for calculating swap statistics and values in the GMX protocol. It includes functions for computing swap fees, price...
- \[swapPath\](https://docs.gmx.io/docs/sdk/v1/exports/utils/swap/swapPath.md): This module provides utilities for finding optimal swap paths between tokens in the GMX protocol. It handles path discovery, liquidity analysis, an...
- \[swapRouting\](https://docs.gmx.io/docs/sdk/v1/exports/utils/swap/swapRouting.md): This module provides utilities for finding optimal swap routes between tokens in GMX markets. It includes functions for creating swap estimators, f...
- \[swapStats\](https://docs.gmx.io/docs/sdk/v1/exports/utils/swap/swapStats.md): This module provides utilities for calculating swap statistics, capacity, and liquidity for token swaps within GMX markets. It includes functions f...
- \[swapValues\](https://docs.gmx.io/docs/sdk/v1/exports/utils/swap/swapValues.md): This module provides utilities for calculating swap amounts and values for token exchanges in the GMX protocol. It handles both internal GMX swaps ...
- \[time\](https://docs.gmx.io/docs/sdk/v1/exports/utils/time.md): This module exports simple period-conversion helpers.
- \[tokens\](https://docs.gmx.io/docs/sdk/v1/exports/utils/tokens.md): This module provides utilities for token price conversions, amount calculations, and token relationship operations in the GMX protocol. It handles ...
- \[decrease\](https://docs.gmx.io/docs/sdk/v1/exports/utils/trade/decrease.md): This module provides utilities for calculating decrease position amounts, fees, and next position values when closing or reducing trading positions...
- \[increase\](https://docs.gmx.io/docs/sdk/v1/exports/utils/trade/increase.md): This module provides utilities for calculating increase position amounts, prices, and next position values for GMX trading operations. It handles d...
- \[trade\](https://docs.gmx.io/docs/sdk/v1/exports/utils/trade/trade.md): This module provides utility functions for trade operations including slippage calculations, swap counting, and trade flag creation for the GMX pro...
- \[tradeHistory\](https://docs.gmx.io/docs/sdk/v1/exports/utils/tradeHistory.md): This module exports typed helpers for transforming Subsquid trade history records into SDK trade actions.
- \[twap\](https://docs.gmx.io/docs/sdk/v1/exports/utils/twap.md): This module exports helpers for validating and deriving TWAP order timing.
- \[types\](https://docs.gmx.io/docs/sdk/v1/exports/utils/types.md): This module exports small shared TypeScript utility types.
- \[Integration guide\](https://docs.gmx.io/docs/sdk/v1/integration-guide.md): Use this page when you want exact steps instead of a function-by-function reference. The \[Getting Started\](./readme.mdx) page explains the SDK surf...
- \[Troubleshooting\](https://docs.gmx.io/docs/sdk/v1/troubleshooting.md): Use this page when SDK v1 reads or writes do not behave the way you expect. Most production issues fall into one of five buckets: missing receipt h...
- \[Getting Started\](https://docs.gmx.io/docs/sdk/v2/readme.md): If you only need read-only HTTP data without RPC calls, use the read-only API client:
- \[Contract addresses\](https://docs.gmx.io/docs/api/contracts/addresses.md): This page lists the key contract addresses for each supported chain. For the complete list of all deployed contracts (100+ per chain), see the \[gmx...\
- \[Advanced entry points\](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints.md): This page covers the contract surfaces beyond the core \`ExchangeRouter\` / \`GlvRouter\` flow: delegated subaccount trading, gasless relay routers, an...\
- \[Architecture\](https://docs.gmx.io/docs/api/contracts/architecture.md): This page covers the GMX smart contract architecture, execution model, keeper network, and integration considerations. For contract function refere...\
- \[Delegated trading integration\](https://docs.gmx.io/docs/api/contracts/delegated-trading.md): This page explains how to build delegated trading flows on GMX V2 using the subaccount and relay surfaces documented in \[Advanced entry points\](./a...\
- \[Event monitoring\](https://docs.gmx.io/docs/api/contracts/events.md): All protocol events are emitted through a single \`EventEmitter\` contract. Every event carries an \`eventName\` field, so you can monitor any protocol...\
- \[ExchangeRouter\](https://docs.gmx.io/docs/api/contracts/exchange-router.md): The \`ExchangeRouter\` contract exposes the main protocol functions for creating orders, deposits, and withdrawals.\
- \[Fees\](https://docs.gmx.io/docs/api/contracts/fees.md): This page documents fee types, execution fee calculation, and how to retrieve fee parameters from the DataStore.\
- \[GlvReader\](https://docs.gmx.io/docs/api/contracts/glv-reader.md): The \`GlvReader\` contract provides read-only functions for querying GMX Liquidity Vault (GLV) data from on-chain storage.\
- \[GlvRouter\](https://docs.gmx.io/docs/api/contracts/glv-router.md): The \`GlvRouter\` contract is the main entry point for creating and cancelling GLV (GMX Liquidity Vault) deposits and withdrawals. It works similarly...\
- \[Known issues\](https://docs.gmx.io/docs/api/contracts/known-issues.md): This page is based on the known issues section of the \[gmx-synthetics repository\](https://github.com/gmx-io/gmx-synthetics/blob/updates/README.md#k...\
- \[Overview\](https://docs.gmx.io/docs/api/contracts/overview.md): Docs for the GMX contracts. This section focuses on the contracts most integrations interact with directly, not an exhaustive page for every deploy...\
- \[Reader\](https://docs.gmx.io/docs/api/contracts/reader.md): The Reader contract provides convenience functions for retrieving information such as markets, positions, and pricing data.\
- \[Simulations\](https://docs.gmx.io/docs/api/contracts/simulations.md): The \`ExchangeRouter\` and \`GlvRouter\` contracts expose public simulation functions that let you dry-run an execution against a set of supplied price...\
- \[GraphQL\](https://docs.gmx.io/docs/api/graphql.md): GMX provides GraphQL endpoints powered by Subsquid for querying indexed on-chain data.\
- \[Fallback URLs\](https://docs.gmx.io/docs/api/rest-api/fallback-urls.md): When the primary API endpoint is unavailable for a chain, use the corresponding fallback endpoint below.\
- \[Liquidity\](https://docs.gmx.io/docs/api/rest-api/liquidity.md): REST endpoints for APY, performance, and GLV information.\
- \[Markets\](https://docs.gmx.io/docs/api/rest-api/markets.md): REST endpoints for trading market information.\
- \[Oracle Prices\](https://docs.gmx.io/docs/api/rest-api/oracle-prices.md): REST endpoints for oracle information.\
- \[Contracts for V1\](https://docs.gmx.io/docs/archived/contracts-v1.md): Docs for the GMX V1 contracts.\
- \[Liquidity on V1\](https://docs.gmx.io/docs/archived/liquidity-v1.md): GLP was the liquidity provider token for V1. Since July 2025, GLP has been phased out and no longer provides liquidity as V1 trading is disabled, s...\
- \[Trading on V1\](https://docs.gmx.io/docs/archived/trading-v1.md): Trading on V1 has been phased out since July 2025. Please close any positions using \[v1.app.gmx.io\](https://v1.app.gmx.io/#/v1).\
- \[Community\](https://docs.gmx.io/docs/community.md): Stay up to date with GMX news and connect with the community across the channels listed below.\
- \[Proposal Process\](https://docs.gmx.io/docs/governance/proposal-process.md): Submitting a proposal to the GMX DAO follows a structured process, outlined below:\
- \[Voting power\](https://docs.gmx.io/docs/governance/voting-power.md): The \`GMX\_DAO\` token is the governance token of the GMX DAO. It lets you participate directly in protocol governance through on-chain voting and del...\
- \[Providing liquidity\](https://docs.gmx.io/docs/providing-liquidity.md): GMX lets you earn yield by depositing tokens into liquidity pools. These pools back leverage trading and swaps on the platform, and liquidity provi...\
- \[Referrals\](https://docs.gmx.io/docs/referrals.md): Get fee discounts and earn rewards through the GMX referral program.\
- \[Getting Started\](https://docs.gmx.io/docs/sdk/v1/readme.md): The full SDK v1 client (\`GmxSdk\`) exposes these top-level modules:\
- \[Security\](https://docs.gmx.io/docs/security.md): This page covers general safety practices, audit reports, and the bug bounty program.\
- \[GMX token\](https://docs.gmx.io/docs/tokenomics/gmx-token.md): GMX is the platform's utility and governance token. Staking GMX earns you a share of protocol fees — 27% of fees from leverage trading, liquidation...\
- \[Rewards\](https://docs.gmx.io/docs/tokenomics/rewards.md): Staking GMX earns you a share of protocol fees. 27% of fees from leverage trading, liquidations, borrowing fees, and swaps are used to buy back GMX...\
- \[Direct URLs\](https://docs.gmx.io/docs/trading/direct-urls.md): The GMX frontend supports direct URLs that pre-fill trade parameters, letting you share specific trading configurations or deep-link users into a p...\
- \[Fees\](https://docs.gmx.io/docs/trading/fees.md): This page covers all fees on GMX, including trading fees, swap fees, price impact, funding, borrowing, and network fees.\
- \[Liquidations and ADL\](https://docs.gmx.io/docs/trading/liquidations.md): This page covers liquidation mechanics, Auto-Deleveraging (ADL), and trading risks.\
- \[Positions and order types\](https://docs.gmx.io/docs/trading/order-types.md): This page covers how pricing works on GMX, how to open and manage positions, the available order types, and swaps.\
- \[Trading overview\](https://docs.gmx.io/docs/trading/overview.md): GMX is a decentralized exchange that lets you trade without a username or password. The platform uses oracle-based pricing sourced from aggregated ...
---
# Unknown
\# GMX Docs
> LLM-friendly documentation index and full-text bundle for GMX.
This file contains all documentation content in a single document following the llmstxt.org standard.
## GMX
GMX is a decentralized spot and perpetual exchange on Arbitrum, Avalanche, Botanix, and MegaETH. It supports perpetual trades with up to 100x leverage and token swaps with low price impact. The \[GMX Account\](./trading/overview.md#gmx-account-multichain) lets you trade on GMX from any supported chain, including Ethereum, Base, and BNB. GMX uses Chainlink Data Stream oracles for accurate pricing, so liquidations occur only at fair market prices — not at momentary spread spikes.
Trading is powered by GM and GLV liquidity pools. GMX routes every order against these pools and quotes the oracle index price rather than relying on an order book or external market makers. Liquidity providers earn 63% of the fees generated from trading, liquidations, borrowing fees, and swaps on Arbitrum and Avalanche, and 50% on Botanix.
This documentation is structured for both humans and AI agents. Oracle-based pricing, deterministic execution, and comprehensive APIs support a range of use cases — whether you are a trader using the app, a developer building an integration, or an AI agent executing autonomous strategies.
## Get started
Choose your role to find the right starting point.
- \*\*Traders:\*\* \[Trading on GMX\](./trading/overview.md) — Open leveraged positions, place limit orders, and swap tokens.
- \*\*Liquidity providers:\*\* \[Providing liquidity\](./providing-liquidity.md) — Earn yield by depositing into GM or GLV pools.
- \*\*Token holders:\*\* \[GMX token\](./tokenomics/gmx-token.md) — Stake GMX to earn rewards. See also \[Rewards\](./tokenomics/rewards.md).
- \*\*Governance:\*\* \[Voting power\](./governance/voting-power.md) — Participate in protocol governance.
- \*\*Developers:\*\* \[API\](./api/overview.md) — Integrate with GMX contracts, REST endpoints, and the \[TypeScript SDK\](./sdk/overview.md).
- \*\*AI agents:\*\* \[AI Agents\](./ai-agents/overview.md) — Agent \[plugins, skills\](./ai-agents/plugins-and-skills.md), and LLM-optimized documentation for building on GMX.
---
## AI Agents
GMX is built for both humans and AI agents. The protocol's oracle-based pricing, deterministic execution, and comprehensive APIs make it the ideal venue for autonomous on-chain perpetual and spot trading.
## Why GMX for AI agents
Centralized exchanges require API keys, KYC approvals, and custodial trust. GMX combines self-custody with oracle-based pricing and purpose-built primitives for autonomous trading:
- \*\*Non-custodial\*\* — Agents hold their own keys. No exchange custody, no counterparty risk, no account freezes.
- \*\*Permissionless\*\* — No KYC, no API key provisioning, no rate limit negotiations. Any wallet can trade immediately.
- \*\*Oracle-based pricing\*\* — Execution happens at Chainlink oracle prices rather than against an internal pool curve. Price impact is determined by open interest imbalance and is predictable before submission.
- \*\*Gasless execution\*\* — \[Express orders\](../trading/order-types.md) use EIP-712 typed data signing with Gelato Relay. Agents sign off-chain and pay relay fees in supported tokens such as USDC, WETH, or USDM instead of managing native gas tokens.
- \*\*MEV protection\*\* — Two-phase order execution (create then execute via keeper) prevents frontrunning and sandwich attacks. The user's intent is committed on-chain before oracle prices are included.
- \*\*Subaccounts\*\* — Agents operate with scoped on-chain permissions via subaccounts, never exposing the master private key.
- \*\*Up to 100x leverage\*\* — Trade perpetuals across major assets on Arbitrum, Avalanche, Botanix, and MegaETH. Arbitrum has the deepest liquidity and most complete feature set.
- \*\*Multichain trading\*\* — Agents can trade from any chain by depositing into a GMX account, which routes funds to the destination chain without manual bridging. For direct non-custodial trading without account deposits, agents interact with GMX markets on the chains where they are deployed (Arbitrum, Avalanche, Botanix, and MegaETH).
- \*\*Structured data APIs\*\* — REST, GraphQL, on-chain contract reads, and an \[MCP server\](#mcp-server) \*(coming soon)\* provide every data point an agent needs: prices, positions, orders, market conditions, fees, and trade history.
- \*\*TypeScript SDK\*\* — The \[\`@gmx-io/sdk\`\](../sdk/overview.md) package wraps all protocol operations into typed methods. Agents can fetch markets, calculate fees, open positions, and manage orders programmatically.
- \*\*LLM-optimized docs\*\* — This documentation site generates \[\`llms.txt\`\](https://docs.gmx.io/llms.txt) and \[\`llms-full.txt\`\](https://docs.gmx.io/llms-full.txt) bundles for direct model consumption.
## Integration paths
GMX offers multiple integration paths depending on the level of control your agent needs.
| Path | Best for | Capabilities |
|------|----------|-------------|
| \*\*\[Agent plugins and skills\](./plugins-and-skills.md)\*\* | AI coding agents (Claude Code, Codex, Cursor, Copilot, Windsurf, and others) | Pre-built trading skill with SDK and API references bundled |
| \*\*\[TypeScript SDK\](../sdk/overview.md)\*\* | Custom agents and bots | Full read + write access: markets, orders, positions, fees |
| \*\*\[REST API\](../api/overview.md)\*\* | Lightweight data access | Oracle prices, markets, positions, orders, rates |
| \*\*\[MCP server\](#mcp-server)\*\* \*(coming soon)\* | Any MCP-compatible client (Claude, ChatGPT, Codex, Cursor, Copilot, Windsurf, and others) | Market data, positions, orders, pools; trade execution via prepare/confirm |
| \*\*\[Smart contracts\](/docs/category/contracts)\*\* | Direct on-chain interaction | Full protocol access via ExchangeRouter, Reader, GlvReader |
| \*\*\[GraphQL\](../api/graphql.mdx)\*\* | Historical data queries | Trade history, position events, indexed on-chain data |
### Agent plugins and skills
The \[\`gmx-io/gmx-ai\`\](https://github.com/gmx-io/gmx-ai) repository provides ready-to-use agent skills for AI frameworks. These skills bundle trading capabilities with SDK references, API endpoint documentation, contract addresses, and order type specifications so agents can trade on GMX without manual setup. See \[Plugins and skills\](./plugins-and-skills.md) for installation and usage.
### SDK for autonomous agents
The \[SDK v1 (\`GmxSdk\`)\](../sdk/v1/readme.mdx) is the recommended integration for agents that need full trading capabilities. It provides:
- Market discovery and price feeds
- Order creation (market, limit, stop-loss, take-profit)
- Position monitoring and management
- Fee estimation and execution cost calculation
- Automatic RPC batching for efficient data fetching
\`\`\`typescript
const { GmxSdk } = require("@gmx-io/sdk");
const sdk = new GmxSdk({
chainId: 42161,
rpcUrl: "https://arb1.arbitrum.io/rpc",
oracleUrl: "https://arbitrum-api.gmxinfra.io",
subsquidUrl: "https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql",
account: walletAddress,
walletClient,
});
// Fetch markets and open a position
const { marketsInfoData, tokensData } = await sdk.markets.getMarketsInfo();
await sdk.orders.long({
marketAddress,
payTokenAddress: usdcAddress,
collateralTokenAddress: longToken,
payAmount: 100\_000000n,
leverage: 50000n,
});
\`\`\`
See the \[SDK examples\](../sdk/v1/examples.md) for complete agent workflows including position monitoring and closing.
### REST API for lightweight agents
For read-only agents or those that submit transactions separately, the \[REST API\](../api/overview.md) provides oracle prices, market data, and position information over HTTP. No RPC connection or SDK installation needed.
### MCP server
:::note
The MCP server is under development and not yet available.
:::
An \[MCP\](https://modelcontextprotocol.io/) (Model Context Protocol) server is being added as a transport layer to the GMX API. MCP is an open standard supported by \[70+ AI clients\](https://modelcontextprotocol.io/clients) — including Claude, ChatGPT, OpenAI Codex, Cursor, GitHub Copilot, Windsurf, JetBrains, Gemini CLI, Amazon Q, and Cline. Any MCP-compatible client can query GMX data and execute trades directly through the protocol.
The server uses SSE transport mounted alongside the existing REST API, sharing the same domain layer with no separate infrastructure required.
The MCP server ships in two phases:
- \*\*Read-only tools\*\* — Market data, positions, orders, pool information, and account summaries
- \*\*Read-write tools\*\* — Trade execution using a prepare/confirm pattern where the server returns human-readable previews and unsigned transactions, and all signing happens client-side
## Supported chains
| Chain | Chain ID | Native token |
|-------|----------|-------------|
| Arbitrum | 42161 | ETH |
| Avalanche | 43114 | AVAX |
| Botanix | 3637 | BTC |
| MegaETH | 4326 | ETH |
---
## Plugins and Skills
The \[\`gmx-io/gmx-ai\`\](https://github.com/gmx-io/gmx-ai) repository provides pre-built agent skills that give AI coding agents the ability to trade perpetuals, provide liquidity, and swap tokens on GMX V2. Skills use a filesystem-based format compatible with a wide range of agents — see \[Installation\](#installation) for supported clients.
:::note
Skills currently use \[SDK v1\](../sdk/v1/readme.mdx) and direct contract calls for write operations, and the \[REST API\](../api/overview.md) for data access. As API v2 and SDK v2 mature, skills will migrate to fully leverage them — expanding capabilities to cover virtually any protocol action.
:::
## Available skills
The repository ships two skills that cover the main protocol operations.
### gmx-trading
Bundles everything an AI agent needs to trade on GMX:
- \*\*Trading operations\*\* — Open long/short positions with up to 100x leverage, swap tokens at oracle prices, and place market, limit, stop-loss, and take-profit orders.
- \*\*Position management\*\* — Query open positions, pending orders, and trade history.
- \*\*Market data\*\* — Fetch markets, token prices, pool sizes, and utilization rates.
- \*\*Reference material\*\* — SDK method signatures, REST and GraphQL endpoint documentation, contract addresses for all supported chains, and order type behavior specifications.
### gmx-liquidity
Covers liquidity provision across GM pools and GLV vaults:
- \*\*GM pool operations\*\* — Deposit into single-market pools (balanced or single-sided), withdraw, and shift liquidity between pools atomically.
- \*\*GLV vault operations\*\* — Deposit raw tokens or existing GM tokens into multi-market auto-rebalancing vaults, and withdraw.
- \*\*Pool data\*\* — Query pool TVL, composition, utilization, capacity, and GM/GLV token balances.
- \*\*Reference material\*\* — Contract struct definitions, execution flows, gas estimation formulas, GLV vault addresses, and viem multicall examples.
### Supported chains
| Chain | Chain ID | Native token |
|-------|----------|-------------|
| Arbitrum | 42161 | ETH |
| Avalanche | 43114 | AVAX |
| Botanix | 3637 | BTC |
| MegaETH | 4326 | ETH |
## Installation
### Claude Code
Install the GMX plugin from the Claude Code marketplace:
\`\`\`
/plugin marketplace add gmx-io/gmx-ai
/plugin install gmx-io@gmx-ai
\`\`\`
Once installed, Claude Code can execute trades, provide liquidity, query positions, and interact with GMX markets using natural language instructions.
### Skills CLI (Codex, Cursor, Copilot, Windsurf, and others)
Add the skill using the \[Skills CLI\](https://github.com/vercel-labs/skills):
\`\`\`bash
npx skills add gmx-io/gmx-ai
\`\`\`
This installs both the \`gmx-trading\` and \`gmx-liquidity\` skills as filesystem-based context files that any compatible coding agent can read. Supported agents include:
- OpenAI Codex
- Cursor
- GitHub Copilot
- Windsurf
- Gemini CLI
- Amp (Sourcegraph)
- Roo Code
- Goose
- Cline
- Continue
Any agent that reads project-level instruction files from the filesystem can use the skill.
## Reference files
Both skills expose capabilities through shared and skill-specific reference files:
| Reference | Skill | Contents |
|-----------|-------|----------|
| \*\*SDK reference\*\* | Shared | \`GmxSdk\` and \`GmxApiSdk\` class APIs, module methods, type definitions, and initialization patterns |
| \*\*API endpoints\*\* | Shared | Oracle REST endpoints, OpenAPI v2 endpoints, GraphQL queries, and fallback URLs per chain |
| \*\*Contract addresses\*\* | Shared | Deployed contract addresses for ExchangeRouter, Reader, GlvReader, vaults, and relay routers on every supported chain |
| \*\*Order types\*\* | Trading | Order type enum values, trigger conditions for longs and shorts, auto-cancel limits, and TWAP specifications |
| \*\*Liquidity operations\*\* | Liquidity | Contract struct definitions, execution flows, gas estimation formulas, GLV vault addresses, and viem multicall examples |
## How agents use the skills
When an AI agent has the skills installed, it can:
1. \*\*Fetch market data\*\* — Discover available markets, current prices, and pool conditions.
2. \*\*Calculate fees\*\* — Estimate execution fees, position fees, and price impact before placing orders.
3. \*\*Open positions\*\* — Create long or short positions with specified leverage and collateral.
4. \*\*Set conditional orders\*\* — Place limit entries, stop-losses, and take-profit orders.
5. \*\*Monitor positions\*\* — Check open positions, unrealized PnL, and pending orders.
6. \*\*Close positions\*\* — Compute decrease amounts and submit close orders.
7. \*\*Swap tokens\*\* — Execute token swaps at oracle-determined prices.
8. \*\*Deposit liquidity\*\* — Deposit into GM pools (balanced or single-sided) and GLV vaults.
9. \*\*Withdraw liquidity\*\* — Withdraw from GM pools and GLV vaults.
10. \*\*Shift liquidity\*\* — Move GM tokens between pools atomically without withdrawing first.
## Repository structure
\`\`\`
gmx-io/gmx-ai/
.well-known/skills/ # Vercel Skills protocol
index.json # Skill registry
gmx-trading/
SKILL.md # Trading skill definition
references/
sdk-reference.md # SDK API reference (shared)
api-endpoints.md # REST and GraphQL endpoints (shared)
contract-addresses.md # Deployed contracts per chain (shared)
order-types.md # Order type specifications
gmx-liquidity/
SKILL.md # Liquidity skill definition
references/
liquidity-operations.md # Contract structs, flows, gas formulas
plugins/gmx-io/ # Claude Code plugin
.claude-plugin/
plugin.json # Plugin manifest
skills/
gmx-trading/ # Trading skill files (mirrored)
gmx-liquidity/ # Liquidity skill files (mirrored)
\`\`\`
## Links
- \*\*Repository:\*\* \[github.com/gmx-io/gmx-ai\](https://github.com/gmx-io/gmx-ai)
- \*\*SDK package:\*\* \[\`@gmx-io/sdk\` on npm\](https://www.npmjs.com/package/@gmx-io/sdk)
- \*\*SDK documentation:\*\* \[SDK overview\](../sdk/overview.md)
- \*\*API documentation:\*\* \[API overview\](../api/overview.md)
- \*\*GMX app:\*\* \[app.gmx.io\](https://app.gmx.io)
---
## Frontend Integration
The GMX protocol consists of smart contracts deployed on blockchains.
Users can interact directly with the smart contracts using blockchain explorers such as \[Arbiscan\](https://arbiscan.io/) and \[SnowTrace\](https://snowtrace.io/).
The \[GMX frontend repository\](https://github.com/gmx-io/gmx-interface) provides code to simplify contract interaction and to view protocol information and can be deployed by any community member.
A deployed instance of the GMX frontend is available at \[https://app.gmx.io/\](https://app.gmx.io/).
A backup instance of the GMX frontend is available at \[https://gmxalt.io/\](https://gmxalt.io/).
## Testnet frontend
A testnet GMX frontend is available at \[https://test.gmx-interface.pages.dev/\](https://test.gmx-interface.pages.dev/). Use it to test against testnet networks (Arbitrum Sepolia and Avalanche Fuji) and to access debug mode tooling.
## Running a frontend
To run the GMX frontend locally, follow the instructions in the \[GMX frontend repository\](https://github.com/gmx-io/gmx-interface). You can also deploy it using a static hosting service such as Vercel, Netlify, or Cloudflare Pages.
GMX orders support a \[UI fee\](./contracts/fees.md#ui-fee): you pass in a receiving address, and it receives fees when the order executes. These fees are charged on top of the base fees.
The GMX interface lets you configure a UI fee receiver and custom RPC URLs by adding environment variables to the \`.env\` file in the project root.
### UI fee receiver
To configure the UI fee receiver, add \`VITE\_APP\_UI\_FEE\_RECEIVER\` to your \`.env\` file. Set it to the wallet address that receives \[UI fees\](./contracts/fees.md#ui-fee).
\`\`\`bash
VITE\_APP\_UI\_FEE\_RECEIVER=0xYourReceiverAddressHere
\`\`\`
The interface only sets \`uiFeeReceiver\` for orders. To set it for deposits and withdrawals, you must add custom code.
### Custom RPC URLs
To override the default RPC endpoints for Arbitrum, Avalanche, or Botanix, add the corresponding variable to your \`.env\` file. Each variable takes a JSON array of RPC URLs, which the interface uses as fallback endpoints.
\`\`\`bash
VITE\_APP\_ARBITRUM\_RPC\_URLS=\["https://arb-rpc-url-1", "https://arb-rpc-url-2"\]
VITE\_APP\_AVALANCHE\_RPC\_URLS=\["https://avax-rpc-url-1", "https://avax-rpc-url-2"\]
VITE\_APP\_BOTANIX\_RPC\_URLS=\["https://botanix-rpc-url-1", "https://botanix-rpc-url-2"\]
\`\`\`
---
## Integration guide
Use this page when you want exact integration steps. The hand-written API pages explain which surfaces exist and how they behave operationally. The API v2 OpenAPI reference is generated and is best used for endpoint schemas and response fields, not for workflow guidance. Use \[Troubleshooting\](./troubleshooting.md) when reads do not match expected state.
## Choose the right integration surface
Start by choosing the narrowest surface that solves your problem.
| Need | Recommended surface | Notes |
| ---- | ------------------- | ----- |
| Live oracle prices, market snapshots, liquidity, and APY | \[API v1 REST pages\](/docs/category/api-v1-rest-api) | Stable public HTTP endpoints on \`gmxinfra.io\` |
| Read markets, tickers, tokens, pairs, rates, APY, performance, positions, orders, OHLCV, buyback stats, or staking power over HTTP from TypeScript | \[SDK v2\](../sdk/v2/readme.md) or the generated API v2 reference | Read-only and expanding |
| Historical trade and order activity | \[GraphQL\](./graphql.mdx) | Indexed data, not write-path state |
| Submit, cancel, or simulate orders | \[SDK v1\](../sdk/v1/readme.mdx) or direct contract calls | Use the SDK or contracts, not the public read-only API guides |
| GM or GLV token prices for use in external protocols | \[Chainlink Data Feeds\](https://data.chain.link/) | Search for GM or GLV feeds on data.chain.link |
## What is available now
The current hand-written docs and checked-out code support the following split:
| Surface | Read | Write | Description |
| ------- | ---- | ----- | ----------- |
| \[API v1 REST\](/docs/category/api-v1-rest-api) (\`gmxinfra.io\`) | ✅ | ❌ | Public market, price, liquidity, APY, and performance reads. Manual docs cover the stable public HTTP endpoints. |
| \[API v2 HTTP reference\](/docs/category/api-v2-openapi-reference) | ✅ | ❌ | Generated schema reference for current API v2 reads. Covers markets, tokens, positions, orders, rates, APY, and performance. The checked-in generated reference does not yet list the staking or buyback endpoints used by SDK v2. API v2 is in active development and is expected to become the primary API in the coming weeks, expanding to support read and write operations for virtually any action. |
| \[GraphQL\](./graphql.mdx) | ✅ | ❌ | Historical indexed activity. Best for history, not write-path confirmation. |
| \[SDK v1\](../sdk/v1/readme.mdx) (\`GmxSdk\`) | ✅ | ✅ | Full TypeScript integration with reads and writes. Uses RPC, oracle, and Subsquid connections directly. |
| \[SDK v2\](../sdk/v2/readme.md) (\`GmxApiSdk\`) | ✅ | ❌ | Read-only TypeScript integration over HTTP. SDK v2 is in active development alongside API v2 and is expected to become the primary SDK in the coming weeks, expanding to support read and write operations for virtually any action. |
| \[Direct contracts\](./contracts/overview.md) | ✅ | ✅ | Lowest-level integration and custom transaction flows. Highest control and highest implementation burden. |
The generated API v2 reference does not currently list every endpoint surfaced by SDK v2. Use the \[SDK v2 docs\](../sdk/v2/readme.md) for the typed client surface, including \`fetchBuybackWeeklyStats()\` and \`fetchStakingPower()\`.
## Build a live market overview
Use API v1 when you need public market snapshots and fallback URLs. Use \`/markets\` for a slower-changing market list, and \`/markets/info\` for a near-live market state snapshot.
\`\`\`typescript
const endpoints = \[\
"https://arbitrum-api.gmxinfra.io/markets/info",\
"https://arbitrum-api-fallback.gmxinfra.io/markets/info",\
"https://arbitrum-api-fallback.gmxinfra2.io/markets/info",\
\];
async function fetchMarketsInfo() {
let lastError: Error | undefined;
for (const endpoint of endpoints) {
try {
const response = await fetch(endpoint, {
headers: { Accept: "application/json" },
});
if (!response.ok) {
throw new Error(\`HTTP ${response.status}\`);
}
return await response.json();
} catch (error) {
lastError = error as Error;
}
}
throw lastError ?? new Error("All market endpoints failed");
}
const markets = await fetchMarketsInfo();
console.log("Loaded markets:", markets.length);
\`\`\`
Use this refresh strategy:
1. Call \`/markets\` when you need the market catalog and can tolerate a \`60\` second cache window.
2. Call \`/markets/info\` when you need liquidity, open interest, funding, borrowing, token amounts, and \`isDisabled\`. This is also the correct endpoint for \*\*near-live funding rates\*\*.
3. Treat \`/markets/info\` as a snapshot, not a guarantee of the latest block. The current implementation caches the route for \`1\` second and refreshes market values on a \`5000\` ms pull interval, so build for near-live rather than same-block state.
4. Use \`/rates\` for \*\*historical\*\* funding and borrowing rate data. This endpoint returns hourly snapshots from the Squid indexer, not realtime values. Use it for rate averages, trends, and historical analysis.
## Read positions and related orders for one account
Use SDK v2 if you are already in TypeScript and want bigint-aware responses. Use the generated API v2 reference if you need raw HTTP schemas.
Install \`@gmx-io/sdk\`, then import \`GmxApiSdk\` from \`@gmx-io/sdk/v2\`. The \`v2\` path is a subpath export, not a separate package.
\`\`\`typescript
const apiSdk = new GmxApiSdk({ chainId: 42161 });
const positions = await apiSdk.fetchPositionsInfo({
address: "0x9f7198eb1b9Ccc0Eb7A07eD228d8FbC12963ea33",
includeRelatedOrders: true,
});
const orders = await apiSdk.fetchOrders({
address: "0x9f7198eb1b9Ccc0Eb7A07eD228d8FbC12963ea33",
});
console.log({
positions,
orders,
});
\`\`\`
Use this flow when you render account state:
1. Fetch positions with \`includeRelatedOrders: true\` if your page shows open positions and their linked orders together.
2. Fetch standalone orders only if you also need an account-wide orders view.
3. After submitting a write through SDK v1 or direct contracts, poll these read endpoints until the expected state appears instead of assuming immediate consistency.
## Read historical trade activity
Use GraphQL for historical, indexed activity. Do not try to reconstruct history from live REST snapshots.
\`\`\`graphql
query RecentTrades($account: String!) {
tradeActions(where: { account\_eq: $account }, limit: 50, orderBy: timestamp\_DESC) {
eventName
account
timestamp
transactionHash
sizeDeltaUsd
collateralDeltaAmount
}
}
\`\`\`
The current GraphQL schema exposes \`transactionHash\` and top-level \`timestamp\`. See \[GraphQL\](./graphql.mdx) for schema usage notes and migration context.
For referral analytics, the GraphQL schema also exposes the \`affiliateStats\` and \`traderReferralStats\` resolvers, plus per-hour stats entities (\`AffiliateReferralTradeStatsByHour\`, \`TraderReferralTradeStatsByHour\`, \`AffiliateTraderStatsByHour\`). Use these instead of stitching \`tradeActions\` for affiliate dashboards or trader rebate views — both resolvers accept \`from\`/\`to\` time windows and return pre-aggregated volume, rebate, discount, and trader-flow figures. See \[GraphQL — Referral analytics\](./graphql.mdx#2026-03-31--referral-analytics-added) for the full schema and example queries.
## Operational notes
### Freshness and caching
- \`GET /markets\` uses a \`60\` second HTTP cache in the current implementation.
- \`GET /markets/info\` uses a \`1\` second HTTP cache in the current implementation.
- The backend currently caches \`prices\`, \`tokensData\`, and \`marketsInfo\` for \`1\` second, \`userReferralInfo\` for \`5\` seconds, and \`onchainSettings\` for \`60\` seconds.
- Avoid joining data from unrelated polls when you need one coherent snapshot. Prefer composite endpoints such as \`/markets/info\` or \`fetchPositionsInfo({ includeRelatedOrders: true })\`.
### Retries, timeouts, and fallback URLs
- The current API server timeout is \`60000\` ms.
- SDK v2 uses a simple HTTP client and does not add retry or fallback logic for you.
- Use the \[Fallback URLs\](./rest-api/fallback-urls.mdx) page for API v1 market and oracle reads.
- If you receive a timeout, network error, \`429\`, or \`5xx\`, retry with backoff and fail over where you have fallback endpoints.
### Surface-specific operational model
- API v1 REST uses endpoint-specific cache windows, and fallback URLs are documented for some public reads.
- API v2 reference documents read-only HTTP endpoints, but the generated reference does not define your retry policy.
- GraphQL is indexed data. Expect lag relative to live chain state.
- SDK v1 mixes live RPC, oracle, and indexed reads. Default SDK-created HTTP transports disable retries.
- SDK v2 is a read-only HTTP client and does not add fallback or retry logic for you.
- Direct contracts give you the most control, but your app owns retry, nonce, gas, and receipt strategy.
### Idempotency and race conditions
- These public API docs cover read paths. They do not provide idempotency keys for writes.
- After a write, do not assume your first follow-up read will reflect final state. Submission, indexing, and keeper execution can land at different times.
- If you need "position plus linked orders" on one screen, prefer a single positions call with \`includeRelatedOrders: true\` over stitching data from independent polls.
## Next steps
- Use \[API Overview\](./overview.md) to decide between REST, GraphQL, contracts, and the SDK.
- Use \[API v1 REST API\](/docs/category/api-v1-rest-api) for public market, price, and liquidity endpoints.
- Use the generated \[API v2 OpenAPI Reference\](/docs/category/api-v2-openapi-reference) for endpoint-level request and response schemas.
- Use \[Troubleshooting\](./troubleshooting.md) if your reads look stale, a query fails validation, or a write does not show up yet.
- Use \[SDK v1\](../sdk/v1/readme.mdx) when your application needs write flows such as creating or canceling orders.
---
## API Overview
GMX exposes several integration points for developers, integrators, and AI agents building on the protocol. Start with the integration surface that matches your task instead of trying to use one API for everything.
For AI agent frameworks with pre-built trading skills, see \[AI Agents\](../ai-agents/overview.md).
## Available APIs
GMX offers four integration points depending on the type of data or action you need.
### REST APIs
GMX provides two REST API generations. API v2 is under active development and will become the primary HTTP integration point.
| | API v1 — \[REST API\](/docs/category/api-v1-rest-api) | API v2 — \[OpenAPI Reference\](/docs/category/api-v2-openapi-reference) |
| ------------- | --------------------------------------------------- | --------------------------------------------------------------------- |
| \*\*Base URLs\*\* | \`gmxinfra.io\` | \`gmx-api-\*.ondigitalocean.app\` |
| \*\*Data\*\* | Oracle prices, markets, liquidity | Markets, tickers, tokens, positions, orders, rates, APY, and performance |
| \*\*Status\*\* | Stable | Expanding — will become the primary HTTP API |
### Other integration points
- \*\*\[Contracts\](/docs/category/contracts)\*\* — Interact directly with ExchangeRouter, Reader, and GlvReader contracts on-chain.
- \*\*\[GraphQL\](./graphql.mdx)\*\* — Historical on-chain data via Subsquid endpoints.
## Start here
- \*\*\[Integration guide\](./integration-guide.md)\*\* — "I want to do X" workflows, cache and retry guidance, and when to use REST, GraphQL, or the SDK
- \*\*\[Troubleshooting\](./troubleshooting.md)\*\* — What to do when reads look stale, validation fails, or write-path state does not appear yet
- \*\*\[API v1 (REST API)\](/docs/category/api-v1-rest-api)\*\* — Manual docs for prices, markets, liquidity, and fallback URLs
- \*\*\[API v2 (OpenAPI Reference)\](/docs/category/api-v2-openapi-reference)\*\* — Generated endpoint schemas for the current API v2 read surface
## TypeScript SDK
The \[\`@gmx-io/sdk\`\](../sdk/overview.md) package provides a high-level TypeScript interface that wraps these APIs. It ships two clients: \*\*SDK v1\*\* (\`GmxSdk\`) for full read/write access via RPC, and \*\*SDK v2\*\* (\`GmxApiSdk\`) for lightweight read-only access over HTTP. The current SDK v2 surface covers markets, tickers, tokens, pairs, rates, APY, performance, positions, orders, OHLCV, buyback stats, and staking power. See the \[SDK docs\](../sdk/overview.md) for details.
The generated API v2 reference covers the current checked-in HTTP endpoints. The SDK pages document additional client coverage such as \`fetchBuybackWeeklyStats()\` and \`fetchStakingPower()\` that is available in code but not yet listed in the generated reference.
## Supported networks
GMX V2 is deployed on the following networks.
- Arbitrum One
- Avalanche C-Chain
- Botanix
- MegaETH
Not every API surface is available on every deployed network. Check the specific REST, GraphQL, SDK, or generated API v2 page you plan to use before wiring a production integration.
For contract and API update announcements, see \[Updates and Support\](./updates-support.md).
## AI agent integration
GMX's oracle-based pricing and two-phase execution model make it well-suited for autonomous trading agents. For pre-built agent plugins that bundle SDK references, API endpoints, contract addresses, and order specifications, see the \[AI Agents\](../ai-agents/overview.md) section. This documentation site also generates LLM-friendly bundles at \[\`llms.txt\`\](https://docs.gmx.io/llms.txt) and \[\`llms-full.txt\`\](https://docs.gmx.io/llms-full.txt) for direct model consumption.
---
## Troubleshooting
Use this page when API reads do not match what you expect. Most issues fall into one of four buckets: invalid request parameters, stale snapshots, using the wrong surface for the job, or expecting immediate read-after-write consistency.
## \`400 Bad Request\`
The current read endpoints validate several inputs and return \`400\` for bad parameters.
Common cases:
- \`/orders\` and \`/positions\` require a valid account address.
- \`/markets/tickers\` validates \`addresses\` and \`symbols\` filters.
- \`/rates\` validates \`period\` and \`averageBy\`.
- \`/apy\` and \`/performance/\*\` validate \`period\`.
If you receive a \`400\`, validate the exact query string before retrying. Retrying the same invalid input will not succeed.
## A value looks stale
Start by checking whether you are reading from a cached or indexed surface.
- Use \`/markets/info\` when you need near-live market state.
- Use \`/markets\` when a \`60\` second cache window is acceptable.
- Use GraphQL for historical activity, not for the latest write-path state.
- Use a single composite read where possible instead of stitching unrelated polls together.
If you need one coherent account snapshot, prefer one positions call with \`includeRelatedOrders: true\` over multiple loosely coordinated reads.
## A write succeeded on-chain, but the API still does not show it
That is usually a surface mismatch, not a broken API call.
- Public API guides in this section describe read surfaces.
- Writes belong to \[SDK v1\](../sdk/v1/readme.mdx) or direct contracts.
- After a write, wait for the transaction receipt first, then poll the read surface you care about until the state appears.
Do not assume the first follow-up HTTP or GraphQL read will reflect final state. Submission, keeper execution, and indexing can complete at different times.
## Positions and orders do not line up
If your UI shows position state together with linked orders, fetch them from the same logical snapshot.
Recommended pattern:
\`\`\`typescript
const apiSdk = new GmxApiSdk({ chainId: 42161 });
const positions = await apiSdk.fetchPositionsInfo({
address: "0x9f7198eb1b9Ccc0Eb7A07eD228d8FbC12963ea33",
includeRelatedOrders: true,
});
\`\`\`
Use a separate account-wide orders read only when you need a dedicated orders screen.
## There is no documented public SLA
The current manual docs do not publish a public SLA for these surfaces. Build your client as if network errors, timeouts, or stale snapshots can happen.
Recommended client behavior:
1. Use endpoint-specific fallback URLs where they are documented.
2. Add retries with backoff for safe read operations.
3. Keep write confirmation logic separate from read polling logic.
4. Log the exact surface you queried so you can distinguish API v1 REST, API v2, GraphQL, and SDK-backed reads during incident review.
## Next steps
- Use the \[Integration guide\](./integration-guide.md) for workflow selection.
- Use \[Fallback URLs\](./rest-api/fallback-urls.mdx) for API v1 public read failover.
---
## Updates and Support
For contract and API updates, subscribe to the \[@GMX\_Technical\_Announcements\](https://t.me/GMX\_Technical\_Announcements) Telegram channel.
Important changes will likely be posted there, but that channel may not cover all updates. Other channels worth monitoring:
- \[GMX Substack\](https://gmxio.substack.com/)
- \[GMX Repositories\](https://github.com/gmx-io)
- \[@GMX\_Announcements\](https://t.me/GMX\_Announcements)
For API or SDK support, join the \[GMX Discord\](https://discord.com/invite/H5PeQru3Aa) to create a support ticket.
---
## @gmx-io/gmx-public-api
GMX Public API overview with Swagger/OpenAPI links and base URLs.
## GMX Public API (Swagger)
- Swagger/OpenAPI spec: \[GMX Public API Swagger\](https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/swagger.json)
- Human-readable API docs: \[GMX Public API Docs\](/docs/api/gmx-api/gmx-io-gmx-public-api/)
## Base URLs
| Network | URL |
|---------|-----|
| Arbitrum | \`https://gmx-api-arbitrum-2nlbk.ondigitalocean.app/api/v1\` |
| Avalanche | \`https://gmx-api-avalanche-vxjas.ondigitalocean.app/api/v1\` |
---
## Changelog
## 1.5.0-alpha-8 — March 11, 2026
This release expands the \`GmxApiSdk\` read surface to cover more GMX HTTP endpoints and exports the matching typed response helpers.
- Added \`fetchMarkets()\`, \`fetchMarketsTickers(params)\`, \`fetchTokens()\`, \`fetchPairs()\`, \`fetchRates(params)\`, \`fetchApy(params)\`, \`fetchPerformanceAnnualized(params)\`, and \`fetchPerformanceSnapshots(params)\` to \`GmxApiSdk\` in \`@gmx-io/sdk/v2\`.
- Added the matching \`@gmx-io/sdk/v2\` type exports for APY, market tickers, pairs, rates, and performance responses.
## 1.5.0-alpha-7 — March 9, 2026
This release improves TypeScript type resolution for projects that consume the SDK in CommonJS mode.
- Added \`typesVersions\` mappings to \`@gmx-io/sdk\` so TypeScript resolves subpath types correctly when \`moduleResolution\` is set to \`"node"\` or \`"node10"\` in \`tsconfig.json\`. Projects using \`"bundler"\` or \`"node16"\` module resolution already resolve types through the \`exports\` field and are unaffected.
- Covers the root client entrypoints (\`@gmx-io/sdk\`, \`@gmx-io/sdk/v1\`, \`@gmx-io/sdk/v2\`) as well as config, ABI, utility, prebuilt, and type-only subpaths.
- No runtime SDK API methods changed in this release. The update is packaging and type-resolution focused.
## 1.5.0-alpha-6 — March 9, 2026
This release adds OHLCV reads to \`GmxApiSdk\` and renames address-filtered API SDK params to match the underlying REST API.
- Added \`fetchOhlcv(params)\` to \`GmxApiSdk\` in \`@gmx-io/sdk/v2\`. This method wraps \`fetchApiOhlcv\` and returns \`OhlcvCandle\[\]\` from \`/prices/ohlcv\`.
- Renamed \`fetchPositionsInfo(params)\` and \`fetchOrders(params)\` params from \`account\` to \`address\`. The underlying \`fetchApiPositionsInfo\` and \`fetchApiOrders\` helpers now use \`address\` as well.
- Added \`OhlcvCandle\` and \`OhlcvParams\` exports in \`@gmx-io/sdk/v2\`, plus the \`@gmx-io/sdk/types/prices\` subpath export for price candle types.
## 1.5.0-alpha-5 — February 28, 2026
This release fixes a potential negative pool amount edge case in position price impact calculations.
- \`getPriceImpactForPosition\` in \`@gmx-io/sdk/utils/fees\` now accepts an optional \`fallbackToZero\` option. When enabled, negative pool amounts are clamped to zero instead of producing invalid results.
- \`getContractPositionDynamicFees\` in \`@gmx-io/sdk/utils/positions\` uses \`fallbackToZero: true\` when calling \`getPriceImpactForPosition\` internally, preventing errors from negative pool states.
## 1.5.0-alpha-4 — February 13, 2026
This release adds five new synthetic markets on Arbitrum and expands the \`GmxApiSdk\` class with positions and orders support.
- Added \`fetchPositionsInfo(params)\` and \`fetchOrders(params)\` methods to \`GmxApiSdk\` in \`@gmx-io/sdk/v2\`. These methods wrap \`fetchApiPositionsInfo\` and \`fetchApiOrders\` respectively.
- Added five new Arbitrum markets: XAUT/USD \[WBTC-USDC\], LIT/USD \[WETH-USDC\], IP/USD \[WBTC-USDC\], CC/USD \[WBTC-USDC\], and MET/USD \[WBTC-USDC\]. All five index tokens are synthetic.
- Added corresponding token configurations for XAUT, LIT (Lighter), IP (Story), CC (Canton), and MET (Meteora) on Arbitrum.
## 1.5.0-alpha-3 — February 13, 2026
This release introduces the \`GmxApiSdk\` client and adds REST API support for positions, orders, and fee utilities.
- Added \`GmxApiSdk\` class exported from \`@gmx-io/sdk/v2\`. Instantiate it with a \`chainId\` to call GMX REST API endpoints directly. Provides \`fetchMarketsInfo()\` and \`fetchTokensData()\` methods. Supported on Arbitrum, Avalanche, and Arbitrum Sepolia; throws at construction time for unsupported chains.
- Added \`getPositionInfo\` utility to \`@gmx-io/sdk/utils/positions\`. Computes a comprehensive position summary (entry price, PnL, leverage, liquidation price, net value, fees) from a raw position and market data.
- Added \`getContractPositionDynamicFees\` to \`@gmx-io/sdk/utils/positions\`. Calculates dynamic fees (borrowing, funding, closing) for a position given the current market fee state.
- Added \`fetchApiPositionsInfo\` to \`@gmx-io/sdk/utils/positions\`. Fetches position data from the GMX REST API instead of on-chain multicalls (available on Arbitrum, Avalanche, and Arbitrum Sepolia).
- Added \`fetchApiOrders\` to \`@gmx-io/sdk/utils/orders\`. Fetches order data from the GMX REST API.
- Added \`isApiSupported(chainId)\` to \`@gmx-io/sdk/configs/api\`. Returns \`true\` for chains that have a GMX REST API endpoint (Arbitrum, Avalanche, and Arbitrum Sepolia).
- Added \`FLOAT\_PRECISION\_SQRT\_DECIMALS\` (15) and \`FLOAT\_PRECISION\_SQRT\` (\`10n \*\* 15n\`) constants to \`@gmx-io/sdk/utils/numbers\`.
## 1.5.0-alpha-2 — February 11, 2026
This release adds fee utilities and Solidity error decoding helpers.
- Added \`getMaxNegativeImpactBps\` to \`@gmx-io/sdk/utils/fees\`. Converts a market's \`maxPositionImpactFactorNegative\` to basis points.
- Added \`tryDecodeCustomError\`, \`decodeErrorFromViemError\`, and \`extractErrorDataFromViemError\` to \`@gmx-io/sdk/utils/errors\`. These functions decode custom Solidity errors from viem error objects using the GMX \`CustomErrors\` ABI.
## 1.3.1 — September 15, 2025
This release fixes order payload forwarding.
- Fixed \`dataList\` not being forwarded to the on-chain order payload in \`createIncreaseOrder\`, \`createDecreaseOrder\`, and \`createSwapOrder\`. The \`dataList\` parameter (optional \`string\[\]\`) now defaults to \`\[\]\` when omitted.
## 1.3.0 — September 15, 2025
This release adds GMX v2.2 contract support and position impact fields.
- Added support for GMX v2.2 contracts. Updated \`SyntheticsReader\` and \`ClaimHandler\` ABIs; added \`SmartAccount\` ABI.
- Added \`pendingImpactUsd\` and \`closePriceImpactDeltaUsd\` fields to \`PositionInfo\`.
- Added \`nextPendingImpactDeltaUsd\` and \`potentialPriceImpactDiffUsd\` fields to \`NextPositionValues\`.
- Fixed position impact capping logic in \`getNextPositionValuesForIncreaseTrade\` to use \`nextSizeUsd\` instead of \`sizeDeltaUsd\`.
## 1.2.1 — August 25, 2025
This release fixes Botanix client initialization.
- Fixed Botanix viem client initialization. Added Botanix to \`BATCH\_CONFIGS\` (it was missing, which caused the default \`PublicClient\` to fail on Botanix). Changed batch config access to use optional chaining (\`?.\`) so an unsupported chain ID doesn't throw at client construction time.
## 1.2.0 — July 17, 2025
This release adds three new markets across Arbitrum and Avalanche.
- Added market and token configurations for three new markets: PUMP/USD \[WBTC-USDC\] and ARB/USD \[ARB-ARB\] on Arbitrum, and PUMP/USD \[WAVAX-USDC\] on Avalanche. PUMP is a synthetic token.
## 1.1.0 — June 3, 2025
This release adds four new synthetic markets on Arbitrum.
- Added market and token configurations for four new markets on Arbitrum: CRV/USD \[WETH-USDC\], XMR/USD \[WBTC-USDC\], MOODENG/USD \[WBTC-USDC\], and PI/USD \[WBTC-USDC\]. All four index tokens are synthetic.
## 1.0.5 — May 26, 2025
This release fixes \`uiFeeReceiver\` propagation in order creation.
- Fixed \`uiFeeReceiver\` not being read from \`sdk.config.settings.uiFeeReceiverAccount\` in \`createIncreaseOrder\`, \`createDecreaseOrder\`, and \`createSwapOrder\`. Previously all three functions passed \`zeroAddress\` unconditionally.
## 1.0.3 — May 23, 2025
This release adds the \`isTrigger\` parameter and fixes order type forwarding in \`createDecreaseOrder\`.
- Added \`isTrigger\` parameter to \`orders.createDecreaseOrder\`. When \`true\`, the order type is taken from \`decreaseAmounts.triggerOrderType\`; when \`false\` or omitted, the order type defaults to \`Market Decrease\`.
- Fixed \`orderType\` not being forwarded correctly in \`orders.createDecreaseOrder\`.
## 1.0.0 — April 30, 2025
This is the initial stable release. It removes the deprecated \`subgraphUrl\` config key and adds dual ESM/CJS module support.
- Removed \`subgraphUrl\` from \`GmxSdkConfig\`. Use \`subsquidUrl\` instead.
- Added support for both ESM and CJS module formats. The package ships two builds: \`build/esm/\` and \`build/cjs/\`.
- Changed the default module format from ESM to CJS. The \`main\` entry point resolves to \`build/cjs/src/index.js\`.
---
## SDK Overview
The GMX SDK (\`@gmx-io/sdk\`) is a TypeScript library for integrating GMX perpetuals and spot trading into your application. It wraps the GMX smart contracts and data APIs into a typed interface, letting you read market data, compute fees, and submit orders without managing low-level contract calls directly.
The SDK runs in Node.js (>=18) and browser environments.
## SDK v1 and v2
The SDK ships two clients. Choose based on your integration needs:
Install both clients from the same package: \`npm install @gmx-io/sdk\`. The SDK v2 import path is \`@gmx-io/sdk/v2\`, but \`@gmx-io/sdk/v2\` is not a separate npm package.
| | SDK v1 — \`GmxSdk\` | SDK v2 — \`GmxApiSdk\` |
| ---------------- | -------------------------------------- | ---------------------------------------------- |
| \*\*Import\*\* | \`import { GmxSdk } from "@gmx-io/sdk"\` | \`import { GmxApiSdk } from "@gmx-io/sdk/v2"\` |
| \*\*Requires\*\* | RPC + Oracle URL + Subsquid URL | Chain ID only |
| \*\*Capabilities\*\* | Full (read + write) | Read-only HTTP client (markets, tickers, tokens, pairs, rates, APY, performance, positions, orders, OHLCV, buyback, staking) |
| \*\*Status\*\* | Current full client | Expanding to cover the full SDK surface |
:::note
SDK v2 (\`GmxApiSdk\`) is under active development and will expand over time, replacing the need for direct RPC, oracle, and Subsquid connections. It wraps the \[API v2 (OpenAPI Reference)\](/docs/category/api-v2-openapi-reference).
:::
- \*\*\[SDK v1 — Getting Started\](./v1/readme.mdx)\*\* — Full client for read and write operations
- \*\*\[SDK v1 — Integration guide\](./v1/integration-guide.md)\*\* — End-to-end workflows and operational guidance
- \*\*\[SDK v1 — Troubleshooting\](./v1/troubleshooting.md)\*\* — Receipt handling, duplicate-submit protection, stale reads, and simulation caveats
- \*\*\[SDK v2 — Getting Started\](./v2/readme.md)\*\* — Read-only API client for TypeScript integrations
If you are starting a new integration, read the workflow page before the reference pages. Use SDK v1 when you need writes or direct RPC-backed reads. Use SDK v2 when you only need read-only HTTP access.
## Operational differences
| Topic | SDK v1 — \`GmxSdk\` | SDK v2 — \`GmxApiSdk\` |
|---|---|---|
| Data sources | RPC, oracle, and Subsquid | GMX HTTP API |
| Trade history | ✅ | ❌ |
| Order submission and cancellation | ✅ | ❌ |
| Built-in HTTP retries | ❌ Default viem transports use \`retryCount: 0\` | ❌ Current HTTP client does not add retry or fallback logic |
| Built-in transaction receipt waiting | ❌ | Not applicable |
| Idempotency keys | ❌ | Not applicable |
## Available now
- SDK v1 is the current full client.
- SDK v2 exposes \`fetchMarketsInfo\`, \`fetchMarkets\`, \`fetchMarketsTickers\`, \`fetchTokensData\`, \`fetchTokens\`, \`fetchPairs\`, \`fetchRates\`, \`fetchApy\`, \`fetchPerformanceAnnualized\`, \`fetchPerformanceSnapshots\`, \`fetchPositionsInfo\`, \`fetchOrders\`, \`fetchOhlcv\`, \`fetchBuybackWeeklyStats\`, and \`fetchStakingPower\`.
- Use SDK v1 if your integration needs writes or trade history today.
## Supported networks
The SDK supports the following production networks:
| Network | Chain ID |
| --------- | -------- |
| Arbitrum | 42161 |
| Avalanche | 43114 |
| Botanix | 3637 |
| MegaETH | 4326 |
\*\*Repository:\*\* \[github.com/gmx-io/gmx-interface/sdk\](https://github.com/gmx-io/gmx-interface/tree/master/sdk)
## Installation
Install the SDK using your preferred package manager:
\`\`\`bash
# npm
npm install @gmx-io/sdk
# yarn
yarn add @gmx-io/sdk
\`\`\`
Both SDK clients ship in this package. Import \`GmxSdk\` from \`@gmx-io/sdk\` and \`GmxApiSdk\` from \`@gmx-io/sdk/v2\`.
The package supports both ESM and CommonJS. CommonJS consumers can use \`require("@gmx-io/sdk")\` for v1 and \`require("@gmx-io/sdk/v2")\` for v2. TypeScript subpath resolution is supported for the SDK's root, client, utility, config, ABI, and type-only entrypoints.
:::note
The current release is \`1.5.0-alpha-8\`. The API may change before a stable release.
:::
The SDK requires Node.js 18 or later.
---
## Examples
Use this page for focused runnable snippets. If you want end-to-end trading flows or operational guidance, start with the \[Integration guide\](./integration-guide.md).
## Get funding fees
This example shows how to fetch hourly funding fee rates for all markets using the GMX SDK. Funding fees are paid between long and short positions to keep open interest balanced — positive values mean a position receives funding, and negative values mean it pays.
### Prerequisites
Initialize the SDK before running this example:
\`\`\`typescript
const sdk = new GmxSdk({
chainId: 42161, // Arbitrum
rpcUrl: "https://arb1.arbitrum.io/rpc",
oracleUrl: "https://arbitrum-api.gmxinfra.io",
subsquidUrl: "https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql",
});
\`\`\`
### Fetch and format funding rates
Call \`sdk.markets.getMarketsInfo()\` to retrieve live market data, then compute the per-period funding factor for each market:
\`\`\`typescript
const { marketsInfoData } = await sdk.markets.getMarketsInfo();
const fundingRates = Object.values(marketsInfoData ?? {}).map((market) => {
// 3600n = 1 hour in seconds (BigInt required)
const longHourly = getFundingFactorPerPeriod(market, true, 3600n);
const shortHourly = getFundingFactorPerPeriod(market, false, 3600n);
return {
market: getMarketFullName(market),
long: formatRatePercentage(longHourly, { displayDecimals: 2 }),
short: formatRatePercentage(shortHourly, { displayDecimals: 2 }),
};
});
console.table(fundingRates);
// Example output:
// \[\
// { market: "BTC/USD \[WBTC-USDC\]", long: "-0.01%", short: "+0.01%" },\
// { market: "ETH/USD \[WETH-USDC\]", long: "+0.00%", short: "-0.00%" },\
// \]
\`\`\`
\`getFundingFactorPerPeriod\` returns a \`bigint\` representing the funding factor scaled to 30 decimal places. A negative value for a position side means that side pays funding for the period. \`formatRatePercentage\` converts the raw factor to a human-readable percentage string.
:::note
The \`periodInSeconds\` argument must be a \`bigint\` (for example, \`3600n\` for hourly rates). Passing a plain number will cause a TypeScript type error.
:::
### What the result tells you
| Field | Type | Description |
| -------- | -------- | ----------------------------------------------------------- |
| \`market\` | \`string\` | Market name in \`INDEX/USD \[LONG-SHORT\]\` format |
| \`long\` | \`string\` | Hourly funding rate for long positions (negative = paying) |
| \`short\` | \`string\` | Hourly funding rate for short positions (negative = paying) |
The sign convention is: negative means the position is paying funding to the counterpart side; positive means it is receiving funding.
### Related
- \[\`getFundingFactorPerPeriod\`\](./exports/utils/fees/fees.md) — function reference and parameter details
- \[\`formatRatePercentage\`\](./exports/utils/numbers.md) — number formatting utilities
- \[\`getMarketFullName\`\](./exports/utils/markets.md) — market name formatting
---
## api
This module exposes the SDK's GMX REST API endpoint lookup helpers.
## Functions
### \`getApiUrl\`
\`\`\`typescript
getApiUrl(chainId: number): string | undefined
\`\`\`
Returns the configured GMX REST API base URL for a chain, or \`undefined\` when that chain does not have API support.
\`\`\`typescript
console.log(getApiUrl(42161)); // Arbitrum API URL
console.log(getApiUrl(43114)); // Avalanche API URL
console.log(getApiUrl(421614)); // Arbitrum Sepolia API URL
console.log(getApiUrl(3637)); // undefined (no public API URL)
\`\`\`
### \`isApiSupported\`
\`\`\`typescript
isApiSupported(chainId: number): boolean
\`\`\`
Returns \`true\` when \`getApiUrl(chainId)\` resolves to a GMX API endpoint.
Current support:
- Arbitrum (\`42161\`)
- Avalanche (\`43114\`)
- Arbitrum Sepolia (\`421614\`)
Current non-support:
- Botanix (\`3637\`)
- Avalanche Fuji (\`43113\`)
\`\`\`typescript
isApiSupported(42161); // true
isApiSupported(421614); // true
isApiSupported(3637); // false
\`\`\`
---
## batch
This module exposes batching defaults used by the SDK's viem transports and paginated Subsquid helpers.
## Exports
- \`BATCH\_CONFIGS\` — per-chain viem batch settings for HTTP transport and client-side batching
- \`SUBSQUID\_PAGINATION\_LIMIT\` — default page size used by paginated indexer helpers
\`\`\`typescript
\`\`\`
Use this module when you provide custom viem clients or build your own paginated Subsquid fetch loops.
When you inject a custom viem \`publicClient\`, carry over \`BATCH\_CONFIGS\[chainId\].client\` instead of relying on viem defaults. The SDK's batch config raises the client-side multicall calldata limit to \`1024 \* 1024\` bytes; without it, large GMX multicalls may be split into many smaller RPC requests.
---
## chainIds
This module exports the raw numeric chain ID constants used across the SDK, without the richer metadata from \[\`configs/chains\`\](./chains.md).
## Exports
- Contracts chains: \`ARBITRUM\`, \`AVALANCHE\`, \`BOTANIX\`
- Development contracts chains: \`ARBITRUM\_SEPOLIA\`, \`AVALANCHE\_FUJI\`
- Source chains: \`SOURCE\_ETHEREUM\_MAINNET\`, \`SOURCE\_BASE\_MAINNET\`, \`SOURCE\_BSC\_MAINNET\`, \`SOURCE\_OPTIMISM\_SEPOLIA\`, \`SOURCE\_SEPOLIA\`
\`\`\`typescript
console.log(ARBITRUM); // 42161
console.log(BOTANIX); // 3637
console.log(SOURCE\_ETHEREUM\_MAINNET); // 1
\`\`\`
---
## chains
This module provides chain configuration constants, types, and utilities for the GMX protocol. It includes chain IDs, names, gas configurations, execution fee settings, and helper functions for working with different blockchain networks supported by GMX.
## Types
The \`chains\` module exports the following TypeScript types for working with chain identifiers and names.
### ContractsChainId
Chain IDs where GMX contracts are deployed, including testnets. Equivalent to the union of all entries in \`CONTRACTS\_CHAIN\_IDS\_DEV\` (42161, 43114, 3637, 43113, 421614).
\`\`\`typescript
// Arbitrum | Avalanche | Botanix | Avalanche Fuji | Arbitrum Sepolia
type ContractsChainId = (typeof CONTRACTS\_CHAIN\_IDS\_DEV)\[number\];
\`\`\`
### ContractsChainIdProduction
Production-only chain IDs where GMX contracts are deployed, excluding testnets. Equivalent to the union of \`CONTRACTS\_CHAIN\_IDS\` (42161, 43114, 3637).
\`\`\`typescript
// Arbitrum | Avalanche | Botanix
type ContractsChainIdProduction = (typeof CONTRACTS\_CHAIN\_IDS)\[number\];
\`\`\`
### SettlementChainId
Chain IDs used for settlement operations, including testnets. Equivalent to the union of \`SETTLEMENT\_CHAIN\_IDS\_DEV\` (42161, 43114, 421614, 43113).
\`\`\`typescript
// Arbitrum | Avalanche | Arbitrum Sepolia | Avalanche Fuji
type SettlementChainId = (typeof SETTLEMENT\_CHAIN\_IDS\_DEV)\[number\];
\`\`\`
### SourceChainId
Chain IDs from which assets can be bridged into GMX. Includes mainnet and testnet source chains as well as GMX settlement chains.
\`\`\`typescript
// SOURCE\_OPTIMISM\_SEPOLIA | SOURCE\_SEPOLIA | SOURCE\_BASE\_MAINNET | SOURCE\_BSC\_MAINNET
// | SOURCE\_ETHEREUM\_MAINNET | ARBITRUM\_SEPOLIA | ARBITRUM | AVALANCHE | AVALANCHE\_FUJI
type SourceChainId = (typeof SOURCE\_CHAIN\_IDS)\[number\];
\`\`\`
### AnyChainId
Union of all supported chain IDs across contracts, settlement, and source chains.
\`\`\`typescript
type AnyChainId = ContractsChainId | SettlementChainId | SourceChainId;
\`\`\`
### ChainName
Human-readable name for a supported chain. Returned by \`getChainName()\`. The value \`"Unknown"\` is returned for unrecognized chain IDs.
\`\`\`typescript
type ChainName =
| "Arbitrum"
| "Avalanche"
| "Avalanche Fuji"
| "Arbitrum Sepolia"
| "Optimism Sepolia"
| "Sepolia"
| "Botanix"
| "Base"
| "BNB"
| "Ethereum"
| "Unknown";
\`\`\`
## Constants
The module exports the following constants.
### Chain ID constants
Numeric chain IDs for all supported networks. Import whichever you need; you rarely need all of them.
\`\`\`typescript
ARBITRUM,
AVALANCHE,
BOTANIX,
AVALANCHE\_FUJI,
ARBITRUM\_SEPOLIA,
SOURCE\_ETHEREUM\_MAINNET,
SOURCE\_BASE\_MAINNET,
SOURCE\_BSC\_MAINNET,
SOURCE\_OPTIMISM\_SEPOLIA,
SOURCE\_SEPOLIA,
} from "@gmx-io/sdk/configs/chains";
console.log(ARBITRUM); // 42161
console.log(AVALANCHE); // 43114
console.log(BOTANIX); // 3637
console.log(AVALANCHE\_FUJI); // 43113
console.log(ARBITRUM\_SEPOLIA); // 421614
console.log(SOURCE\_ETHEREUM\_MAINNET); // 1
console.log(SOURCE\_BASE\_MAINNET); // 8453
console.log(SOURCE\_BSC\_MAINNET); // 56
console.log(SOURCE\_OPTIMISM\_SEPOLIA); // 11155420
console.log(SOURCE\_SEPOLIA); // 11155111
\`\`\`
### Chain ID arrays
Readonly tuples of chain IDs grouped by role. Use these for validation or iteration instead of hardcoding values.
- \`CONTRACTS\_CHAIN\_IDS\` — Production chains where GMX contracts are deployed: \`\[42161, 43114, 3637\]\`
- \`CONTRACTS\_CHAIN\_IDS\_DEV\` — All contracts chains including testnets: \`\[42161, 43114, 3637, 43113, 421614\]\`
- \`SETTLEMENT\_CHAIN\_IDS\` — Production settlement chains: \`\[42161, 43114\]\`
- \`SETTLEMENT\_CHAIN\_IDS\_DEV\` — Settlement chains including testnets: \`\[42161, 43114, 421614, 43113\]\`
- \`SOURCE\_CHAIN\_IDS\` — Source chains for cross-chain deposits
\`\`\`typescript
for (const chainId of CONTRACTS\_CHAIN\_IDS) {
console.log(isContractsChain(chainId)); // true
}
\`\`\`
### Other constants
- \`GMX\_ACCOUNT\_PSEUDO\_CHAIN\_ID: 0\` — Pseudo chain ID used internally for the GMX Account feature.
- \`botanix: Chain\` — Viem \`Chain\` definition for the Botanix network. Pass to \`createPublicClient\` when connecting to Botanix.
- \`VIEM\_CHAIN\_BY\_CHAIN\_ID: Record\` — Map of chain ID to viem \`Chain\` object for all supported chains.
\`\`\`typescript
// Use the pre-built Botanix chain definition
const client = createPublicClient({ chain: botanix, transport: http("https://rpc.ankr.com/botanix\_mainnet") });
// Or look up any chain by ID
const arbitrumChain = VIEM\_CHAIN\_BY\_CHAIN\_ID\[ARBITRUM\];
\`\`\`
## Methods
The module exports functions for looking up chain metadata, validating chain IDs, and reading per-chain execution fee configuration.
### Chain identification
#### getChainName
\`getChainName(chainId: number): ChainName\`
Returns the human-readable name for a chain ID. Returns \`"Unknown"\` for unrecognized IDs.
\`\`\`typescript
console.log(getChainName(ARBITRUM)); // "Arbitrum"
console.log(getChainName(BOTANIX)); // "Botanix"
console.log(getChainName(99999)); // "Unknown"
\`\`\`
#### getChainSlug
\`getChainSlug(chainId: number): ChainSlug\`
Returns the URL-friendly slug for a chain ID. Returns \`"unknown"\` for unrecognized IDs.
\`\`\`typescript
console.log(getChainSlug(ARBITRUM)); // "arbitrum"
console.log(getChainSlug(AVALANCHE)); // "avalanche"
\`\`\`
#### getChainIdBySlug
\`getChainIdBySlug(slug: string): AnyChainId | undefined\`
Returns the chain ID for a given slug, or \`undefined\` if not found.
\`\`\`typescript
console.log(getChainIdBySlug("arbitrum")); // 42161
console.log(getChainIdBySlug("unknown")); // undefined
\`\`\`
#### getViemChain
\`getViemChain(chainId: number): Chain\`
Returns the viem \`Chain\` object for a chain ID. Use this when constructing a viem \`PublicClient\` or \`WalletClient\` for a dynamically selected chain.
\`\`\`typescript
const chain = getViemChain(ARBITRUM);
const client = createPublicClient({ chain, transport: http("https://arb1.arbitrum.io/rpc") });
\`\`\`
### Chain classification
#### isContractsChain
\`isContractsChain(chainId: number, dev?: boolean): chainId is ContractsChainId\`
Returns \`true\` if the chain ID is one where GMX contracts are deployed. Pass \`dev: true\` to include testnet chains.
\`\`\`typescript
isContractsChain(ARBITRUM); // true
isContractsChain(AVALANCHE\_FUJI); // false (testnet excluded by default)
isContractsChain(AVALANCHE\_FUJI, true); // true (testnet included)
\`\`\`
#### isTestnetChain
\`isTestnetChain(chainId: number): boolean\`
Returns \`true\` if the chain ID is a testnet. Matches Avalanche Fuji, Arbitrum Sepolia, Sepolia, and Optimism Sepolia.
\`\`\`typescript
isTestnetChain(ARBITRUM); // false
isTestnetChain(ARBITRUM\_SEPOLIA); // true
\`\`\`
#### isChainDisabled
\`isChainDisabled(chainId: ContractsChainId): boolean\`
Returns \`true\` if the chain is disabled in the SDK configuration.
### Execution fee helpers
These functions read per-chain execution fee configuration. Use them to validate or display fee estimates before submitting orders.
#### getHighExecutionFee
\`getHighExecutionFee(chainId: number): number\`
Returns the "high fee" warning threshold in USD. Defaults to 5 for unknown chain IDs.
\`\`\`typescript
console.log(getHighExecutionFee(ARBITRUM)); // 5
\`\`\`
#### getExcessiveExecutionFee
\`getExcessiveExecutionFee(chainId: number): number\`
Returns the "excessive fee" threshold in USD. Defaults to 10 for unknown chain IDs.
\`\`\`typescript
console.log(getExcessiveExecutionFee(ARBITRUM)); // 10
\`\`\`
#### getExecutionFeeConfig
\`getExecutionFeeConfig(chainId: ContractsChainId): { shouldUseMaxPriorityFeePerGas: boolean; defaultBufferBps: number | undefined } | undefined\`
Returns the execution fee configuration for a chain, including whether to use \`maxPriorityFeePerGas\` and the default buffer basis points.
#### getMaxFeePerGas
\`getMaxFeePerGas(chainId: ContractsChainId): bigint | undefined\`
Returns the EIP-1559 \`maxFeePerGas\` cap for a chain, or \`undefined\` if uncapped.
#### getGasPricePremium
\`getGasPricePremium(chainId: ContractsChainId): bigint | undefined\`
Returns the gas price premium (in wei) added to execution fee calculations.
#### getMaxPriorityFeePerGas
\`getMaxPriorityFeePerGas(chainId: ContractsChainId): bigint | undefined\`
Returns the \`maxPriorityFeePerGas\` value for a chain.
#### getMinExecutionFeeUsd
\`getMinExecutionFeeUsd(chainId: ContractsChainId): bigint | undefined\`
Returns the minimum execution fee in USD equivalent (30-decimal precision). Set on chains with volatile gas pricing, such as Botanix.
#### getGasPriceBuffer
\`getGasPriceBuffer(chainId: ContractsChainId): bigint | undefined\`
Returns the gas price buffer in basis points for non-EIP-1559 transaction fee calculations.
### Chain metadata
#### getChainNativeTokenSymbol
\`getChainNativeTokenSymbol(chainId: ContractsChainId): string\`
Returns the native token symbol for a chain (for example, \`"ETH"\` for Arbitrum, \`"AVAX"\` for Avalanche, \`"BTC"\` for Botanix).
#### getChainWrappedTokenSymbol
\`getChainWrappedTokenSymbol(chainId: ContractsChainId): string\`
Returns the wrapped native token symbol (for example, \`"WETH"\`, \`"WAVAX"\`, \`"PBTC"\`).
#### getChainDefaultCollateralSymbol
\`getChainDefaultCollateralSymbol(chainId: ContractsChainId): string\`
Returns the default collateral token symbol for a chain (for example, \`"USDC.e"\` for Arbitrum, \`"USDC"\` for Avalanche).
#### getExplorerUrl
\`getExplorerUrl(chainId: number | "layerzero" | "layerzero-testnet"): string\`
Returns the block explorer base URL for a chain. Also accepts \`"layerzero"\` and \`"layerzero-testnet"\` as special values for cross-chain transaction lookup.
\`\`\`typescript
console.log(getExplorerUrl(ARBITRUM)); // "https://arbiscan.io/"
console.log(getExplorerUrl("layerzero")); // "https://layerzeroscan.com/"
\`\`\`
#### getTokenExplorerUrl
\`getTokenExplorerUrl(chainId: number, tokenAddress: string): string\`
Returns the full block explorer URL for a specific token address on a chain.
\`\`\`typescript
const url = getTokenExplorerUrl(ARBITRUM, "0xaf88d065e77c8cC2239327C5EDb3A432268e5831");
// "https://arbiscan.io/token/0xaf88d065e77c8cC2239327C5EDb3A432268e5831"
\`\`\`
---
## contracts
This module provides contract addresses for the GMX protocol across different blockchain networks. It includes addresses for V1, V2 (Synthetics), GLV, Multichain, Gelato relay, and external contracts, as well as the \`getContract\` utility for typed address lookups.
## Constants
### \`CONTRACTS\`
\`\`\`typescript
const CONTRACTS: Record>;
\`\`\`
A complete mapping of chain IDs to contract addresses for all GMX protocol contracts.
\`CONTRACTS\` covers five chain IDs:
| Chain | Chain ID | Type |
| ---------------- | -------- | --------------------- |
| Arbitrum | \`42161\` | Production |
| Avalanche | \`43114\` | Production |
| Botanix | \`3637\` | Production |
| Avalanche Fuji | \`43113\` | Development / testnet |
| Arbitrum Sepolia | \`421614\` | Development / testnet |
Contract categories vary by chain. Production chains (Arbitrum and Avalanche) include both V1 contracts (Vault, GLP, staking trackers) and V2 Synthetics contracts (DataStore, ExchangeRouter, SyntheticsReader, GLV router, Multichain routers). Botanix and the testnet chains include V2 Synthetics contracts only, with V1 slots set to \`zeroAddress\`.
\`\`\`typescript
// Get the DataStore address on Arbitrum
const dataStoreAddress = CONTRACTS\[42161\].DataStore;
// Returns: "0xFD70de6b91282D8017aA4E741e9Ae325CAb992d8"
// Get the ExchangeRouter address on Avalanche
const exchangeRouterAddress = CONTRACTS\[43114\].ExchangeRouter;
// Returns: "0x8f550E53DFe96C055D5Bdb267c21F268fCAF63B2"
// Iterate all production chains
for (const chainId of CONTRACTS\_CHAIN\_IDS) {
const router = CONTRACTS\[chainId\].ExchangeRouter;
console.log(\`ExchangeRouter on ${chainId}: ${router}\`);
}
\`\`\`
:::tip
Prefer \`getContract\` over direct \`CONTRACTS\` indexing in application code. It provides a typed lookup and throws a descriptive error if the chain ID or contract name is not found, making integration bugs easier to diagnose.
:::
## Types
### \`ContractName\`
\`\`\`typescript
type ContractName = ExtractContractNames;
// resolves to: "DataStore" | "ExchangeRouter" | "SyntheticsReader" | "Vault" | ...
\`\`\`
A union of every contract key name defined across all chains in \`CONTRACTS\`. The type is derived automatically from the \`CONTRACTS\` object, so it stays in sync with the source without manual maintenance.
\`\`\`typescript
// Valid: "DataStore" is a key in CONTRACTS
const name: ContractName = "DataStore";
// Also valid
const names: ContractName\[\] = \["ExchangeRouter", "SyntheticsReader", "GlvRouter"\];
\`\`\`
\`ContractName\` includes all contract keys from all chains, including V1-only contracts (such as \`"Vault"\`, \`"GlpManager"\`) and V2-only contracts (such as \`"DataStore"\`, \`"GlvRouter"\`). Some contracts are set to \`zeroAddress\` on chains where they are not deployed — use \`getContract\` to retrieve the address and check the result before use if the contract may not be active on a given chain.
## Methods
### \`getContract\`
\`\`\`typescript
function getContract(chainId: ContractsChainId, name: ContractName): Address;
\`\`\`
Retrieves a specific contract address for a given chain ID and contract name.
#### Parameters
| Parameter | Type | Description |
| --------- | ------------------ | ---------------------------------------------------------------------- |
| \`chainId\` | \`ContractsChainId\` | The numeric chain ID (42161, 43114, 3637, 43113, or 421614) |
| \`name\` | \`ContractName\` | The contract name key (for example, \`"DataStore"\`, \`"ExchangeRouter"\`) |
#### Returns
\`Address\` — the checksummed hex address string for the contract on the given chain.
:::warning
\`getContract\` throws an \`Error\` if \`chainId\` is not in \`CONTRACTS\` or if \`name\` is not found for that chain. Always call with a valid \`ContractsChainId\` value.
:::
\`\`\`typescript
// Get DataStore on Arbitrum
const dataStoreAddress = getContract(ARBITRUM, "DataStore");
// Returns: "0xFD70de6b91282D8017aA4E741e9Ae325CAb992d8"
// Get ExchangeRouter on Avalanche
const exchangeRouterAddress = getContract(AVALANCHE, "ExchangeRouter");
// Returns: "0x8f550E53DFe96C055D5Bdb267c21F268fCAF63B2"
// Use with a dynamic chain ID (validated at runtime)
function lookupContract(chainId: number, name: ContractName): Address | null {
try {
return getContract(chainId as ContractsChainId, name);
} catch {
return null;
}
}
\`\`\`
## Related
- \[\`chains\`\](./chains.md) — chain IDs, \`ContractsChainId\`, \`ContractsChainIdProduction\`
- \[SDK v1 Getting Started\](../../readme.mdx)
---
## dataStore
This module is the SDK's public registry of GMX \`DataStore\` key constants and key-builder helpers.
## What it exports
- Static hashed keys such as \`MIN\_COLLATERAL\_USD\_KEY\`, \`MAX\_AUTO\_CANCEL\_ORDERS\_KEY\`, \`USE\_OPEN\_INTEREST\_IN\_TOKENS\_FOR\_BALANCE\`, and \`REQUEST\_EXPIRATION\_TIME\_KEY\`
- Dynamic key builders such as \`positionImpactFactorKey\`, \`swapFeeFactorKey\`, \`poolAmountKey\`, \`accountOrderListKey\`, \`uiFeeFactorKey\`, \`hashedPositionKey\`, and \`claimTermsKey\`
\`\`\`typescript
MAX\_AUTO\_CANCEL\_ORDERS\_KEY,
positionImpactFactorKey,
poolAmountKey,
uiFeeFactorKey,
} from "@gmx-io/sdk/configs/dataStore";
\`\`\`
Use this module when you need to read or derive raw \`DataStore\` keys for multicalls or contract debugging. The entrypoint is large by design because it mirrors the on-chain key layout.
---
## express
This module exports constants and helpers for express trading, subaccounts, and Gelato-relayed flows.
## Exports
This module provides constants and helper functions for Express Trading integrations.
### Constants
- \`DEFAULT\_SUBACCOUNT\_EXPIRY\_DURATION\` -- default One-Click Trading session length (7 days)
- \`DEFAULT\_SUBACCOUNT\_MAX\_ALLOWED\_COUNT\` -- maximum allowed subaccount count (90)
- \`DEFAULT\_PERMIT\_DEADLINE\_DURATION\` -- default ERC-20 permit deadline (1 hour)
- \`DEFAULT\_EXPRESS\_ORDER\_DEADLINE\_DURATION\` -- default express order deadline (1 hour)
- \`MIN\_RELAYER\_FEE\_USD\` -- minimum relayer fee threshold (0.5 USD)
- \`EXPRESS\_EXTRA\_EXECUTION\_FEE\_BUFFER\_BPS\` -- extra execution fee buffer in basis points (1000 bps)
\`\`\`typescript
\`\`\`
### Helper functions
#### \`getGasPaymentTokens\`
\`\`\`typescript
getGasPaymentTokens(chainId: number): string\[\]
\`\`\`
Returns the list of token addresses accepted for gas payment on the given chain. For example, on Arbitrum this returns the addresses of USDC, WETH, and USDT.
#### \`getDefaultGasPaymentToken\`
\`\`\`typescript
getDefaultGasPaymentToken(chainId: number): string
\`\`\`
Returns the default gas payment token address for the given chain. This is the first token in the gas payment list (USDC on Arbitrum, USDC on Avalanche).
#### \`getRelayerFeeToken\`
\`\`\`typescript
getRelayerFeeToken(chainId: number): Token
\`\`\`
Returns the wrapped native token for the given chain. The relayer fee is denominated in this token.
\`\`\`typescript
const gasTokens = getGasPaymentTokens(42161); // Arbitrum gas payment token addresses
const defaultToken = getDefaultGasPaymentToken(42161); // USDC address on Arbitrum
\`\`\`
Use this module only if your integration exposes express or subaccount flows directly.
---
## factors
This module provides constants for various impact thresholds, slippage limits, and basis point calculations used throughout the GMX protocol. These factors help determine when to show warnings to users and set default acceptable limits for trading operations.
## Constants
The following constants are exported from \`@gmx-io/sdk/configs/factors\`. All numeric values represent basis points unless otherwise noted.
- \`USD\_DECIMALS: number\` — Number of decimal places for USD values (30)
\`\`\`typescript
const oneDollar = 10n \*\* BigInt(USD\_DECIMALS);
\`\`\`
- \`BASIS\_POINTS\_DIVISOR: number\` — Divisor for basis points calculations (10000)
\`\`\`typescript
const percentage = (basisPoints / BASIS\_POINTS\_DIVISOR) \* 100;
\`\`\`
- \`BASIS\_POINTS\_DIVISOR\_BIGINT: bigint\` — BigInt version of the basis points divisor (10000n)
\`\`\`typescript
const percentageBigInt = (basisPointsBigInt \* 100n) / BASIS\_POINTS\_DIVISOR\_BIGINT;
\`\`\`
- \`BASIS\_POINTS\_DECIMALS: number\` — Number of decimal places for basis points (4)
\`\`\`typescript
const formattedBps = basisPoints.toFixed(BASIS\_POINTS\_DECIMALS);
\`\`\`
- \`HIGH\_PRICE\_IMPACT\_BPS: number\` — Threshold for high price impact warning (80 basis points = 0.8%)
\`\`\`typescript
if (priceImpactBps > HIGH\_PRICE\_IMPACT\_BPS) {
console.warn("High price impact detected");
}
\`\`\`
- \`HIGH\_COLLATERAL\_IMPACT\_BPS: number\` — Threshold for high collateral impact warning (2500 basis points = 25%)
\`\`\`typescript
if (collateralImpactBps > HIGH\_COLLATERAL\_IMPACT\_BPS) {
console.warn("High collateral impact");
}
\`\`\`
- \`HIGH\_SWAP\_IMPACT\_BPS: number\` — Threshold for high swap impact warning (50 basis points = 0.5%)
\`\`\`typescript
const showSwapWarning = swapImpactBps > HIGH\_SWAP\_IMPACT\_BPS;
\`\`\`
- \`DEFAULT\_ACCEPTABLE\_PRICE\_IMPACT\_BUFFER: number\` — Default buffer for acceptable price impact (30 basis points = 0.3%)
\`\`\`typescript
const maxAcceptableImpact = priceImpact + DEFAULT\_ACCEPTABLE\_PRICE\_IMPACT\_BUFFER;
\`\`\`
- \`HIGH\_ALLOWED\_SWAP\_SLIPPAGE\_BPS: number\` — Threshold for high swap slippage (20 basis points = 0.2%)
\`\`\`typescript
if (slippageBps > HIGH\_ALLOWED\_SWAP\_SLIPPAGE\_BPS) {
console.warn("High slippage tolerance");
}
\`\`\`
- \`DEFAULT\_ALLOWED\_SWAP\_SLIPPAGE\_BPS: bigint\` — Default allowed swap slippage (100 basis points = 1%)
\`\`\`typescript
const slippageTolerance = DEFAULT\_ALLOWED\_SWAP\_SLIPPAGE\_BPS;
\`\`\`
---
## gasLimits
This module exports the SDK's static gas-limit defaults.
## Exports
- \`StaticGasLimitsConfig\` — the shape of the per-chain static gas-limit map
- \`GAS\_LIMITS\_STATIC\_CONFIG\` — static per-chain gas limits used alongside dynamically fetched datastore values
\`\`\`typescript
console.log(GAS\_LIMITS\_STATIC\_CONFIG\[42161\]);
\`\`\`
---
## markets
This module provides market configuration data for the GMX protocol across different blockchain networks. It contains predefined market configurations including token addresses and swap limits for trading pairs on supported chains.
## Types
The \`markets\` module exports the following TypeScript types.
### MarketConfig
Configuration for a single market, keyed by market token address in the \`MARKETS\` map.
\`\`\`typescript
type MarketConfig = {
marketTokenAddress: string;
indexTokenAddress: string;
longTokenAddress: string;
shortTokenAddress: string;
};
\`\`\`
### MarketsConfigMap
A mapping from market token address to \`MarketConfig\`.
\`\`\`typescript
type MarketsConfigMap = Record;
\`\`\`
### MarketLabel
A template literal type for market label strings in the format \`"SYMBOL/USD \[LONG-SHORT\]"\`.
\`\`\`typescript
type MarketLabel = \`${string}/USD \[${string}-${string}\]\`;
\`\`\`
\`\`\`typescript
const label: MarketLabel = "BTC/USD \[WBTC.e-USDC\]";
\`\`\`
## Constants
### SWAP\_GRAPH\_MAX\_MARKETS\_PER\_TOKEN
\`SWAP\_GRAPH\_MAX\_MARKETS\_PER\_TOKEN: number\`
Maximum number of markets per token considered when building the swap graph. Value: \`5\`.
\`\`\`typescript
console.log(SWAP\_GRAPH\_MAX\_MARKETS\_PER\_TOKEN); // 5
\`\`\`
### MARKETS
\`MARKETS: Record\`
Complete market configuration mapping for all supported chains, keyed first by chain ID and then by market token address.
\`\`\`typescript
// Get all markets for Arbitrum
const arbitrumMarkets = MARKETS\[ARBITRUM\];
// Get a specific market configuration
const btcUsdMarket = MARKETS\[ARBITRUM\]\["0x47c031236e19d024b42f8AE6780E44A573170703"\];
console.log(btcUsdMarket.indexTokenAddress); // BTC index token address
\`\`\`
## Methods
The \`markets\` module exports the following functions for looking up market configuration by chain, address, or label.
### getMarketsByChainId
\`getMarketsByChainId(chainId: ContractsChainId): Record\`
Returns all market configs for a chain. Throws if the chain ID has no configured markets.
\`\`\`typescript
const markets = getMarketsByChainId(ARBITRUM);
for (const \[address, config\] of Object.entries(markets)) {
console.log(address, config.indexTokenAddress);
}
\`\`\`
### getMarketByLabel
\`getMarketByLabel(chainId: ContractsChainId, label: MarketLabel): MarketConfig\`
Retrieves a market configuration by its human-readable label. Throws if the label is invalid or no matching market is found.
\`\`\`typescript
const market = getMarketByLabel(ARBITRUM, "BTC/USD \[WBTC.e-USDC\]");
console.log(market.marketTokenAddress);
\`\`\`
### fixTokenSymbolFromMarketLabel
\`fixTokenSymbolFromMarketLabel(chainId: ContractsChainId, symbol: string): string\`
Normalizes a raw token symbol extracted from a market label to match the token configuration format. For example, on Arbitrum \`"WBTC"\` maps to \`"BTC"\` and \`"ETH"\` maps to \`"WETH"\`.
\`\`\`typescript
console.log(fixTokenSymbolFromMarketLabel(ARBITRUM, "WBTC")); // "BTC"
console.log(fixTokenSymbolFromMarketLabel(ARBITRUM, "ETH")); // "WETH"
\`\`\`
### isMarketTokenAddress
\`isMarketTokenAddress(chainId: number, marketTokenAddress: string): boolean\`
Returns \`true\` if the given address is a known market token address on the specified chain.
\`\`\`typescript
isMarketTokenAddress(ARBITRUM, "0x47c031236e19d024b42f8AE6780E44A573170703"); // true
isMarketTokenAddress(ARBITRUM, "0x0000000000000000000000000000000000000000"); // false
\`\`\`
### getTokenAddressByMarket
\`getTokenAddressByMarket(chainId: number, marketTokenAddress: string, tokenType: "long" | "short" | "index"): string\`
Returns the address of the long, short, or index token for a market. For \`"index"\`, returns the native token address where applicable.
\`\`\`typescript
const longTokenAddress = getTokenAddressByMarket(ARBITRUM, "0x47c031236e19d024b42f8AE6780E44A573170703", "long");
\`\`\`
### getMarketIndexToken
\`getMarketIndexToken(chainId: number, marketTokenAddress: string): Token\`
Returns the \`Token\` object for a market's index token.
### getTokenSymbolByMarket
\`getTokenSymbolByMarket(chainId: number, marketTokenAddress: string, tokenType: "long" | "short" | "index"): string\`
Returns the symbol of the long, short, or index token for a market.
### getIsSpotOnlyMarket
\`getIsSpotOnlyMarket(chainId: number, marketTokenAddress: string): boolean\`
Returns \`true\` if the market is a spot-only market (index token address is \`zeroAddress\`, meaning no perpetuals).
### getMarketIsSameCollaterals
\`getMarketIsSameCollaterals(chainId: number, marketTokenAddress: string): boolean\`
Returns \`true\` if the market uses the same token for both long and short collateral (single-sided collateral market).
---
## multichain
This module exports chain guards used by the SDK's multichain funding logic.
## Exports
- \`isSettlementChain(chainId)\` — narrows a chain ID to \`SettlementChainId\`
- \`isSourceChain(chainId, settlementChainId)\` — checks whether a source chain is valid for a settlement chain
- \`isSourceChainForAnySettlementChain(chainId)\` — checks whether a chain is a valid source chain anywhere in the SDK
\`\`\`typescript
\`\`\`
---
## oracleKeeper
This module provides utilities for retrieving Oracle Keeper URLs for different blockchain networks supported by the GMX protocol. Oracle Keepers are responsible for providing price feeds and other critical data to the GMX smart contracts.
## Methods
Both functions throw an \`Error\` if \`chainId\` is not one of the supported chains: \`ARBITRUM\`, \`AVALANCHE\`, \`AVALANCHE\_FUJI\`, \`BOTANIX\`, or \`ARBITRUM\_SEPOLIA\`.
### getOracleKeeperUrl
\`\`\`typescript
getOracleKeeperUrl(chainId: number): string
\`\`\`
Returns the primary Oracle Keeper URL for the chain. Throws if \`chainId\` is not supported.
\`\`\`typescript
const url = getOracleKeeperUrl(ARBITRUM);
// "https://arbitrum-api.gmxinfra.io"
\`\`\`
### getOracleKeeperFallbackUrls
\`\`\`typescript
getOracleKeeperFallbackUrls(chainId: number): string\[\]
\`\`\`
Returns an ordered list of fallback Oracle Keeper URLs for the chain. Use these when the primary URL is unavailable. Throws if \`chainId\` is not supported.
\`\`\`typescript
const fallbackUrls = getOracleKeeperFallbackUrls(ARBITRUM);
// \["https://arbitrum-api-fallback.gmxinfra.io", "https://arbitrum-api-fallback.gmxinfra2.io"\]
\`\`\`
---
## tokens
This module provides comprehensive token configuration and utilities for the GMX protocol across different blockchain networks. It includes token definitions, mappings, and helper functions for working with tokens in both V1 and V2 versions of the protocol.
## Constants
The constants section covers three categories: special stub addresses, pre-built token data maps, and color mappings. Import any constant directly from \`@gmx-io/sdk/configs/tokens\`.
### Special addresses
- \`NATIVE\_TOKEN\_ADDRESS: string\` — The zero address (\`"0x0000000000000000000000000000000000000000"\`) used to represent native tokens (ETH, AVAX, etc.).
- \`GM\_STUB\_ADDRESS: string\` — Stub address used internally to represent GM (liquidity pool) tokens: \`""\`.
- \`GLV\_STUB\_ADDRESS: string\` — Stub address used internally to represent GLV (liquidity vault) tokens: \`""\`.
\`\`\`typescript
console.log(NATIVE\_TOKEN\_ADDRESS); // "0x0000000000000000000000000000000000000000"
\`\`\`
### Token data maps (pre-built)
These objects are populated at module initialization time from the static \`TOKENS\` array. Prefer the getter functions below over accessing these maps directly.
- \`TOKENS: { \[chainId: number\]: Token\[\] }\` — Raw token array for each chain, used as the source of truth.
- \`TOKENS\_MAP: { \[chainId: number\]: { \[address: string\]: Token } }\` — Tokens keyed by address per chain.
- \`V1\_TOKENS: { \[chainId: number\]: Token\[\] }\` — V1-available tokens per chain.
- \`V2\_TOKENS: { \[chainId: number\]: Token\[\] }\` — V2-available tokens per chain.
- \`SYNTHETIC\_TOKENS: { \[chainId: number\]: Token\[\] }\` — Synthetic tokens per chain.
- \`TOKENS\_BY\_SYMBOL\_MAP: { \[chainId: number\]: { \[symbol: string\]: Token } }\` — Tokens keyed by symbol per chain.
- \`WRAPPED\_TOKENS\_MAP: { \[chainId: number\]: Token }\` — The wrapped native token per chain.
- \`NATIVE\_TOKENS\_MAP: { \[chainId: number\]: Token }\` — The native token per chain.
\`\`\`typescript
const arbitrumTokens = TOKENS\[ARBITRUM\];
console.log(arbitrumTokens\[0\].symbol); // "ETH"
\`\`\`
### TOKEN\_COLOR\_MAP
\`TOKEN\_COLOR\_MAP: { \[symbol: string\]: string }\`
Color mappings for token symbols used in UI components. Includes a \`default\` fallback color.
\`\`\`typescript
console.log(TOKEN\_COLOR\_MAP.ETH); // "#6062a6"
console.log(TOKEN\_COLOR\_MAP.BTC); // "#F7931A"
console.log(TOKEN\_COLOR\_MAP.default); // "#6062a6"
\`\`\`
## Methods
The tokens config module exports functions organized into two groups: lookup and validation helpers for retrieving token objects, and display/conversion utilities. Import any function directly from \`@gmx-io/sdk/configs/tokens\`. Chain ID constants (such as \`ARBITRUM\`) must be imported from \`@gmx-io/sdk/configs/chains\`.
### getSyntheticTokens
\`\`\`typescript
getSyntheticTokens(chainId: number): Token\[\]
\`\`\`
Returns all synthetic tokens available on the specified chain.
\`\`\`typescript
const syntheticTokens = getSyntheticTokens(ARBITRUM);
console.log(syntheticTokens.map((token) => token.symbol));
\`\`\`
### getWrappedToken
\`\`\`typescript
getWrappedToken(chainId: number): Token
\`\`\`
Returns the wrapped native token for the specified chain (for example, WETH on Arbitrum, WAVAX on Avalanche).
\`\`\`typescript
const wrappedToken = getWrappedToken(ARBITRUM);
console.log(wrappedToken.symbol); // "WETH"
\`\`\`
### getNativeToken
\`\`\`typescript
getNativeToken(chainId: number): Token
\`\`\`
Returns the native token for the specified chain.
\`\`\`typescript
const nativeToken = getNativeToken(ARBITRUM);
console.log(nativeToken.symbol); // "ETH"
\`\`\`
### getTokens
\`\`\`typescript
getTokens(chainId: number): Token\[\]
\`\`\`
Returns all tokens available on the specified chain.
\`\`\`typescript
const allTokens = getTokens(ARBITRUM);
\`\`\`
### getV1Tokens
\`\`\`typescript
getV1Tokens(chainId: number): Token\[\]
\`\`\`
Returns tokens available in GMX V1 on the specified chain.
### getV2Tokens
\`\`\`typescript
getV2Tokens(chainId: number): Token\[\]
\`\`\`
Returns tokens available in GMX V2 on the specified chain.
### getTokensMap
\`\`\`typescript
getTokensMap(chainId: number): { \[address: string\]: Token }
\`\`\`
Returns a mapping of token addresses to token objects for the specified chain.
\`\`\`typescript
const tokensMap = getTokensMap(ARBITRUM);
const ethToken = tokensMap\["0x0000000000000000000000000000000000000000"\];
console.log(ethToken.symbol); // "ETH"
\`\`\`
### getWhitelistedV1Tokens
\`\`\`typescript
getWhitelistedV1Tokens(chainId: number): Token\[\]
\`\`\`
Returns whitelisted tokens for GMX V1 on the specified chain. Equivalent to \`getV1Tokens\`.
### getVisibleV1Tokens
\`\`\`typescript
getVisibleV1Tokens(chainId: number): Token\[\]
\`\`\`
Returns visible V1 tokens (excluding wrapped tokens) for the specified chain.
### isValidToken
\`\`\`typescript
isValidToken(chainId: number, address: string): boolean
\`\`\`
Returns \`true\` if the token address exists on the specified chain. Throws if the chain ID is not recognized.
\`\`\`typescript
const isValid = isValidToken(ARBITRUM, "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1");
console.log(isValid); // true
\`\`\`
### isValidTokenSafe
\`\`\`typescript
isValidTokenSafe(chainId: number, address: string): boolean
\`\`\`
Safely checks if a token address exists on the specified chain without throwing.
\`\`\`typescript
isValidTokenSafe(ARBITRUM, "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"); // true
isValidTokenSafe(ARBITRUM, "0xinvalidaddress"); // false
\`\`\`
### getToken
\`\`\`typescript
getToken(chainId: number, address: string): Token
\`\`\`
Returns the token object for the specified address. Throws if the chain or address is not recognized.
\`\`\`typescript
const wethToken = getToken(ARBITRUM, "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1");
console.log(wethToken.symbol); // "WETH"
\`\`\`
### getTokenBySymbol
\`\`\`typescript
getTokenBySymbol(chainId: number, symbol: string, options?: { isSynthetic?: boolean; version?: "v1" | "v2"; symbolType?: "symbol" | "baseSymbol" }): Token
\`\`\`
Returns the token object for the specified symbol. Throws if not found.
\`\`\`typescript
const ethToken = getTokenBySymbol(ARBITRUM, "ETH");
const syntheticBTC = getTokenBySymbol(ARBITRUM, "BTC", { isSynthetic: true });
\`\`\`
### getTokenBySymbolSafe
\`\`\`typescript
getTokenBySymbolSafe(chainId: number, symbol: string, options?: { isSynthetic?: boolean; version?: "v1" | "v2"; symbolType?: "symbol" | "baseSymbol" }): Token | undefined
\`\`\`
Like \`getTokenBySymbol\` but returns \`undefined\` instead of throwing when the token is not found.
\`\`\`typescript
const token = getTokenBySymbolSafe(ARBITRUM, "ETH"); // Token
const missing = getTokenBySymbolSafe(ARBITRUM, "INVALID"); // undefined
\`\`\`
### convertTokenAddress
\`\`\`typescript
convertTokenAddress(chainId: number, address: string, convertTo?: "wrapped" | "native"): string
\`\`\`
Converts between native and wrapped token addresses.
\`\`\`typescript
const wrappedAddress = convertTokenAddress(ARBITRUM, NATIVE\_TOKEN\_ADDRESS, "wrapped");
console.log(wrappedAddress); // "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"
const nativeAddress = convertTokenAddress(ARBITRUM, "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", "native");
console.log(nativeAddress); // "0x0000000000000000000000000000000000000000"
\`\`\`
### getNormalizedTokenSymbol
\`\`\`typescript
getNormalizedTokenSymbol(tokenSymbol: string): string
\`\`\`
Returns a normalized version of a token symbol by applying these rules in order:
- \`WBTC\`, \`WETH\`, \`WAVAX\` → strip the leading \`W\` (for example, \`WETH\` → \`ETH\`)
- \`PBTC\`, \`STBTC\` → return \`"BTC"\`
- \`XAUT\` → return \`"XAUT.v2"\`
- Symbols containing \`.\` → return the part before the dot (for example, \`USDC.E\` → \`USDC\`)
- All other symbols → return as-is
\`\`\`typescript
console.log(getNormalizedTokenSymbol("WETH")); // "ETH"
console.log(getNormalizedTokenSymbol("USDC.E")); // "USDC"
console.log(getNormalizedTokenSymbol("PBTC")); // "BTC"
\`\`\`
### isChartAvailableForToken
\`\`\`typescript
isChartAvailableForToken(chainId: number, tokenSymbol: string): boolean
\`\`\`
Returns \`true\` if chart data is available for the token on the specified chain.
### getPriceDecimals
\`\`\`typescript
getPriceDecimals(chainId: number, tokenSymbol?: string): number
\`\`\`
Returns the number of decimal places to display for a token's price. Defaults to \`2\`.
\`\`\`typescript
console.log(getPriceDecimals(ARBITRUM, "ETH")); // 2
\`\`\`
### isTokenInList
\`\`\`typescript
isTokenInList(token: Token, tokenList: Token\[\]): boolean
\`\`\`
Returns \`true\` if the token exists in the given list (matched by address).
### isSimilarToken
\`\`\`typescript
isSimilarToken(tokenA: Token, tokenB: Token): boolean
\`\`\`
Returns \`true\` if two tokens are similar. Two tokens are considered similar when they share the same address, or when their \`symbol\` and \`baseSymbol\` fields overlap (for example, WETH with \`baseSymbol: "ETH"\` is similar to a token with \`symbol: "ETH"\`).
### getTokenVisualMultiplier
\`\`\`typescript
getTokenVisualMultiplier(token: Token): string
\`\`\`
Returns the visual multiplier string for a token, derived from \`token.visualPrefix\` or \`token.visualMultiplier\`. Returns an empty string if neither is set.
### getStableTokens
\`\`\`typescript
getStableTokens(chainId: number): Token\[\]
\`\`\`
Returns all stable tokens on the specified chain (tokens with \`isStable: true\`).
### getCategoryTokenAddresses
\`\`\`typescript
getCategoryTokenAddresses(chainId: number, category: TokenCategory): string\[\]
\`\`\`
Returns token addresses belonging to the specified category on a chain.
### createTokensMap
\`\`\`typescript
createTokensMap(tokens: Token\[\]): Record
\`\`\`
Creates a token address-to-token map from an array of tokens.
\`\`\`typescript
const v1Tokens = getV1Tokens(ARBITRUM);
const tokensMap = createTokensMap(v1Tokens);
\`\`\`
### isUsdBasedStableToken
\`\`\`typescript
isUsdBasedStableToken(token: Token): boolean
\`\`\`
Returns \`true\` if the token is a USD-based stablecoin (USDC, USDC.E, USDT, DAI, USDC.SG).
\`\`\`typescript
const usdc = getTokenBySymbol(ARBITRUM, "USDC");
console.log(isUsdBasedStableToken(usdc)); // true
\`\`\`
---
## twap
This module exports TWAP configuration defaults.
## Exports
- \`DEFAULT\_TWAP\_NUMBER\_OF\_PARTS\`
- \`MIN\_TWAP\_NUMBER\_OF\_PARTS\`
- \`MAX\_TWAP\_NUMBER\_OF\_PARTS\`
- \`DEFAULT\_TWAP\_DURATION\`
\`\`\`typescript
\`\`\`
Use these constants together with \[\`utils/twap\`\](../utils/twap.md).
---
## uniswapV3
This module exposes Uniswap v3 deployment metadata used by external-swap integrations.
## Exports
- \`UniswapV3Deployment\` — deployment shape
- \`getUniswapV3Deployment(chainId)\`
- \`hasUniswapV3Deployment(chainId)\`
\`\`\`typescript
\`\`\`
---
## venus
This module exposes Venus deployment metadata used by integrations that need Venus token support.
## Exports
- \`VenusVTokenConfig\`
- \`VenusDeployment\`
- \`VENUS\_EXCHANGE\_RATE\_DECIMALS\`
- \`getVenusDeployment(chainId)\`
- \`hasVenusDeployment(chainId)\`
\`\`\`typescript
\`\`\`
---
## Useful modules
The GMX SDK exports constants, types, and utility functions that you can import directly without going through the \`GmxSdk\` class. These exports are organized into three top-level categories:
- \*\*\`configs/\`\*\* — chain IDs, contract addresses, token metadata, market parameters, oracle keeper URLs, and fee factors
- \*\*\`utils/\`\*\* — fee calculations, price impact, swap routing, position sizing, number formatting, error parsing, and other computation helpers
- \*\*\`types/\`\*\* — type-only entrypoints for SDK configs, markets, tokens, orders, positions, fees, price candles, trade flows, referrals, TWAP, trade history, and Subsquid schema types
Use these exports to implement custom logic or to pre-compute values before passing them to SDK methods. Import any export directly from its module path, for example:
\`\`\`typescript
\`\`\`
See the sub-pages in this section for the full API reference for each module.
---
## 24h types
This type-only entrypoint exports candle data used by the SDK's 24-hour market views.
## Exports
- \`DayPriceCandle\`
\`\`\`typescript
\`\`\`
---
## chains types
This type-only entrypoint exports chain configuration shapes.
## Exports
- \`ContractsChainConfig\`
- \`SourceChainConfig\`
\`\`\`typescript
\`\`\`
---
## fees types
This type-only entrypoint exports fee and gas-limit model types.
## Exports
- \`ExecutionFee\`
- \`FeeItem\`
- \`SwapFeeItem\`
- \`ExternalSwapFeeItem\`
- \`GasLimitsConfig\`
- \`L1ExpressOrderGasReference\`
\`\`\`typescript
\`\`\`
---
## markets types
This type-only entrypoint exports the SDK's market and market-info model types.
## Exports
- \`PnlFactorType\`
- \`MarketSdkConfig\`
- \`Market\`
- \`MarketPoolTokens\`
- \`MarketInfo\`
- \`RawOpenInterestValues\`
- \`MarketValues\`
- \`MarketConfig\`
- \`MarketsData\`
- \`RawMarketInfo\`
- \`RawMarketsInfoData\`
- \`MarketsInfoData\`
- \`MarketTokensAPRData\`
- \`UserEarningsData\`
- \`ContractMarketPrices\`
- \`ClaimableFunding\`
- \`ClaimableFundingData\`
- \`MarketTicker\`
- \`LeverageTier\`
- \`MarketWithTiers\`
\`\`\`typescript
\`\`\`
---
## orders types
This type-only entrypoint exports order enums and enriched order model types.
## Exports
- \`OrderType\`
- \`SwapOrderType\`
- \`IncreaseOrderType\`
- \`DecreaseOrderType\`
- \`SwapPricingType\`
- \`DecreasePositionSwapType\`
- \`Order\`
- \`SwapOrderInfo\`
- \`PositionOrderInfo\`
- \`TwapOrderInfo\`
- \`OrderInfo\`
- \`OrdersData\`
- \`OrdersInfoData\`
- \`OrderTxnType\`
- \`OrderParams\`
- \`ApiOrderInfo\`
\`\`\`typescript
\`\`\`
---
## positions types
This type-only entrypoint exports raw and enriched position model types.
## Exports
- \`Position\`
- \`PositionInfo\`
- \`PositionInfoLoaded\`
- \`RawPositionInfo\`
- \`PositionsData\`
- \`PositionsInfoData\`
- \`ApiPositionInfo\`
\`\`\`typescript
\`\`\`
---
## prices types
This type-only entrypoint exports OHLCV candle shapes and request params for the SDK's price candle API helpers.
## Exports
- \`OhlcvCandle\`
- \`OhlcvParams\`
\`\`\`typescript
\`\`\`
---
## referrals types
This type-only entrypoint exports the SDK's referral data shapes.
## Exports
- \`UserReferralInfo\`
- \`RebateDistributionType\`
- \`RebateDistribution\`
- \`CodeOwnershipInfo\`
- \`ReferralCodeStats\`
- \`AffiliateTotalStats\`
- \`TraderReferralTotalStats\`
- \`TierInfo\`
- \`ReferralsStats\`
- \`TotalReferralsStats\`
\`\`\`typescript
\`\`\`
---
## sdk types
This type-only entrypoint exports the v1 client config interface.
## Exports
- \`GmxSdkConfig\`
\`\`\`typescript
\`\`\`
See \[Getting Started\](../../) for the currently documented \`GmxSdkConfig\` fields and initialization patterns.
---
## sidecarOrders types
This type-only entrypoint exports sidecar stop-loss, take-profit, and limit-order entry types.
## Exports
- \`GroupPrefix\`
- \`EntryField\`
- \`InitialEntry\`
- \`SidecarOrderEntryBase\`
- \`SidecarSlTpOrderEntry\`
- \`SidecarSlTpOrderEntryValid\`
- \`SidecarLimitOrderEntry\`
- \`SidecarLimitOrderEntryValid\`
- \`SidecarOrderEntry\`
- \`SidecarOrderEntryGroupBase\`
- \`SidecarOrderEntryGroup\`
\`\`\`typescript
\`\`\`
---
## subsquid types
This type-only entrypoint re-exports the generated GraphQL schema types from the SDK's Subsquid codegen.
## What it contains
- GraphQL scalar helpers such as \`Maybe\`, \`InputMaybe\`, \`Exact\`, and \`Scalars\`
- Generated entity types for the Subsquid schema
- Generated connection, \`WhereInput\`, and \`OrderByInput\` types for paginated GraphQL queries
\`\`\`typescript
\`\`\`
This surface is generated and intentionally large. Use it when you need exact schema types for custom Subsquid queries.
---
## swap types
This type-only entrypoint exports the swap-strategy model types used by the trade helpers.
## Exports
- \`NoSwapStrategy\`
- \`ExternalSwapStrategy\`
- \`InternalSwapStrategy\`
- \`CombinedSwapStrategy\`
- \`SwapStrategyForIncreaseOrders\`
- \`SwapStrategyForSwapOrders\`
\`\`\`typescript
\`\`\`
---
## tokens types
This type-only entrypoint exports token metadata, pricing, and balance model types.
## Exports
- \`ERC20Address\`
- \`NativeTokenSupportedAddress\`
- \`TokenAddressTypesMap\`
- \`ContractPrice\`
- \`TokenCategory\`
- \`Token\`
- \`TokenInfo\`
- \`SignedTokenPermit\`
- \`TokenPrices\`
- \`TokenBalanceType\`
- \`TokenAsyncData\`
- \`TokenData\`
- \`ProgressiveTokenData\`
- \`TokensRatio\`
- \`TokensRatioAndSlippage\`
- \`InfoTokens\`
- \`TokenBalancesData\`
- \`TokenPricesData\`
- \`TokensAllowanceData\`
- \`TokensData\`
- \`ProgressiveTokensData\`
\`\`\`typescript
\`\`\`
---
## trade types
This type-only entrypoint exports the main trade calculation enums and result types.
## Exports
- \`TradeType\`
- \`TradeMode\`
- \`TriggerThresholdType\`
- \`TradeFlags\`
- \`SwapAmounts\`
- \`IncreasePositionAmounts\`
- \`DecreasePositionAmounts\`
- \`DepositAmounts\`
- \`WithdrawalAmounts\`
- \`NextPositionValues\`
- \`SwapStats\`
- \`SwapPathStats\`
- \`MarketEdge\`
- \`SwapRoute\`
- \`SwapPaths\`
- \`SwapEstimator\`
- \`NaiveSwapEstimator\`
- \`NaiveNetworkEstimator\`
- \`MarketEdgeLiquidityGetter\`
- \`SwapOptimizationOrderArray\`
- \`FindSwapPath\`
- \`TradeFeesType\`
- \`ExternalSwapAggregator\`
- \`ExternalSwapQuote\`
- \`ExternalSwapPath\`
- \`ExternalSwapQuoteParams\`
- \`ExternalSwapCalculationStrategy\`
- \`ExternalSwapInputs\`
- \`TradeFees\`
- \`GmSwapFees\`
- \`TradeSearchParams\`
\`\`\`typescript
\`\`\`
---
## tradeHistory types
This type-only entrypoint exports the SDK's normalized trade-history action types.
## Exports
- \`TradeActionType\`
- \`PositionTradeAction\`
- \`SwapTradeAction\`
- \`TradeAction\`
\`\`\`typescript
\`\`\`
---
## twap types
This type-only entrypoint exports TWAP timing and order-part parameter types.
## Exports
- \`TwapDuration\`
- \`TwapOrderParams\`
- \`TwapPartParams\`
\`\`\`typescript
\`\`\`
---
## LruCache
This module exports a small in-memory least-recently-used cache.
## Exports
- \`LRUCache\`
\`\`\`typescript
const cache = new LRUCache(100);
\`\`\`
The class exposes \`has\`, \`get\`, \`set\`, \`delete\`, \`getKeys\`, and \`clean\`.
---
## abort
This module exports abort-signal composition helpers.
## Exports
- \`combineAbortSignals(...signals)\`
\`\`\`typescript
\`\`\`
---
## bigmath
This module provides mathematical utility functions for working with BigInt values, offering operations like absolute value, multiplication with division, min/max calculations, averaging, and various rounding strategies.
\`\`\`typescript
\`\`\`
## Methods
All methods are accessed through the \`bigMath\` object exported from \`@gmx-io/sdk/utils/bigmath\`. Import it once and call any method directly.
### abs
\`\`\`typescript
abs(x: bigint): bigint
\`\`\`
Returns the absolute value of a \`bigint\`.
\`\`\`typescript
bigMath.abs(-100n); // 100n
bigMath.abs(50n); // 50n
\`\`\`
### mulDiv
\`\`\`typescript
mulDiv(x: bigint, y: bigint, z: bigint, roundUpMagnitude?: boolean): bigint
\`\`\`
Computes \`(x \* y) / z\`. When \`roundUpMagnitude\` is \`true\` and there is a nonzero remainder (checked via \`mulmod\`), the result rounds away from zero by adding \`1n\`. Default is \`false\`.
\`\`\`typescript
bigMath.mulDiv(100n, 3n, 2n); // 150n
bigMath.mulDiv(100n, 3n, 7n, true); // 43n (rounds up from 42.857...)
\`\`\`
### max
\`\`\`typescript
max(first: bigint, ...rest: bigint\[\]): bigint
\`\`\`
Returns the largest value from the provided \`bigint\` arguments.
\`\`\`typescript
bigMath.max(10n, 25n, 5n, 100n); // 100n
bigMath.max(42n); // 42n
\`\`\`
### min
\`\`\`typescript
min(first: bigint, ...rest: bigint\[\]): bigint
\`\`\`
Returns the smallest value from the provided \`bigint\` arguments.
\`\`\`typescript
bigMath.min(10n, 25n, 5n, 100n); // 5n
bigMath.min(42n); // 42n
\`\`\`
### avg
\`\`\`typescript
avg(...values: (bigint | undefined)\[\]): bigint | undefined
\`\`\`
Computes the average of the provided \`bigint\` values, ignoring \`undefined\` entries. Returns \`undefined\` if no valid values are provided (truncates fractional result using integer division).
\`\`\`typescript
bigMath.avg(10n, 20n, 30n); // 20n
bigMath.avg(10n, undefined, 30n); // 20n (undefined ignored)
bigMath.avg(undefined, undefined); // undefined
\`\`\`
### divRound
\`\`\`typescript
divRound(x: bigint, y: bigint): bigint
\`\`\`
Divides \`x\` by \`y\`, rounding to the nearest integer. Rounds up when the remainder is more than half the divisor.
\`\`\`typescript
bigMath.divRound(7n, 3n); // 2n (remainder 1, less than half of 3)
bigMath.divRound(8n, 3n); // 3n (remainder 2, more than half of 3)
\`\`\`
### divRoundUp
\`\`\`typescript
divRoundUp(x: bigint, y: bigint): bigint
\`\`\`
Divides \`x\` by \`y\`, always rounding up (ceiling division). Equivalent to \`(x + y - 1n) / y\`.
\`\`\`typescript
bigMath.divRoundUp(7n, 3n); // 3n (ceiling of 2.33...)
bigMath.divRoundUp(6n, 3n); // 2n (exact, no rounding)
\`\`\`
### mulmod
\`\`\`typescript
mulmod(x: bigint, y: bigint, m: bigint): bigint
\`\`\`
Returns \`(x \* y) % m\` — the remainder of the product when divided by the modulus \`m\`. Used internally by \`mulDiv\` to check for nonzero remainders.
\`\`\`typescript
bigMath.mulmod(7n, 8n, 10n); // 6n (56 % 10)
bigMath.mulmod(5n, 4n, 10n); // 0n (20 % 10)
\`\`\`
### clamp
\`\`\`typescript
clamp(value: bigint, min: bigint, max: bigint): bigint
\`\`\`
Constrains \`value\` to the \`\[min, max\]\` range (inclusive), returning \`min\` if below or \`max\` if above.
\`\`\`typescript
bigMath.clamp(50n, 0n, 100n); // 50n (within range)
bigMath.clamp(-5n, 0n, 100n); // 0n (below min)
bigMath.clamp(150n, 0n, 100n); // 100n (above max)
\`\`\`
---
## buildUrl
This module exports the URL builder used by the SDK's HTTP helpers.
## Exports
- \`buildUrl(baseUrl, path, query?)\`
\`\`\`typescript
const url = buildUrl("https://example.com/api", "/orders", { account: "0x1234" });
\`\`\`
---
## chains(Utils)
This module is a type-only re-export for chain configuration shapes used by the SDK.
## Exports
- \`ContractsChainConfig\`
- \`SourceChainConfig\`
\`\`\`typescript
\`\`\`
For concrete chain IDs and helpers, use \[\`configs/chains\`\](../configs/chains.md).
---
## common
This module exports small shared helpers used across the SDK.
## Exports
- \`sleep(ms, abortSignal?)\`
\`\`\`typescript
\`\`\`
---
## errors
This module exposes helpers for extracting and decoding transaction errors, especially viem and GMX custom errors.
## Functions
### \`extractErrorDataFromViemError\`
\`\`\`typescript
extractErrorDataFromViemError(error: any): string | undefined
\`\`\`
Walks a viem error object and returns the first raw revert-data payload it can find.
\`\`\`typescript
const data = extractErrorDataFromViemError(error);
\`\`\`
### \`tryDecodeCustomError\`
\`\`\`typescript
tryDecodeCustomError(reasonBytes: string): ParsedCustomError | undefined
\`\`\`
Attempts to decode a GMX custom error directly from raw revert bytes.
\`\`\`typescript
const decoded = tryDecodeCustomError("0x08c379a0...");
\`\`\`
### \`decodeErrorFromViemError\`
\`\`\`typescript
decodeErrorFromViemError(error: any): ParsedCustomError | undefined
\`\`\`
Combines raw-data extraction and GMX custom-error decoding in one step.
\`\`\`typescript
const decoded = decodeErrorFromViemError(error);
\`\`\`
### \`parseError\`
\`\`\`typescript
parseError(error: ErrorLike | string | undefined, errorDepth = 0): ErrorData | undefined
\`\`\`
Normalizes nested transaction errors into a structured object with context, decoded contract error details, and user-error classification.
\`\`\`typescript
const parsed = parseError(error);
console.log(parsed?.contractError, parsed?.errorMessage);
\`\`\`
## Related
- \[\`configs/contracts\`\](../configs/contracts.md) — ABI-backed contract context
- \[\`utils/orders\`\](./orders.md) — order helpers that may surface decoded execution errors
---
## estimateOraclePriceCount
This module provides utilities for estimating the number of oracle prices required for various GMX protocol operations. These functions help calculate gas costs and oracle price requirements for deposits, withdrawals, orders, shifts, and GLV operations.
## Methods
Each function returns a \`bigint\` representing the number of oracle price signatures required for that operation type. Import any function directly from \`@gmx-io/sdk/utils/fees\`.
### estimateDepositOraclePriceCount
\`\`\`typescript
estimateDepositOraclePriceCount(swapsCount: number | bigint): bigint
\`\`\`
Estimates the number of oracle prices required for a deposit operation. Returns \`3n + swapsCount\`.
\`\`\`typescript
const priceCount = estimateDepositOraclePriceCount(2);
console.log(priceCount); // 5n
\`\`\`
### estimateWithdrawalOraclePriceCount
\`\`\`typescript
estimateWithdrawalOraclePriceCount(swapsCount: bigint): bigint
\`\`\`
Estimates the number of oracle prices required for a withdrawal operation. Returns \`3n + swapsCount\`.
\`\`\`typescript
const priceCount = estimateWithdrawalOraclePriceCount(1n);
console.log(priceCount); // 4n
\`\`\`
### estimateOrderOraclePriceCount
\`\`\`typescript
estimateOrderOraclePriceCount(swapsCount: number): bigint
\`\`\`
Estimates the number of oracle prices required for an order operation. Returns \`3n + swapsCount\`.
\`\`\`typescript
const priceCount = estimateOrderOraclePriceCount(0);
console.log(priceCount); // 3n
\`\`\`
### estimateShiftOraclePriceCount
\`\`\`typescript
estimateShiftOraclePriceCount(): bigint
\`\`\`
Estimates the number of oracle prices required for a shift operation. Always returns \`4n\`.
\`\`\`typescript
const priceCount = estimateShiftOraclePriceCount();
console.log(priceCount); // 4n
\`\`\`
### estimateGlvDepositOraclePriceCount
\`\`\`typescript
estimateGlvDepositOraclePriceCount(marketCount: bigint, swapsCount?: bigint): bigint
\`\`\`
Estimates the number of oracle prices required for a GLV deposit operation. Returns \`2n + marketCount + swapsCount\`. \`swapsCount\` defaults to \`0n\`.
\`\`\`typescript
const priceCount = estimateGlvDepositOraclePriceCount(3n, 1n);
console.log(priceCount); // 6n
\`\`\`
### estimateGlvWithdrawalOraclePriceCount
\`\`\`typescript
estimateGlvWithdrawalOraclePriceCount(marketCount: bigint, swapsCount?: bigint): bigint
\`\`\`
Estimates the number of oracle prices required for a GLV withdrawal operation. Returns \`2n + marketCount + swapsCount\`. \`swapsCount\` defaults to \`0n\`.
\`\`\`typescript
const priceCount = estimateGlvWithdrawalOraclePriceCount(2n);
console.log(priceCount); // 4n
\`\`\`
---
## executionFee
This module provides utilities for calculating execution fees and estimating gas limits for various GMX protocol operations. It handles fee calculations for orders, deposits, withdrawals, and batch operations while considering network-specific gas costs and limits.
## Methods
The \`executionFee\` module exports two categories of functions: \*\*fee calculation\*\* functions that convert a gas limit into a token amount the user must pay, and \*\*gas estimation\*\* functions that compute the gas limit for each operation type.
### Fee calculation
#### getExecutionFee
\`\`\`typescript
getExecutionFee(
chainId: number,
gasLimits: GasLimitsConfig,
tokensData: TokensData,
estimatedGasLimit: bigint,
gasPrice: bigint,
oraclePriceCount: bigint,
numberOfParts?: number
): ExecutionFee | undefined
\`\`\`
Converts an estimated gas limit into a full \`ExecutionFee\` object. Internally it applies the \`estimatedFeeMultiplierFactor\` from \`GasLimitsConfig\` and adds per-oracle-price overhead before multiplying by \`gasPrice\`. Returns \`undefined\` if the native token is not found in \`tokensData\`.
The returned \`ExecutionFee\` contains:
| Field | Type | Description |
| ---------------- | --------- | ----------------------------------------------------------- |
| \`feeUsd\` | \`bigint\` | Total fee in USD (30-decimal precision) |
| \`feeTokenAmount\` | \`bigint\` | Total fee in native token units |
| \`feeToken\` | \`Token\` | Native token data |
| \`gasLimit\` | \`bigint\` | Adjusted gas limit (after multiplier) |
| \`isFeeHigh\` | \`boolean\` | \`true\` when fee exceeds the chain's high-fee threshold |
| \`isFeeVeryHigh\` | \`boolean\` | \`true\` when fee exceeds the chain's excessive-fee threshold |
\`\`\`typescript
const executionFee = getExecutionFee(
42161, // Arbitrum
gasLimits,
tokensData,
500000n, // estimated gas for the operation
1000000000n, // gas price in wei
2n // number of oracle prices required
);
if (executionFee) {
console.log("Fee USD:", executionFee.feeUsd);
console.log("Fee token amount:", executionFee.feeTokenAmount);
if (executionFee.isFeeVeryHigh) {
console.warn("Execution fee is excessively high");
} else if (executionFee.isFeeHigh) {
console.warn("Execution fee is high");
}
}
\`\`\`
#### estimateRelayerGasLimit
\`\`\`typescript
estimateRelayerGasLimit(params: {
gasLimits: GasLimitsConfig;
tokenPermitsCount: number;
feeSwapsCount: number;
feeExternalCallsGasLimit: bigint;
oraclePriceCount: number;
transactionPayloadGasLimit: bigint;
l1GasLimit: bigint;
}): bigint
\`\`\`
Estimates the total gas limit for a relayer-submitted Express Trading transaction. The total is the sum of: per-permit overhead, per-fee-swap overhead, per-oracle-price overhead, external calls gas limit, the transaction payload gas limit, and the L1 gas buffer.
\`\`\`typescript
const gasLimit = estimateRelayerGasLimit({
gasLimits,
tokenPermitsCount: 1,
feeSwapsCount: 1, // 1 swap needed to convert payment token to relay fee token
feeExternalCallsGasLimit: 0n,
oraclePriceCount: 3,
transactionPayloadGasLimit: 200000n,
l1GasLimit: 0n, // non-zero only for L1-anchored chains
});
\`\`\`
#### approximateL1GasBuffer
\`\`\`typescript
approximateL1GasBuffer(params: {
l1Reference: L1ExpressOrderGasReference;
sizeOfData: bigint;
}): bigint
\`\`\`
Estimates the L1 gas buffer for an Express Trading transaction by logarithmically scaling the reference gas limit based on data size. The formula is:
\`\`\`
result = round(l1Reference.gasLimit × log(sizeOfData) / log(l1Reference.sizeOfData))
\`\`\`
Falls back to \`l1Reference.gasLimit\` if the logarithm produces a non-finite value (for example, when \`sizeOfData\` is \`0n\`).
\`\`\`typescript
const l1GasBuffer = approximateL1GasBuffer({
l1Reference: {
gasLimit: 100000n,
sizeOfData: 1000n, // reference data size in bytes
},
sizeOfData: 1500n, // actual data size for this transaction
});
\`\`\`
#### estimateBatchGasLimit
\`\`\`typescript
estimateBatchGasLimit(params: {
gasLimits: GasLimitsConfig;
createOrdersCount: number;
updateOrdersCount: number;
cancelOrdersCount: number;
externalCallsGasLimit: bigint;
isGmxAccount: boolean;
}): bigint
\`\`\`
Estimates the gas limit for a batch of order operations. Adds a \`gmxAccountCollateralGasLimit\` overhead when \`isGmxAccount\` is \`true\`.
\`\`\`typescript
const batchGasLimit = estimateBatchGasLimit({
gasLimits,
createOrdersCount: 2,
updateOrdersCount: 0,
cancelOrdersCount: 1,
externalCallsGasLimit: 0n,
isGmxAccount: false,
});
\`\`\`
#### estimateBatchMinGasPaymentTokenAmount
\`\`\`typescript
estimateBatchMinGasPaymentTokenAmount(params: {
chainId: ContractsChainId;
gasPaymentToken: TokenData;
isGmxAccount: boolean;
relayFeeToken: TokenData;
gasPrice: bigint;
gasLimits: GasLimitsConfig;
l1Reference: L1ExpressOrderGasReference | undefined;
tokensData: TokensData;
createOrdersCount?: number; // default: 1
updateOrdersCount?: number; // default: 0
cancelOrdersCount?: number; // default: 0
executionFeeAmount?: bigint; // pass to override the estimated execution fee
}): bigint
\`\`\`
Estimates the minimum amount of \`gasPaymentToken\` the user must hold to cover a batch Express Trading transaction — including the relayer fee, batch gas limit, and execution fee. Converts the total from the relay fee token denomination to the payment token denomination.
:::note
\`chainId\` must be a \`ContractsChainId\` (a supported chain ID literal), not a generic \`number\`.
:::
\`\`\`typescript
const minPayment = estimateBatchMinGasPaymentTokenAmount({
chainId: 42161, // ContractsChainId for Arbitrum
gasPaymentToken: usdcToken,
isGmxAccount: false,
relayFeeToken: wethToken,
gasPrice: 1000000000n,
gasLimits,
l1Reference: undefined,
tokensData,
createOrdersCount: 2,
updateOrdersCount: 0,
cancelOrdersCount: 1,
});
\`\`\`
### Gas estimation
These functions mirror their on-chain counterparts (\`Copy from contract\` in the source). They compute the gas limit for specific operation types by combining the base limit from \`GasLimitsConfig\` with per-swap and callback overheads.
#### estimateExecuteIncreaseOrderGasLimit
\`\`\`typescript
estimateExecuteIncreaseOrderGasLimit(
gasLimits: GasLimitsConfig,
order: { swapsCount?: number; callbackGasLimit?: bigint }
): bigint
\`\`\`
Estimates gas for a Market Increase or Limit Increase order. \`swapsCount\` defaults to \`0\`.
\`\`\`typescript
const gasLimit = estimateExecuteIncreaseOrderGasLimit(gasLimits, {
swapsCount: 1, // number of token swaps along the collateral path
callbackGasLimit: 0n,
});
\`\`\`
#### estimateExecuteDecreaseOrderGasLimit
\`\`\`typescript
estimateExecuteDecreaseOrderGasLimit(
gasLimits: GasLimitsConfig,
order: {
swapsCount: number;
callbackGasLimit?: bigint;
decreaseSwapType?: DecreasePositionSwapType;
}
): bigint
\`\`\`
Estimates gas for a Market Decrease, Limit Decrease, Stop-Loss, or Take-Profit order. When \`decreaseSwapType\` is not \`NoSwap\`, one additional swap is added to \`swapsCount\`.
\`\`\`typescript
const gasLimit = estimateExecuteDecreaseOrderGasLimit(gasLimits, {
swapsCount: 0,
decreaseSwapType: DecreasePositionSwapType.SwapCollateralTokenToPnlToken,
});
\`\`\`
#### estimateExecuteSwapOrderGasLimit
\`\`\`typescript
estimateExecuteSwapOrderGasLimit(
gasLimits: GasLimitsConfig,
order: { swapsCount: number; callbackGasLimit?: bigint }
): bigint
\`\`\`
Estimates gas for a Market Swap or Limit Swap order.
\`\`\`typescript
const gasLimit = estimateExecuteSwapOrderGasLimit(gasLimits, {
swapsCount: 2, // number of market hops in the swap path
callbackGasLimit: 0n,
});
\`\`\`
#### estimateExecuteDepositGasLimit
\`\`\`typescript
estimateExecuteDepositGasLimit(
gasLimits: GasLimitsConfig,
deposit: { swapsCount?: number | bigint; callbackGasLimit?: bigint }
): bigint
\`\`\`
Estimates gas for a GM token deposit (not a position increase). \`swapsCount\` is the total number of input-token swaps required before the deposit — for example, \`2\` when depositing USDC into an ETH/USDC market that accepts only the long and short tokens individually.
:::note
This function is for GM pool deposits only. For position increases (Market Increase / Limit Increase), use \`estimateExecuteIncreaseOrderGasLimit\`.
:::
\`\`\`typescript
const gasLimit = estimateExecuteDepositGasLimit(gasLimits, {
swapsCount: 2, // total token swaps needed before the deposit
callbackGasLimit: 0n,
});
\`\`\`
#### estimateExecuteGlvDepositGasLimit
\`\`\`typescript
estimateExecuteGlvDepositGasLimit(
gasLimits: GasLimitsConfig,
params: {
isMarketTokenDeposit: boolean;
marketsCount: bigint;
swapsCount: bigint;
}
): bigint
\`\`\`
Estimates gas for a GLV deposit. When \`isMarketTokenDeposit\` is \`true\`, the user deposits GM tokens directly and no deposit or swap gas is added — only the GLV base gas and per-market overhead. When \`false\`, the base GM deposit gas and swap gas are added on top.
\`\`\`typescript
// Deposit raw tokens (not GM tokens) into a GLV vault across 5 markets with 1 input swap
const gasLimit = estimateExecuteGlvDepositGasLimit(gasLimits, {
isMarketTokenDeposit: false,
marketsCount: 5n,
swapsCount: 1n,
});
\`\`\`
#### estimateExecuteGlvWithdrawalGasLimit
\`\`\`typescript
estimateExecuteGlvWithdrawalGasLimit(
gasLimits: GasLimitsConfig,
params: { marketsCount: bigint; swapsCount: bigint }
): bigint
\`\`\`
Estimates gas for a GLV withdrawal. Both \`marketsCount\` and \`swapsCount\` affect the result.
\`\`\`typescript
const gasLimit = estimateExecuteGlvWithdrawalGasLimit(gasLimits, {
marketsCount: 5n,
swapsCount: 1n,
});
\`\`\`
#### estimateExecuteWithdrawalGasLimit
\`\`\`typescript
estimateExecuteWithdrawalGasLimit(
gasLimits: GasLimitsConfig,
withdrawal: { callbackGasLimit?: bigint; swapsCount?: bigint }
): bigint
\`\`\`
Estimates gas for a GM token withdrawal (not a position decrease). \`swapsCount\` defaults to \`0n\`.
:::note
This function is for GM pool withdrawals only. For position decreases, use \`estimateExecuteDecreaseOrderGasLimit\`.
:::
\`\`\`typescript
const gasLimit = estimateExecuteWithdrawalGasLimit(gasLimits, {
swapsCount: 1n, // token swaps performed after the withdrawal
callbackGasLimit: 0n,
});
\`\`\`
#### estimateExecuteShiftGasLimit
\`\`\`typescript
estimateExecuteShiftGasLimit(
gasLimits: GasLimitsConfig,
shift: { callbackGasLimit?: bigint }
): bigint
\`\`\`
Estimates gas for a GM pool shift (moving liquidity from one market to another without withdrawing).
\`\`\`typescript
const gasLimit = estimateExecuteShiftGasLimit(gasLimits, {
callbackGasLimit: 0n,
});
\`\`\`
---
## fees
This module provides utilities for calculating various fees in the GMX protocol, including swap fees, position fees, funding fees, borrowing fees, and price impact calculations. It also includes helper functions for working with fee items and swap statistics.
## Methods
The \`fees\` module exports fee calculation functions for three categories of on-chain costs: swap fees, position fees (including referral discounts), and holding costs (funding fee and borrow fee). It also exports helper utilities for working with \`FeeItem\` objects.
### Swap and position fees
#### getSwapFee
\`\`\`typescript
getSwapFee(
marketInfo: MarketInfo,
swapAmount: bigint,
balanceWasImproved: boolean,
swapPricingType: SwapPricingType
): bigint
\`\`\`
Calculates the swap fee for a token amount. The fee factor depends on \`swapPricingType\`:
- \`SwapPricingType.AtomicSwap\` — uses \`atomicSwapFeeFactor\`
- \`SwapPricingType.Withdrawal\` — uses \`withdrawalFeeFactorBalanceWasImproved\` or \`withdrawalFeeFactorBalanceWasNotImproved\`
- All other types (standard swaps) — uses \`swapFeeFactorForBalanceWasImproved\` or \`swapFeeFactorForBalanceWasNotImproved\`
:::note
The fourth parameter is \`swapPricingType: SwapPricingType\` (an enum), not \`isAtomicSwap: boolean\` as earlier documentation stated.
:::
\`\`\`typescript
const swapFee = getSwapFee(
marketInfo,
1000n \* 10n \*\* 18n, // 1000 USDC (18 decimals)
true, // swap improves pool balance
SwapPricingType.Swap
);
\`\`\`
#### getPositionFee
\`\`\`typescript
getPositionFee(
marketInfo: MarketInfo,
sizeDeltaUsd: bigint,
balanceWasImproved: boolean,
referralInfo: { totalRebateFactor: bigint; discountFactor: bigint } | undefined,
uiFeeFactor?: bigint
): {
positionFeeUsd: bigint;
discountUsd: bigint;
totalRebateUsd: bigint;
uiFeeUsd: bigint;
}
\`\`\`
Calculates the position fee for a size change. When \`referralInfo\` is provided, the rebate and discount are calculated and deducted from \`positionFeeUsd\`.
\`\`\`typescript
const { positionFeeUsd, discountUsd, totalRebateUsd, uiFeeUsd } = getPositionFee(
marketInfo,
10000n \* 10n \*\* 30n, // $10,000 size delta (30-decimal precision)
false,
{ totalRebateFactor: 5000n, discountFactor: 3000n }, // rebate factors in basis points (PRECISION-scaled)
100n // UI fee factor
);
\`\`\`
### Funding fee
#### getFundingFactorPerPeriod
\`\`\`typescript
getFundingFactorPerPeriod(marketInfo: MarketInfo, isLong: boolean, periodInSeconds: bigint): bigint
\`\`\`
Returns the funding factor (PRECISION-scaled) accumulated over \`periodInSeconds\`. Negative values mean the position pays funding; positive values mean it receives funding.
The paying side is determined by \`marketInfo.longsPayShorts\`. The receiving side's factor is scaled by \`payingInterest / receivingInterest\` to maintain balance.
\`\`\`typescript
const factor = getFundingFactorPerPeriod(marketInfo, true, 3600n); // 1 hour in seconds (bigint)
// Negative: longs are paying funding this hour
\`\`\`
#### getFundingFeeRateUsd
\`\`\`typescript
getFundingFeeRateUsd(marketInfo: MarketInfo, isLong: boolean, sizeInUsd: bigint, periodInSeconds: bigint): bigint
\`\`\`
Returns the funding fee in USD for a position of \`sizeInUsd\` over \`periodInSeconds\`. Applies \`getFundingFactorPerPeriod\` to the size.
\`\`\`typescript
const fundingFeeUsd = getFundingFeeRateUsd(
marketInfo,
true,
10000n \* 10n \*\* 30n, // $10,000 position
86400n // 24 hours (bigint)
);
\`\`\`
### Borrow fee
#### getBorrowingFactorPerPeriod
\`\`\`typescript
getBorrowingFactorPerPeriod(marketInfo: MarketInfo, isLong: boolean, periodInSeconds: bigint): bigint
\`\`\`
Returns the borrow factor (PRECISION-scaled) accumulated over \`periodInSeconds\`. Uses \`borrowingFactorPerSecondForLongs\` or \`borrowingFactorPerSecondForShorts\` from \`marketInfo\`.
\`\`\`typescript
const borrowFactor = getBorrowingFactorPerPeriod(marketInfo, false, 3600n); // short, 1 hour
\`\`\`
#### getBorrowingFeeRateUsd
\`\`\`typescript
getBorrowingFeeRateUsd(marketInfo: MarketInfo, isLong: boolean, sizeInUsd: bigint, periodInSeconds: bigint): bigint
\`\`\`
Returns the borrow fee in USD for a position of \`sizeInUsd\` over \`periodInSeconds\`.
\`\`\`typescript
const borrowFeeUsd = getBorrowingFeeRateUsd(
marketInfo,
false,
10000n \* 10n \*\* 30n, // $10,000 position
86400n // 24 hours
);
\`\`\`
### FeeItem helpers
#### getIsHighPriceImpact
\`\`\`typescript
getIsHighPriceImpact(positionPriceImpact?: FeeItem, swapPriceImpact?: FeeItem): boolean
\`\`\`
Returns \`true\` when the combined price impact is negative and its absolute basis-point value is at or above \`HIGH\_PRICE\_IMPACT\_BPS\` (80 bps = 0.8%).
\`\`\`typescript
const isHigh = getIsHighPriceImpact(positionPriceImpactFeeItem, swapPriceImpactFeeItem);
if (isHigh) {
// warn the user before submitting
}
\`\`\`
#### getFeeItem
\`\`\`typescript
getFeeItem(
feeDeltaUsd?: bigint,
basis?: bigint,
opts?: { shouldRoundUp?: boolean }
): FeeItem | undefined
\`\`\`
Creates a \`FeeItem\` from a USD delta and a USD basis. Returns \`undefined\` when \`feeDeltaUsd\` is \`undefined\`. When \`basis\` is \`undefined\` or \`0\`, \`bps\` and \`precisePercentage\` are set to \`0n\`.
\`\`\`typescript
const feeItem = getFeeItem(
-100n \* 10n \*\* 30n, // -$100 impact
10000n \* 10n \*\* 30n // $10,000 basis
);
// feeItem.bps ≈ -100n (1%)
// feeItem.precisePercentage is PRECISION-scaled
\`\`\`
#### getTotalFeeItem
\`\`\`typescript
getTotalFeeItem(feeItems: (FeeItem | undefined)\[\]): FeeItem
\`\`\`
Sums a list of \`FeeItem\` objects. \`undefined\` entries are ignored. Always returns a \`FeeItem\` (never \`undefined\`), with all fields starting at \`0n\`.
\`\`\`typescript
const total = getTotalFeeItem(\[positionFeeItem, swapFeeItem, undefined\]);
// total.deltaUsd = sum of all non-undefined deltaUsd values
\`\`\`
#### getTotalSwapVolumeFromSwapStats
\`\`\`typescript
getTotalSwapVolumeFromSwapStats(swapSteps?: SwapStats\[\]): bigint
\`\`\`
Returns the sum of \`usdIn\` across all swap steps. Returns \`0n\` when \`swapSteps\` is \`undefined\` or empty.
\`\`\`typescript
const totalVolume = getTotalSwapVolumeFromSwapStats(swapPath);
// totalVolume: sum of usdIn for each hop in the swap path
\`\`\`
---
## getNaiveEstimatedGasBySwapCount
This module provides a utility function for calculating estimated gas costs based on the number of swaps in a transaction.
## Methods
This module exports a single function, available from \`@gmx-io/sdk/utils/fees\`.
### getNaiveEstimatedGasBySwapCount
\`\`\`typescript
getNaiveEstimatedGasBySwapCount(
singleSwap: GasLimitsConfig\["singleSwap"\],
swapsCount: number
): bigint
\`\`\`
Returns \`singleSwap × swapsCount\`. Use this to estimate the swap portion of an order's gas limit when building a quick pre-check or a UI estimate. Pass \`gasLimits.singleSwap\` as the first argument.
\`\`\`typescript
// 2-hop swap path: USDC → WETH → WBTC
const swapGas = getNaiveEstimatedGasBySwapCount(gasLimits.singleSwap, 2);
// swapGas = gasLimits.singleSwap \* 2n
\`\`\`
---
## priceImpact
This module provides utilities for calculating price impact in GMX protocol operations, including position trades and swaps. It handles price impact calculations based on pool imbalances, virtual inventories, and various impact factors.
## Methods
This module exports functions for computing price impact in position and swap operations. Price impact measures how a trade shifts pool balance — moves that improve balance receive positive impact (a rebate), while moves that worsen balance receive negative impact (a cost). All USD values use 30-decimal precision (\`USD\_DECIMALS = 30\`), meaning \`1\_000000000000000000000000000000n\` represents $1.
:::note
All functions in this module are exported from \`@gmx-io/sdk/utils/fees\`. Import them individually as shown in each example.
:::
### getPriceImpactByAcceptablePrice
\`\`\`typescript
getPriceImpactByAcceptablePrice(p: {
sizeDeltaUsd: bigint;
acceptablePrice: bigint;
indexPrice: bigint;
isLong: boolean;
isIncrease: boolean;
}): {
priceImpactDeltaUsd: bigint;
priceImpactDeltaAmount: bigint;
priceDelta: bigint;
acceptablePriceDeltaBps: bigint;
}
\`\`\`
Computes the price impact implied by the difference between your acceptable price and the current index price. Use this to show users the cost of their slippage tolerance before order submission.
| Parameter | Type | Description |
| ----------------- | --------- | ------------------------------------------------------------ |
| \`sizeDeltaUsd\` | \`bigint\` | Trade size in USD (30-decimal precision) |
| \`acceptablePrice\` | \`bigint\` | Worst price the user accepts (30-decimal precision) |
| \`indexPrice\` | \`bigint\` | Current mark price of the index token (30-decimal precision) |
| \`isLong\` | \`boolean\` | \`true\` for long positions |
| \`isIncrease\` | \`boolean\` | \`true\` when opening or increasing a position |
\`\`\`typescript
// ETH long increase: $1 size, acceptable price $1.95, mark price $2.00
const priceImpact = getPriceImpactByAcceptablePrice({
sizeDeltaUsd: 1\_000000000000000000000000000000n, // $1
acceptablePrice: 1\_950000000000000000000000000000n, // $1.95
indexPrice: 2\_000000000000000000000000000000n, // $2.00
isLong: true,
isIncrease: true,
});
console.log(priceImpact.priceImpactDeltaUsd); // negative — user pays for slippage
console.log(priceImpact.acceptablePriceDeltaBps); // basis-point difference from mark price
\`\`\`
### applySwapImpactWithCap
\`\`\`typescript
applySwapImpactWithCap(
marketInfo: MarketInfo,
token: TokenData,
priceImpactDeltaUsd: bigint
): { impactDeltaAmount: bigint; cappedDiffUsd: bigint }
\`\`\`
Converts a USD price impact value to a token amount for swap operations, capping positive impact at the available swap impact pool balance. Positive impact is paid out from the pool; negative impact is collected from the user.
:::warning
Throws if \`token\` is not a collateral token of the given market. Always pass a token that belongs to the market's long or short pool.
:::
| Parameter | Type | Description |
| --------------------- | ------------ | ---------------------------------------------------------------------------------- |
| \`marketInfo\` | \`MarketInfo\` | Market containing the swap impact pool |
| \`token\` | \`TokenData\` | Collateral token being swapped in or out |
| \`priceImpactDeltaUsd\` | \`bigint\` | Raw price impact in USD (30-decimal precision); positive = rebate, negative = cost |
\`\`\`typescript
// Apply $0.50 positive impact, capped by the pool's available balance
const result = applySwapImpactWithCap(
marketInfo,
usdcTokenData,
500000000000000000000000000000n // $0.50 impact
);
console.log(result.impactDeltaAmount); // token amount credited or debited
console.log(result.cappedDiffUsd); // USD value lost to pool cap (if any)
\`\`\`
### getCappedPositionImpactUsd
\`\`\`typescript
getCappedPositionImpactUsd(
marketInfo: MarketInfo,
sizeDeltaUsd: bigint,
isLong: boolean,
isIncrease: boolean,
opts?: { fallbackToZero?: boolean; shouldCapNegativeImpact?: boolean }
): { priceImpactDeltaUsd: bigint; balanceWasImproved: boolean }
\`\`\`
Computes position price impact bounded by the market's maximum impact factor. This is the main function to use when you need to show a user their estimated price impact before placing a position order.
| Parameter | Type | Description |
| ------------------------------ | ------------ | ----------------------------------------------------------- |
| \`marketInfo\` | \`MarketInfo\` | Target market |
| \`sizeDeltaUsd\` | \`bigint\` | Absolute position size change in USD (30-decimal precision) |
| \`isLong\` | \`boolean\` | \`true\` for long positions |
| \`isIncrease\` | \`boolean\` | \`true\` when opening or increasing; \`false\` when decreasing |
| \`opts.fallbackToZero\` | \`boolean\` | Return zero instead of throwing when pool goes negative |
| \`opts.shouldCapNegativeImpact\` | \`boolean\` | Also cap negative impact by the max impact factor |
\`\`\`typescript
// Estimate impact for a $1 long increase
const impact = getCappedPositionImpactUsd(
marketInfo,
1\_000000000000000000000000000000n, // $1
true, // long
true, // increase
{ fallbackToZero: true }
);
console.log(impact.priceImpactDeltaUsd); // negative = cost, positive = rebate
console.log(impact.balanceWasImproved); // true when trade improves pool balance
\`\`\`
### capPositionImpactUsdByMaxImpactPool
\`\`\`typescript
capPositionImpactUsdByMaxImpactPool(
marketInfo: MarketInfo,
positionImpactDeltaUsd: bigint
): bigint
\`\`\`
Caps a positive position impact at the value of tokens available in the position impact pool. Negative values pass through unchanged. Call this before distributing a positive impact rebate to ensure the pool can cover it.
| Parameter | Type | Description |
| ------------------------ | ------------ | ------------------------------------------------- |
| \`marketInfo\` | \`MarketInfo\` | Market containing the position impact pool |
| \`positionImpactDeltaUsd\` | \`bigint\` | Raw positive impact in USD (30-decimal precision) |
\`\`\`typescript
const cappedImpact = capPositionImpactUsdByMaxImpactPool(
marketInfo,
750000000000000000000000000000n // $0.75 raw impact
);
console.log(cappedImpact); // at most the pool's available USD value
\`\`\`
### capPositionImpactUsdByMaxPriceImpactFactor
\`\`\`typescript
capPositionImpactUsdByMaxPriceImpactFactor(
marketInfo: MarketInfo,
sizeDeltaUsd: bigint,
positionImpactDeltaUsd: bigint
): bigint
\`\`\`
Caps position impact (positive or negative) at the market's configured maximum impact factor multiplied by the trade size. The effective cap is \`abs(sizeDeltaUsd) × maxImpactFactor\`.
| Parameter | Type | Description |
| ------------------------ | ------------ | -------------------------------------------------- |
| \`marketInfo\` | \`MarketInfo\` | Market with configured max impact factors |
| \`sizeDeltaUsd\` | \`bigint\` | Trade size in USD (signed; negative for decreases) |
| \`positionImpactDeltaUsd\` | \`bigint\` | Raw impact in USD to cap |
\`\`\`typescript
const cappedImpact = capPositionImpactUsdByMaxPriceImpactFactor(
marketInfo,
1\_000000000000000000000000000000n, // $1 trade size
-500000000000000000000000000000n // $0.50 raw negative impact
);
console.log(cappedImpact); // bounded by maxNegativeImpactFactor × $1
\`\`\`
### getMaxPositionImpactFactors
\`\`\`typescript
getMaxPositionImpactFactors(
marketInfo: MarketInfo
): { maxPositiveImpactFactor: bigint; maxNegativeImpactFactor: bigint }
\`\`\`
Returns the maximum position impact factors for a market. The positive cap is set to \`min(maxPositiveImpactFactorPositive, maxNegativeImpactFactor)\` to prevent excessive rebates.
| Parameter | Type | Description |
| ------------ | ------------ | ---------------------------------- |
| \`marketInfo\` | \`MarketInfo\` | Market to read impact factors from |
\`\`\`typescript
const { maxPositiveImpactFactor, maxNegativeImpactFactor } = getMaxPositionImpactFactors(marketInfo);
// Factors are scaled to 30 decimals — divide by 1e30 to get the decimal fraction
console.log(maxPositiveImpactFactor); // bigint, 30-decimal precision
console.log(maxNegativeImpactFactor);
\`\`\`
### getPriceImpactForPosition
\`\`\`typescript
getPriceImpactForPosition(
marketInfo: MarketInfo,
sizeDeltaUsd: bigint,
isLong: boolean,
opts?: { fallbackToZero?: boolean }
): { priceImpactDeltaUsd: bigint; balanceWasImproved: boolean }
\`\`\`
Computes the uncapped price impact for a position trade based on the change in open interest. When the market has a non-zero virtual inventory, the function uses the more conservative of the real and virtual impact values. This is a building block used by \`getCappedPositionImpactUsd\`.
| Parameter | Type | Description |
| --------------------- | ------------ | ------------------------------------------------------------------ |
| \`marketInfo\` | \`MarketInfo\` | Market with open interest and virtual inventory data |
| \`sizeDeltaUsd\` | \`bigint\` | Signed size delta in USD — positive for longs, negative for shorts |
| \`isLong\` | \`boolean\` | \`true\` for long positions |
| \`opts.fallbackToZero\` | \`boolean\` | Return zero instead of throwing when pool goes negative |
\`\`\`typescript
const impact = getPriceImpactForPosition(
marketInfo,
1\_000000000000000000000000000000n, // $1 long increase
true,
{ fallbackToZero: true }
);
console.log(impact.priceImpactDeltaUsd); // uncapped impact in USD
console.log(impact.balanceWasImproved);
\`\`\`
### getProportionalPendingImpactValues
\`\`\`typescript
getProportionalPendingImpactValues(p: {
sizeInUsd: bigint;
pendingImpactAmount: bigint;
sizeDeltaUsd: bigint;
indexToken: TokenData;
}): {
proportionalPendingImpactDeltaAmount: bigint;
proportionalPendingImpactDeltaUsd: bigint;
}
\`\`\`
Splits a pending price impact proportionally when partially closing a position. Use this when a user closes part of a position that has an accrued impact amount.
| Parameter | Type | Description |
| --------------------- | ----------- | ------------------------------------------------ |
| \`sizeInUsd\` | \`bigint\` | Full position size in USD (30-decimal precision) |
| \`pendingImpactAmount\` | \`bigint\` | Accrued pending impact in index tokens |
| \`sizeDeltaUsd\` | \`bigint\` | Size being closed in USD |
| \`indexToken\` | \`TokenData\` | Index token with price data for USD conversion |
\`\`\`typescript
// Close $1 of a $5 position with 0.1 ETH pending impact
const impact = getProportionalPendingImpactValues({
sizeInUsd: 5\_000000000000000000000000000000n, // $5 full position
pendingImpactAmount: 100000000000000000n, // 0.1 ETH
sizeDeltaUsd: 1\_000000000000000000000000000000n, // $1 being closed
indexToken: ethTokenData,
});
console.log(impact.proportionalPendingImpactDeltaAmount); // token amount for this close
console.log(impact.proportionalPendingImpactDeltaUsd); // USD value of that amount
\`\`\`
### getPriceImpactForSwap
\`\`\`typescript
getPriceImpactForSwap(
marketInfo: MarketInfo,
tokenA: TokenData,
tokenB: TokenData,
usdDeltaTokenA: bigint,
usdDeltaTokenB: bigint,
opts?: { fallbackToZero?: boolean }
): { priceImpactDeltaUsd: bigint; balanceWasImproved: boolean }
\`\`\`
Computes the uncapped price impact for a swap between two tokens in the same market pool. When the market has non-zero virtual inventory, the function uses the more conservative of the real and virtual impact values.
:::warning
Throws if either token is not a collateral token of the given market, or if both tokens map to the same pool side on a non-same-collateral market.
:::
| Parameter | Type | Description |
| --------------------- | ------------ | ----------------------------------------------------------------------------- |
| \`marketInfo\` | \`MarketInfo\` | Market containing both tokens |
| \`tokenA\` | \`TokenData\` | First swap token |
| \`tokenB\` | \`TokenData\` | Second swap token |
| \`usdDeltaTokenA\` | \`bigint\` | USD added to the pool for token A (positive = deposit, negative = withdrawal) |
| \`usdDeltaTokenB\` | \`bigint\` | USD added to the pool for token B |
| \`opts.fallbackToZero\` | \`boolean\` | Return zero instead of throwing on pool underflow |
\`\`\`typescript
// Swap $1 USDC in, $1 WETH out
const impact = getPriceImpactForSwap(
marketInfo,
usdcTokenData,
wethTokenData,
1\_000000000000000000000000000000n, // +$1 USDC into pool
-1\_000000000000000000000000000000n, // -$1 WETH from pool
{ fallbackToZero: true }
);
console.log(impact.priceImpactDeltaUsd); // negative = user pays, positive = user receives
console.log(impact.balanceWasImproved);
\`\`\`
### getNextPoolAmountsParams
\`\`\`typescript
getNextPoolAmountsParams(p: {
longToken: TokenData;
shortToken: TokenData;
longPoolAmount: bigint;
shortPoolAmount: bigint;
longDeltaUsd: bigint;
shortDeltaUsd: bigint;
}): {
longPoolUsd: bigint;
shortPoolUsd: bigint;
nextLongPoolUsd: bigint;
nextShortPoolUsd: bigint;
}
\`\`\`
Converts current pool token amounts to USD and applies deltas to produce the next-state pool values. This is a helper used by \`getPriceImpactForSwap\` and \`getPriceImpactUsd\`.
| Parameter | Type | Description |
| ----------------- | ----------- | -------------------------------------------------- |
| \`longToken\` | \`TokenData\` | Long-side collateral token with price data |
| \`shortToken\` | \`TokenData\` | Short-side collateral token with price data |
| \`longPoolAmount\` | \`bigint\` | Current long pool amount in token units |
| \`shortPoolAmount\` | \`bigint\` | Current short pool amount in token units |
| \`longDeltaUsd\` | \`bigint\` | USD change to the long pool (30-decimal precision) |
| \`shortDeltaUsd\` | \`bigint\` | USD change to the short pool |
\`\`\`typescript
const poolParams = getNextPoolAmountsParams({
longToken: wethTokenData,
shortToken: usdcTokenData,
longPoolAmount: 1\_000000000000000000n, // 1 WETH
shortPoolAmount: 2\_000000000000000000n, // 2 USDC (6-decimal token, adjust per token.decimals)
longDeltaUsd: 500000000000000000000000000000n, // +$0.50 into long pool
shortDeltaUsd: -250000000000000000000000000000n, // -$0.25 from short pool
});
console.log(poolParams.longPoolUsd); // current long pool in USD
console.log(poolParams.nextLongPoolUsd); // long pool after delta
\`\`\`
### getPriceImpactUsd
\`\`\`typescript
getPriceImpactUsd(p: {
currentLongUsd: bigint;
currentShortUsd: bigint;
nextLongUsd: bigint;
nextShortUsd: bigint;
factorPositive: bigint;
factorNegative: bigint;
exponentFactorPositive: bigint;
exponentFactorNegative: bigint;
fallbackToZero?: boolean;
}): { priceImpactDeltaUsd: bigint; balanceWasImproved: boolean }
\`\`\`
Core price impact calculation. Compares the current and next pool state to determine whether the trade improves or worsens balance, then applies the appropriate factor and exponent. Uses separate exponent factors for positive and negative impact paths.
See the \[GMX synthetics SwapPricingUtils contract\](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/pricing/SwapPricingUtils.sol) for the matching on-chain implementation.
| Parameter | Type | Description |
| ------------------------ | --------- | ------------------------------------------------------------- |
| \`currentLongUsd\` | \`bigint\` | Current long-side USD value |
| \`currentShortUsd\` | \`bigint\` | Current short-side USD value |
| \`nextLongUsd\` | \`bigint\` | Post-trade long-side USD value |
| \`nextShortUsd\` | \`bigint\` | Post-trade short-side USD value |
| \`factorPositive\` | \`bigint\` | Impact factor when balance improves (30-decimal fraction) |
| \`factorNegative\` | \`bigint\` | Impact factor when balance worsens |
| \`exponentFactorPositive\` | \`bigint\` | Exponent applied to positive-impact calculations (30-decimal) |
| \`exponentFactorNegative\` | \`bigint\` | Exponent applied to negative-impact calculations |
| \`fallbackToZero\` | \`boolean\` | Return zero instead of throwing when pool goes negative |
\`\`\`typescript
// Long pool increases from $10 to $11, short stays at $8 — worsens imbalance
const impact = getPriceImpactUsd({
currentLongUsd: 10\_000000000000000000000000000000n, // $10
currentShortUsd: 8\_000000000000000000000000000000n, // $8
nextLongUsd: 11\_000000000000000000000000000000n, // $11
nextShortUsd: 8\_000000000000000000000000000000n, // $8 (unchanged)
factorPositive: 5000000000000000000000000n, // 0.0005% factor
factorNegative: 5000000000000000000000000n, // 0.0005% factor
exponentFactorPositive: 2\_000000000000000000000000000000n, // exponent 2.0
exponentFactorNegative: 2\_000000000000000000000000000000n, // exponent 2.0
fallbackToZero: true,
});
console.log(impact.priceImpactDeltaUsd); // negative — trade worsens pool balance
console.log(impact.balanceWasImproved); // false
\`\`\`
### calculateImpactForSameSideRebalance
\`\`\`typescript
calculateImpactForSameSideRebalance(p: {
currentDiff: bigint;
nextDiff: bigint;
hasPositiveImpact: boolean;
factor: bigint;
exponentFactor: bigint;
}): bigint
\`\`\`
Computes impact when a trade stays on the same side of the pool imbalance — that is, the larger pool stays larger after the trade. Returns positive or negative \`bigint\` depending on \`hasPositiveImpact\`.
See the \[GMX PricingUtils contract\](https://github.com/gmx-io/gmx-synthetics/blob/5fd9991ff2c37ae5f24f03bc9c132730b012ebf2/contracts/pricing/PricingUtils.sol) for the matching on-chain implementation.
| Parameter | Type | Description |
| ------------------- | --------- | ------------------------------------------------------------------------- |
| \`currentDiff\` | \`bigint\` | Absolute difference between current long and short pools (30-decimal USD) |
| \`nextDiff\` | \`bigint\` | Absolute difference between next long and short pools |
| \`hasPositiveImpact\` | \`boolean\` | \`true\` when the trade reduces the imbalance |
| \`factor\` | \`bigint\` | Impact factor (30-decimal fraction) |
| \`exponentFactor\` | \`bigint\` | Exponent (30-decimal) |
\`\`\`typescript
// Imbalance narrows from $2 to $1.50 — positive impact
const impact = calculateImpactForSameSideRebalance({
currentDiff: 2\_000000000000000000000000000000n, // $2 imbalance
nextDiff: 1\_500000000000000000000000000000n, // $1.50 imbalance
hasPositiveImpact: true,
factor: 5000000000000000000000000n, // 0.0005%
exponentFactor: 2\_000000000000000000000000000000n, // 2.0
});
console.log(impact); // positive bigint rebate in USD (30-decimal)
\`\`\`
### calculateImpactForCrossoverRebalance
\`\`\`typescript
calculateImpactForCrossoverRebalance(p: {
currentDiff: bigint;
nextDiff: bigint;
factorPositive: bigint;
factorNegative: bigint;
exponentFactorPositive: bigint;
exponentFactorNegative: bigint;
}): bigint
\`\`\`
Computes impact when a trade crosses over the pool balance point — the previously larger side becomes the smaller side. This is a split calculation: the portion that moves the pool toward balance uses \`factorPositive\`; the portion past the balance point uses \`factorNegative\`.
See the \[GMX PricingUtils contract\](https://github.com/gmx-io/gmx-synthetics/blob/5fd9991ff2c37ae5f24f03bc9c132730b012ebf2/contracts/pricing/PricingUtils.sol) for the matching on-chain implementation.
| Parameter | Type | Description |
| ------------------------ | -------- | ------------------------------------------------------------- |
| \`currentDiff\` | \`bigint\` | Absolute imbalance before the trade (30-decimal USD) |
| \`nextDiff\` | \`bigint\` | Absolute imbalance after the trade (now on the opposite side) |
| \`factorPositive\` | \`bigint\` | Factor applied to the balance-improving portion |
| \`factorNegative\` | \`bigint\` | Factor applied to the balance-worsening portion |
| \`exponentFactorPositive\` | \`bigint\` | Exponent for the positive portion (30-decimal) |
| \`exponentFactorNegative\` | \`bigint\` | Exponent for the negative portion |
\`\`\`typescript
// Imbalance of $1 crosses zero to -$0.50 on the other side
const impact = calculateImpactForCrossoverRebalance({
currentDiff: 1\_000000000000000000000000000000n, // $1 imbalance
nextDiff: 500000000000000000000000000000n, // $0.50 imbalance, opposite side
factorPositive: 5000000000000000000000000n, // 0.0005%
factorNegative: 5000000000000000000000000n, // 0.0005%
exponentFactorPositive: 2\_000000000000000000000000000000n, // 2.0
exponentFactorNegative: 2\_000000000000000000000000000000n, // 2.0
});
console.log(impact); // net impact bigint in USD (30-decimal), may be positive or negative
\`\`\`
### applyImpactFactor
\`\`\`typescript
applyImpactFactor(diff: bigint, factor: bigint, exponent: bigint): bigint
\`\`\`
Low-level helper that raises \`diff\` to the power of \`exponent\` and multiplies by \`factor\`. Both \`diff\` and \`exponent\` are converted to floating-point for the exponentiation, then the result is converted back to a 30-decimal \`bigint\`. Returns \`0n\` if the intermediate value is not finite.
| Parameter | Type | Description |
| ---------- | -------- | ------------------------------------- |
| \`diff\` | \`bigint\` | Pool imbalance value (30-decimal USD) |
| \`factor\` | \`bigint\` | Impact factor (30-decimal fraction) |
| \`exponent\` | \`bigint\` | Exponent (30-decimal) |
\`\`\`typescript
const result = applyImpactFactor(
1\_000000000000000000000000000000n, // $1 imbalance
5000000000000000000000000n, // 0.0005% factor
2\_000000000000000000000000000000n // exponent 2.0
);
console.log(result); // bigint result (30-decimal)
\`\`\`
### getCappedPriceImpactPercentageFromFees
\`\`\`typescript
getCappedPriceImpactPercentageFromFees(p: {
fees: TradeFees | undefined;
isSwap: boolean;
}): bigint | undefined
\`\`\`
Extracts the capped price impact percentage from an already-computed \`TradeFees\` object. Returns \`swapPriceImpact.precisePercentage\` for swaps or \`positionNetPriceImpact.precisePercentage\` for position trades. Returns \`0n\` when the relevant fee item is absent.
| Parameter | Type | Description |
| --------- | ------------------------ | ----------------------------------------------------------- |
| \`fees\` | \`TradeFees \\| undefined\` | Pre-computed trade fees object |
| \`isSwap\` | \`boolean\` | \`true\` to read swap impact; \`false\` to read position impact |
\`\`\`typescript
// Read position price impact percentage from an existing TradeFees object
const impactPercentage = getCappedPriceImpactPercentageFromFees({
fees: tradeFees,
isSwap: false,
});
// impactPercentage is a 30-decimal fraction — divide by 1e28 for a basis-point value
console.log(impactPercentage);
\`\`\`
### getMaxNegativeImpactBps
\`\`\`typescript
getMaxNegativeImpactBps(marketInfo: MarketInfo): bigint
\`\`\`
Converts a market's \`maxPositionImpactFactorNegative\` from a 30-decimal factor to basis points. Use this to display the maximum adverse price impact a user can experience in a given market.
| Parameter | Type | Description |
| ------------ | ------------ | ---------------------------------------------- |
| \`marketInfo\` | \`MarketInfo\` | Market to read the negative impact factor from |
\`\`\`typescript
const maxNegImpactBps = getMaxNegativeImpactBps(marketInfo);
// For example, 50n means 0.50% max negative price impact
\`\`\`
---
## gelatoRelay
This module exports Gelato relayer helpers and re-exported status types from \`@gelatocloud/gasless\`.
## Exports
- \`StatusCode\`
- \`TerminalStatus\`
- \`Status\`
- \`GelatoEvmRelayerClient\`
- \`getGelatoRelayerClient(apiKey)\`
\`\`\`typescript
\`\`\`
---
## graphqlFetcher
This module exports the SDK's default GraphQL POST fetch helper.
## Exports
- default export \`graphqlFetcher(endpoint, query, variables?)\`
\`\`\`typescript
\`\`\`
It posts \`{ query, variables }\` to the target endpoint and returns the \`data\` field from the GraphQL response.
---
## hash
This module exports low-level hashing helpers used for SDK key generation.
## Exports
- \`ZERO\_DATA\`
- \`hashData\`
- \`hashString\`
- \`hashDataMap\`
- \`keccakString\`
\`\`\`typescript
\`\`\`
---
## indexers
This module exports helper types and functions for building GraphQL filter bodies and paginating indexer reads.
## Exports
- \`GraphQlFilters\`
- \`buildFiltersBody\`
- \`queryPaginated\`
\`\`\`typescript
\`\`\`
---
## markets(Utils)
This module provides utilities for working with GMX markets, including market naming, pricing, liquidity calculations, and PnL computations. It handles market metadata, pool calculations, leverage limits, and various market-related operations.
## Methods
The \`markets\` utility module exports functions organized into six categories: display names, prices and PnL, liquidity and open interest, market classification, leverage, and data assembly.
### Market display names
#### getMarketFullName
\`getMarketFullName(p: { longToken: Token; shortToken: Token; indexToken: Token; isSpotOnly: boolean }): string\`
Returns the full display name of a market combining the index name and pool name.
\`\`\`typescript
const fullName = getMarketFullName({
longToken: ethToken,
shortToken: usdcToken,
indexToken: ethToken,
isSpotOnly: false,
});
// "ETH/USD \[ETH-USDC\]"
\`\`\`
#### getMarketIndexName
\`getMarketIndexName(p: ({ indexToken: Token } | { glvToken: Token }) & { isSpotOnly: boolean }): string\`
Returns the index name portion of a market name (for example, \`"ETH/USD"\` or \`"SWAP-ONLY"\`).
#### getMarketBaseName
\`getMarketBaseName(p: ({ indexToken: Token } | { glvToken: Token }) & { isSpotOnly: boolean }): string\`
Returns the base token name from a market (for example, \`"ETH"\`).
#### getMarketPoolName
\`getMarketPoolName(p: { longToken: Token; shortToken: Token }, separator?: string): string\`
Returns the pool name combining long and short token symbols. Default separator is \`"-"\`.
\`\`\`typescript
getMarketPoolName({ longToken: ethToken, shortToken: usdcToken }); // "ETH-USDC"
getMarketPoolName({ longToken: ethToken, shortToken: usdcToken }, "/"); // "ETH/USDC"
\`\`\`
#### getMarketAddressByName
\`getMarketAddressByName(marketsInfoData: MarketsInfoData, name: string): string | undefined\`
Looks up a market token address by its full name string (for example, \`"ETH/USD \[WETH-USDC\]"\`). Returns \`undefined\` if not found.
### Prices and PnL
#### getContractMarketPrices
\`getContractMarketPrices(tokensData: TokensData, market: Market): ContractMarketPrices | undefined\`
Returns contract-formatted prices for market tokens, or \`undefined\` if token price data is missing.
\`\`\`typescript
const contractPrices = getContractMarketPrices(tokensData, market);
if (contractPrices) {
console.log(contractPrices.indexTokenPrice);
}
\`\`\`
#### getPriceForPnl
\`getPriceForPnl(prices: TokenPrices, isLong: boolean, maximize: boolean): bigint\`
Returns the appropriate price (min or max) for PnL calculations based on position direction.
#### getMarketPnl
\`getMarketPnl(marketInfo: MarketInfo, isLong: boolean, forMaxPoolValue: boolean): bigint\`
Returns the aggregate PnL for the long or short side of a market.
#### getMarket24Stats
\`getMarket24Stats(dayPriceCandle: DayPriceCandle): { open24h, high24h, low24h, close24h, priceChange24h, priceChangePercent24hBps }\`
Computes 24-hour OHLC stats and price change in basis points from a day price candle.
#### getMarketTicker
\`getMarketTicker(marketInfo: MarketInfo, dayPriceCandle: DayPriceCandle): MarketTicker\`
Returns a comprehensive market ticker including prices, open interest, liquidity, funding rates, and borrowing rates.
### Liquidity and open interest
#### getPoolUsdWithoutPnl
\`getPoolUsdWithoutPnl(marketInfo: MarketInfo, isLong: boolean, priceType: "minPrice" | "maxPrice" | "midPrice"): bigint\`
Returns the USD value of the long or short pool excluding PnL.
#### getCappedPoolPnl
\`getCappedPoolPnl(p: { marketInfo: MarketInfo; poolUsd: bigint; poolPnl: bigint; isLong: boolean }): bigint\`
Returns the pool PnL capped at the market's maximum allowed PnL ratio.
#### getAvailableUsdLiquidityForCollateral
\`getAvailableUsdLiquidityForCollateral(marketInfo: MarketInfo, isLong: boolean): bigint\`
Returns available USD liquidity for collateral on the specified side.
#### getReservedUsd
\`getReservedUsd(marketInfo: MarketInfo, isLong: boolean): bigint\`
Returns the reserved USD amount for the long or short side.
#### getOpenInterestUsd
\`getOpenInterestUsd(marketInfo: MarketInfo, isLong: boolean): bigint\`
Returns the open interest in USD for the long or short side.
#### getOpenInterestInTokens
\`getOpenInterestInTokens(marketInfo: MarketInfo, isLong: boolean): bigint\`
Returns the open interest in tokens for the long or short side.
#### getOpenInterestForBalance
\`getOpenInterestForBalance(marketInfo: MarketInfo, isLong: boolean): bigint\`
Returns the open interest used for balance calculations. Uses token-denominated interest converted to USD when \`useOpenInterestInTokensForBalance\` is set.
#### getOiUsdFromRawValues
\`getOiUsdFromRawValues(rawValues: { longInterestUsingLongToken, longInterestUsingShortToken, shortInterestUsingLongToken, shortInterestUsingShortToken }, marketDivisor: bigint): { longInterestUsd, shortInterestUsd }\`
Computes aggregate long/short USD open interest from raw on-chain split values, applying the market divisor.
#### getOiInTokensFromRawValues
\`getOiInTokensFromRawValues(rawValues: {...}, marketDivisor: bigint): { longInterestInTokens, shortInterestInTokens }\`
Computes aggregate long/short token open interest from raw on-chain split values.
### Market classification and config
#### getTokenPoolType
\`getTokenPoolType(marketInfo: { longToken: Token; shortToken: Token }, tokenAddress: string): "long" | "short" | undefined\`
Returns whether a token belongs to the \`"long"\` or \`"short"\` pool in a market.
#### getMarketDivisor
\`getMarketDivisor({ longTokenAddress, shortTokenAddress }): bigint\`
Returns \`2n\` for single-collateral markets (same long/short token) and \`1n\` for two-token markets.
#### getOppositeCollateral
\`getOppositeCollateral(marketInfo: MarketInfo, tokenAddress: string): Token | undefined\`
Returns the opposite collateral token for a given token in a market.
#### getOppositeCollateralFromConfig
\`getOppositeCollateralFromConfig(marketConfig: ConfigMarketConfig, tokenAddress: string): string\`
Like \`getOppositeCollateral\` but works on the config object (addresses only, no hydrated token data).
#### getIsMarketAvailableForExpressSwaps
\`getIsMarketAvailableForExpressSwaps(marketInfo: MarketInfo): boolean\`
Returns \`true\` if all three market tokens (index, long, short) have a price feed provider, enabling express swaps.
### Leverage
#### getMaxLeverageByMinCollateralFactor
\`getMaxLeverageByMinCollateralFactor(minCollateralFactor: bigint | undefined): number\`
Returns the theoretical maximum leverage (as a basis-point integer) from the minimum collateral factor.
#### getMaxAllowedLeverageByMinCollateralFactor
\`getMaxAllowedLeverageByMinCollateralFactor(minCollateralFactor: bigint | undefined): number\`
Returns the maximum allowed leverage — half the theoretical maximum — as a basis-point integer.
#### getMarketWithTiers
\`getMarketWithTiers(marketInfo: MarketInfo, constants: { minCollateralUsd, minPositionSizeUsd }): MarketWithTiers\`
Returns a \`MarketWithTiers\` object including leverage tiers and size limits, used for market listing displays.
### Market data assembly
These functions assemble market data from raw on-chain responses. Typically used internally by the SDK client rather than called directly.
#### composeRawMarketInfo
\`composeRawMarketInfo({ market, marketValues, marketConfig, marketsConstants }): RawMarketInfo\`
Merges on-chain market values, config, and constants into a \`RawMarketInfo\` record.
#### composeRawMarketsInfoData
\`composeRawMarketsInfoData({ marketsAddresses, marketValues, marketConfigs, marketsConstants }): RawMarketsInfoData\`
Composes a full \`RawMarketsInfoData\` map for multiple markets.
#### hydrateMarketInfo
\`hydrateMarketInfo({ chainId, rawMarketInfo, tokensData, claimableFundingData? }): MarketInfo | undefined\`
Hydrates a \`RawMarketInfo\` into a full \`MarketInfo\` by resolving token addresses to \`Token\` objects. Returns \`undefined\` if any token is missing from \`tokensData\`.
#### composeFullMarketsInfoData
\`composeFullMarketsInfoData({ chainId, marketsAddresses, rawMarketsInfoData, tokensData, claimableFundingData? }): MarketsInfoData\`
Hydrates a full \`RawMarketsInfoData\` map into \`MarketsInfoData\`.
### API data fetching
#### fetchApiMarketsInfo
\`fetchApiMarketsInfo(ctx: { api: IHttp }): Promise\`
Fetches raw market info records from the GMX REST API.
#### fetchApiTokensData
\`fetchApiTokensData(ctx: { api: IHttp }): Promise\`
Fetches token data from the GMX REST API.
### Multicall helpers
These functions build and parse multicall requests for on-chain market data. They are used internally by the SDK.
#### buildClaimableFundingDataRequest
Builds a multicall request for claimable funding data for a given account and set of markets.
#### buildMarketsValuesRequest
Builds a multicall request for market values (pool amounts, open interest, PnL, and borrowing fees) for a set of markets.
#### parseMarketsValuesResponse
Parses the multicall response from \`buildMarketsValuesRequest\` into \`MarketsValuesData\`.
#### buildMarketsConfigsRequest
Builds a multicall request for market configurations (fees, impact factors, and borrowing rate parameters) for a set of markets.
#### parseMarketsConfigsResponse
Parses the multicall response from \`buildMarketsConfigsRequest\` into \`MarketsConfigsData\`.
### Hash key helpers (from \`hashKeys.ts\`)
Used internally for building multicall key hashes.
#### hashMarketConfigKeys
\`hashMarketConfigKeys(market: MarketConfigInput): MarketConfigKeysHash\`
#### hashMarketValuesKeys
\`hashMarketValuesKeys(market: MarketConfigInput): MarketValuesKeysHash\`
#### hashKinkModelKeys
\`hashKinkModelKeys(marketAddress: string): KinkModelKeysHash\`
---
## 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 & { 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. |
\`\`\`typescript
// 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 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
}
\`\`\`
:::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\`\](#numbertobigint) or \[\`expandDecimals\`\](#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. |
\`\`\`typescript
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
\`\`\`typescript
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.
\`\`\`typescript
const oneEth = expandDecimals(1, 18); // 1000000000000000000n
const oneUsd = expandDecimals(1, USD\_DECIMALS); // 1000000000000000000000000000000n
\`\`\`
#### basisPointsToFloat
\`\`\`typescript
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.
\`\`\`typescript
// 250 bps = 2.5%
const factor = basisPointsToFloat(250n); // (250n \* PRECISION) / 10000n
\`\`\`
#### getBasisPoints
\`\`\`typescript
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.
\`\`\`typescript
// 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
\`\`\`typescript
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.
\`\`\`typescript
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
\`\`\`typescript
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\`.
\`\`\`typescript
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
\`\`\`typescript
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.
\`\`\`typescript
numberToBigint(123.456, 18); // 123456000000000000000n
numberToBigint(-50.25, 6); // -50250000n
\`\`\`
#### bigintToNumber
\`\`\`typescript
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.
\`\`\`typescript
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
\`\`\`typescript
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.
\`\`\`typescript
// 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
\`\`\`typescript
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).
\`\`\`typescript
roundUpDivision(100n, 3n); // 34n (ceiling of 33.33...)
roundUpDivision(99n, 3n); // 33n (exact)
\`\`\`
#### roundToTwoDecimals
\`\`\`typescript
roundToTwoDecimals(n: number): number
\`\`\`
Rounds a JavaScript \`number\` to two decimal places using \`Math.round(n \* 100) / 100\`.
\`\`\`typescript
roundToTwoDecimals(123.456789); // 123.46
roundToTwoDecimals(1.005); // 1.01
\`\`\`
#### roundToOrder
\`\`\`typescript
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.
\`\`\`typescript
roundToOrder(123456789n, 3); // 123000000n
roundToOrder(987654321n, 1); // 900000000n
\`\`\`
#### roundBigIntToDecimals
\`\`\`typescript
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.
\`\`\`typescript
// Round an 18-decimal value to 6 decimal places
const precise = expandDecimals(123456789, 12); // 123456789000000000000n
const rounded = roundBigIntToDecimals(precise, 18, 6);
\`\`\`
#### roundWithDecimals
\`\`\`typescript
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\`.
\`\`\`typescript
// Round 8-decimal value to 4 display decimals
roundWithDecimals(123456789n, { displayDecimals: 4, decimals: 8 }); // 123460000n
\`\`\`
#### clamp
\`\`\`typescript
clamp(value: number, min: number, max: number): number
\`\`\`
Constrains a \`number\` to the \`\[min, max\]\` range, returning \`min\` if below or \`max\` if above.
\`\`\`typescript
clamp(150, 0, 100); // 100
clamp(-5, 0, 100); // 0
clamp(50, 0, 100); // 50
\`\`\`
#### minBigNumber
\`\`\`typescript
minBigNumber(...args: bigint\[\]): bigint | undefined
\`\`\`
Returns the smallest value from a list of \`bigint\` arguments. Returns \`undefined\` if called with no arguments.
\`\`\`typescript
minBigNumber(100n, 50n, 200n); // 50n
minBigNumber(); // undefined
\`\`\`
#### maxbigint
\`\`\`typescript
maxbigint(...args: bigint\[\]): bigint | undefined
\`\`\`
Returns the largest value from a list of \`bigint\` arguments. Returns \`undefined\` if called with no arguments.
\`\`\`typescript
maxbigint(100n, 50n, 200n); // 200n
\`\`\`
#### absDiffBps
\`\`\`typescript
absDiffBps(value: bigint, base: bigint): bigint
\`\`\`
Calculates the absolute difference between \`value\` and \`base\` expressed in basis points: \`|value - base| \* 10000 / base\`.
\`\`\`typescript
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
\`\`\`typescript
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\`.
\`\`\`typescript
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.
:::
\`\`\`typescript
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\`.
\`\`\`typescript
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.
:::
\`\`\`typescript
bigNumberify(n?: BigNumberish | null | undefined): bigint | undefined
\`\`\`
Wraps \`BigInt()\` in a try/catch, returning \`undefined\` instead of throwing on invalid input.
\`\`\`typescript
bigNumberify("123"); // 123n
bigNumberify("invalid"); // undefined (logs console.error)
bigNumberify(null); // undefined
\`\`\`
#### trimZeroDecimals
\`\`\`typescript
trimZeroDecimals(amount: string): string
\`\`\`
Removes trailing zeros and unnecessary decimal points from a numeric string.
\`\`\`typescript
trimZeroDecimals("123.000"); // "123"
trimZeroDecimals("123.456"); // "123.456"
trimZeroDecimals("0.00"); // "0"
\`\`\`
#### limitDecimals
\`\`\`typescript
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.
\`\`\`typescript
limitDecimals("123.456789", 4); // "123.4567" (truncated, not rounded)
limitDecimals("123.456789"); // "123.456789"
limitDecimals("123.456789", 0); // "123"
\`\`\`
#### padDecimals
\`\`\`typescript
padDecimals(amount: BigNumberish, minDecimals: number): string
\`\`\`
Pads a numeric string with trailing zeros to ensure at least \`minDecimals\` decimal places.
\`\`\`typescript
padDecimals("123.4", 4); // "123.4000"
padDecimals("123", 2); // "123.00"
padDecimals("1.50", 2); // "1.50" (already has enough decimals)
\`\`\`
#### removeTrailingZeros
\`\`\`typescript
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\`.
\`\`\`typescript
removeTrailingZeros("123.000"); // 123 (as number)
removeTrailingZeros("0.500"); // 0.5 (as number)
removeTrailingZeros(0); // 0 (unchanged)
\`\`\`
### Display formatting
#### formatAmount
\`\`\`typescript
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.
\`\`\`typescript
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
\`\`\`typescript
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.
\`\`\`typescript
formatAmountFree(expandDecimals(123, 18), 18, 6); // "0.000123"
formatAmountFree(expandDecimals(1, 18), 18, 4); // "1" (not "1.0000")
\`\`\`
#### formatKeyAmount
\`\`\`typescript
formatKeyAmount(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.
\`\`\`typescript
const market = { longOpenInterest: 1234567890000000000n };
formatKeyAmount(market, "longOpenInterest", 18, 4); // "1.2346"
formatKeyAmount(undefined, "longOpenInterest", 18, 4); // "..."
\`\`\`
#### formatArrayAmount
\`\`\`typescript
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.
\`\`\`typescript
const amounts = \[expandDecimals(1, 18), expandDecimals(2, 18)\];
formatArrayAmount(amounts, 0, 18, 4); // "1.0000"
\`\`\`
#### getLimitedDisplay
\`\`\`typescript
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.
\`\`\`typescript
// Amount below minimum threshold
const tiny = expandDecimals(1, 15); // 0.001 ETH
getLimitedDisplay(tiny, 18);
// { symbol: "<", value: }
// Amount above maximum threshold
const huge = expandDecimals(2\_000\_000\_000, 18);
getLimitedDisplay(huge, 18);
// { symbol: ">", value: }
// Amount in range
const normal = expandDecimals(100, 18);
getLimitedDisplay(normal, 18);
// { symbol: "", value: 100000000000000000000n }
\`\`\`
#### formatUsd
\`\`\`typescript
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\`.
\`\`\`typescript
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
\`\`\`typescript
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.
\`\`\`typescript
formatBigUsd(expandDecimals(999\_999\_999\_999, USD\_DECIMALS)); // "$999,999,999,999"
\`\`\`
#### formatDeltaUsd
\`\`\`typescript
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.
\`\`\`typescript
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
\`\`\`typescript
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).
\`\`\`typescript
// 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
\`\`\`typescript
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\`.
\`\`\`typescript
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
\`\`\`typescript
formatUsdPrice(price?: bigint, opts?: Parameters\[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.
\`\`\`typescript
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
\`\`\`typescript
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\`.
\`\`\`typescript
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
\`\`\`typescript
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\`.
\`\`\`typescript
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
\`\`\`typescript
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.
\`\`\`typescript
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
\`\`\`typescript
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.
\`\`\`typescript
formatTokenAmountWithUsd(expandDecimals(1, 18), expandDecimals(2500, USD\_DECIMALS), "ETH", 18); // "1.0000 ETH ($2,500.00)"
\`\`\`
#### formatBalanceAmount
\`\`\`typescript
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).
\`\`\`typescript
formatBalanceAmount(expandDecimals(123, 15), 18, "ETH"); // "0.000123 ETH"
formatBalanceAmount(0n, 18, "ETH"); // "-"
formatBalanceAmount(0n, 18, "ETH", { showZero: true }); // "0.0000 ETH"
\`\`\`
#### formatFactor
\`\`\`typescript
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.
\`\`\`typescript
formatFactor(expandDecimals(15, 29)); // "1.5"
formatFactor(expandDecimals(2, 30)); // "2"
formatFactor(0n); // "0"
\`\`\`
#### numberWithCommas
\`\`\`typescript
numberWithCommas(x: BigNumberish, opts?: { showDollar?: boolean }): string
\`\`\`
Adds comma thousand-separators to a number string. Returns \`"..."\` if the input is \`undefined\` or \`null\`.
\`\`\`typescript
numberWithCommas(1234567); // "1,234,567"
numberWithCommas(1234567.89); // "1,234,567.89"
numberWithCommas(1234567, { showDollar: true }); // "$1,234,567"
\`\`\`
#### calculateDisplayDecimals
\`\`\`typescript
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.
\`\`\`typescript
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
\`\`\`typescript
getPlusOrMinusSymbol(value?: bigint, opts?: { showPlusForZero?: boolean }): string
\`\`\`
Returns \`"+"\` for positive values, \`"-"\` for negative values, and \`""\` for zero. Pass \`showPlusForZero: true\` to return \`"+"\` for zero.
\`\`\`typescript
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
\`\`\`typescript
serializeBigIntsInObject(obj: T): SerializedBigIntsInObject
\`\`\`
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.
\`\`\`typescript
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
\`\`\`typescript
deserializeBigIntsInObject(
obj: T,
opts?: { handleInts?: boolean }
): DeserializeBigIntInObject
\`\`\`
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\`.
\`\`\`typescript
const stored = { size: { type: "bigint", value: "1000000000000000000000000000000" } };
const position = deserializeBigIntsInObject(stored);
// { size: 1000000000000000000000000000000n }
\`\`\`
---
## objects
This module exports dictionary helpers used across the SDK.
## Exports
- \`setByKey\`
- \`updateByKey\`
- \`getByKey\`
- \`deleteByKey\`
- \`objectKeysDeep\`
- \`toDict\`
\`\`\`typescript
\`\`\`
---
## orders
This module provides utilities for working with GMX orders, including type checking functions, order information processing, and order classification helpers. It handles both swap orders and position orders, including TWAP (Time-Weighted Average Price) orders.
## Methods
This module exports type-check predicates, type-narrowing guards, and data-enrichment helpers for working with GMX orders. Import everything from \`@gmx-io/sdk/utils/orders\`.
### Order type classification
The following predicates check which broad category an \`OrderType\` enum value belongs to. Use these to branch logic without hardcoding enum integers.
| Function | Returns \`true\` for |
| ---------------------------- | ----------------------------------------------------- |
| \`isMarketOrderType\` | \`MarketSwap\`, \`MarketIncrease\`, \`MarketDecrease\` |
| \`isLimitOrderType\` | \`LimitIncrease\`, \`LimitSwap\`, \`StopIncrease\` |
| \`isTriggerDecreaseOrderType\` | \`LimitDecrease\`, \`StopLossDecrease\` |
| \`isDecreaseOrderType\` | \`MarketDecrease\`, \`LimitDecrease\`, \`StopLossDecrease\` |
| \`isIncreaseOrderType\` | \`MarketIncrease\`, \`LimitIncrease\`, \`StopIncrease\` |
| \`isSwapOrderType\` | \`MarketSwap\`, \`LimitSwap\` |
| \`isLimitSwapOrderType\` | \`LimitSwap\` only |
| \`isLiquidationOrderType\` | \`Liquidation\` only |
| \`isStopLossOrderType\` | \`StopLossDecrease\` only |
| \`isLimitDecreaseOrderType\` | \`LimitDecrease\` only |
| \`isLimitIncreaseOrderType\` | \`LimitIncrease\` only |
| \`isStopIncreaseOrderType\` | \`StopIncrease\` only |
:::note
\`isLimitOrderType\` includes \`StopIncrease\` (Stop Market Increase) in addition to \`LimitIncrease\` and \`LimitSwap\`. This matches the on-chain classification where stop market increase orders behave like limit orders — they execute when price reaches a trigger level.
:::
\`\`\`typescript
isMarketOrderType,
isLimitOrderType,
isTriggerDecreaseOrderType,
isDecreaseOrderType,
isIncreaseOrderType,
isSwapOrderType,
isLiquidationOrderType,
} from "@gmx-io/sdk/utils/orders";
isMarketOrderType(OrderType.MarketIncrease); // true
isLimitOrderType(OrderType.LimitIncrease); // true
isLimitOrderType(OrderType.StopIncrease); // true — stop market is treated as limit
isTriggerDecreaseOrderType(OrderType.StopLossDecrease); // true
isDecreaseOrderType(OrderType.MarketDecrease); // true
isIncreaseOrderType(OrderType.LimitIncrease); // true
isSwapOrderType(OrderType.LimitSwap); // true
isLiquidationOrderType(OrderType.Liquidation); // true
\`\`\`
### \`isIncreaseOrderType\`
\`\`\`typescript
function isIncreaseOrderType(
orderType: OrderType
): orderType is OrderType.MarketIncrease | OrderType.LimitIncrease | OrderType.StopIncrease;
\`\`\`
Type predicate that narrows \`OrderType\` to one of the three increase variants. Use this in conditional branches where the TypeScript compiler must know the narrowed type.
\`\`\`typescript
function handleOrder(orderType: OrderType) {
if (isIncreaseOrderType(orderType)) {
// orderType is now typed as MarketIncrease | LimitIncrease | StopIncrease
return buildIncreaseParams(orderType);
}
}
\`\`\`
### OrderInfo type guards
These functions accept an \`OrderInfo\` object (enriched order) and narrow its type to a more specific variant. \`OrderInfo\` is a union of \`SwapOrderInfo\`, \`PositionOrderInfo\`, and \`TwapOrderInfo\`.
| Function | Narrows to |
| -------------------------------- | --------------------------------------------------------------------------------------- |
| \`isSwapOrder(orderInfo)\` | \`SwapOrderInfo\` — has \`triggerRatio\`, \`initialCollateralToken\`, \`targetCollateralToken\` |
| \`isPositionOrder(orderInfo)\` | \`PositionOrderInfo\` — has \`acceptablePrice\`, \`triggerPrice\`, \`marketInfo\`, \`indexToken\` |
| \`isTwapOrder(orderInfo)\` | \`Extract\` — has \`orders\[\]\`, \`twapId\`, \`numberOfParts\` |
| \`isTwapSwapOrder(orderInfo)\` | \`TwapOrderInfo\` |
| \`isTwapPositionOrder(orderInfo)\` | \`TwapOrderInfo\` |
\`\`\`typescript
isSwapOrder,
isPositionOrder,
isTwapOrder,
isTwapSwapOrder,
isTwapPositionOrder,
} from "@gmx-io/sdk/utils/orders";
// Route order handling by type
function handleOrderInfo(orderInfo: OrderInfo) {
if (isTwapOrder(orderInfo)) {
// orderInfo.orders — array of individual sub-orders
console.log(\`TWAP has ${orderInfo.orders.length} parts\`);
} else if (isSwapOrder(orderInfo)) {
console.log("Swap trigger ratio:", orderInfo.triggerRatio);
} else if (isPositionOrder(orderInfo)) {
console.log("Acceptable price:", orderInfo.acceptablePrice);
}
}
\`\`\`
### \`getOrderKeys\`
\`\`\`typescript
function getOrderKeys(order: OrderInfo): string\[\];
\`\`\`
Returns all on-chain order keys for an order. TWAP orders have one key per sub-order; regular orders have a single key. Use this when you need to cancel or update all parts of an order without special-casing TWAP.
\`\`\`typescript
const keys = getOrderKeys(orderInfo);
// Regular order: \["0xabc..."\]
// TWAP order with 4 parts: \["0xabc...", "0xdef...", "0x123...", "0x456..."\]
\`\`\`
### \`getOrderInfo\`
\`\`\`typescript
function getOrderInfo(p: {
marketsInfoData: MarketsInfoData;
tokensData: TokensData;
wrappedNativeToken: Token;
order: Order;
}): OrderInfo | undefined;
\`\`\`
Enriches a raw \`Order\` (as returned by the contract reader) into an \`OrderInfo\` with resolved token data, market info, computed swap path stats, trigger ratios, and parsed prices. Returns \`undefined\` if required tokens or market data are missing from the supplied data maps.
#### Parameters
| Parameter | Type | Description |
| -------------------- | ----------------- | ------------------------------------------------- |
| \`marketsInfoData\` | \`MarketsInfoData\` | Map of market address → \`MarketInfo\` |
| \`tokensData\` | \`TokensData\` | Map of token address → \`TokenData\` with prices |
| \`wrappedNativeToken\` | \`Token\` | Wrapped native token (for unwrap path resolution) |
| \`order\` | \`Order\` | Raw order object from contract |
:::warning
\`getOrderInfo\` returns \`undefined\` when any required lookup fails — for example, when the initial collateral token or target collateral token is not present in \`tokensData\`, or when the market is not in \`marketsInfoData\`. Always check the return value before accessing fields.
:::
\`\`\`typescript
const orderInfo = getOrderInfo({
marketsInfoData,
tokensData,
wrappedNativeToken,
order: rawOrder,
});
if (!orderInfo) {
// Token or market data not loaded yet — retry when data is available
return;
}
console.log("Trigger price:", orderInfo.triggerPrice);
\`\`\`
### \`isVisibleOrder\`
\`\`\`typescript
function isVisibleOrder(orderType: OrderType): boolean;
\`\`\`
Returns \`true\` if the order type is one that a user would see in a position or orders list. Returns \`true\` for all market orders, limit orders, limit swap orders, and trigger decrease orders. Returns \`false\` for \`Liquidation\` (which is a keeper action, not a user order).
\`\`\`typescript
isVisibleOrder(OrderType.LimitIncrease); // true
isVisibleOrder(OrderType.MarketDecrease); // true
isVisibleOrder(OrderType.Liquidation); // false — liquidations are not user-visible
\`\`\`
### \`isOrderForPosition\`
\`\`\`typescript
function isOrderForPosition(order: OrderInfo, positionKey: string): order is PositionOrderInfo;
\`\`\`
Returns \`true\` if the order belongs to the position identified by \`positionKey\`, and narrows the type to \`PositionOrderInfo\`. The collateral address check differs by order type: limit increase orders match on \`targetCollateralToken\`, while trigger decrease orders match on \`initialCollateralTokenAddress\`.
\`\`\`typescript
const positionOrders = orders.filter((o) => isOrderForPosition(o, positionKey));
// positionOrders is now typed as PositionOrderInfo\[\]
\`\`\`
### \`isOrderForPositionByData\`
\`\`\`typescript
function isOrderForPositionByData(
order: OrderInfo,
params: {
account: string;
marketAddress: string;
collateralAddress: string;
isLong: boolean;
}
): order is PositionOrderInfo;
\`\`\`
Same matching logic as \`isOrderForPosition\` but accepts explicit position data instead of a position key string. Use this when you have individual position fields rather than a composed key.
#### Parameters
| Parameter | Type | Description |
| ------------------- | ----------- | ------------------------- |
| \`order\` | \`OrderInfo\` | Enriched order to check |
| \`account\` | \`string\` | Trader account address |
| \`marketAddress\` | \`string\` | Market contract address |
| \`collateralAddress\` | \`string\` | Collateral token address |
| \`isLong\` | \`boolean\` | \`true\` for long positions |
\`\`\`typescript
const isMatch = isOrderForPositionByData(orderInfo, {
account: "0x1234567890123456789012345678901234567890",
marketAddress: "0xFD70de6b91282D8017aA4E741e9Ae325CAb992d8",
collateralAddress: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
isLong: true,
});
\`\`\`
### \`getOrderTradeboxKey\`
\`\`\`typescript
function getOrderTradeboxKey(order: OrderInfo): string;
\`\`\`
Returns a stable string key for deduplicating orders by position in UI state. Position orders (including TWAP position orders) use the format \`POSITION-{account}:{marketAddress}:{collateralAddress}:{isLong}\`. Swap orders use \`SWAP-{account}:{initialCollateralTokenAddress}:{targetCollateralToken.address}\`.
\`\`\`typescript
const key = getOrderTradeboxKey(orderInfo);
// Position order example:
// "POSITION-0x1234...5678:0xFD70...2d8:0x82aF...bab1:true"
// Swap order example:
// "SWAP-0x1234...5678:0x82aF...bab1:0xFF97...cf5"
\`\`\`
### API data fetching
#### \`fetchApiOrders\`
\`\`\`typescript
fetchApiOrders(ctx: { api: IHttp }, params: {
address: string;
}): Promise
\`\`\`
Fetches order data from the GMX REST API instead of on-chain multicalls. Available on chains where \`isApiSupported(chainId)\` returns \`true\` (Arbitrum, Avalanche, and Arbitrum Sepolia). The response is deserialized with \`deserializeBigIntsInObject\`.
\`\`\`typescript
const apiSdk = new GmxApiSdk({ chainId: 42161 });
const orders = await fetchApiOrders(apiSdk.ctx, { address: "0x1234...5678" });
\`\`\`
## Related
- \[\`utils/prices\`\](./prices.md) — \`getOrderThresholdType\`, trigger price logic
- \[\`utils/trade/increase\`\](./trade/increase.md) — building increase position order params
- \[\`utils/trade/decrease\`\](./trade/decrease.md) — building decrease position order params
---
## positions
This module provides utilities for working with trading positions in the GMX protocol. It includes functions for calculating position metrics, PnL, liquidation prices, leverage, and managing position keys.
## Methods
The positions utility module exports functions organized into six groups: position key utilities, position value calculations, leverage and risk, price impact calculations, API data fetching, and position enrichment. Import any function directly from \`@gmx-io/sdk/utils/positions\`.
### Position key utilities
These functions create and parse the string keys used to identify positions on-chain.
#### getPositionKey
\`\`\`typescript
getPositionKey(account: string, marketAddress: string, collateralAddress: string, isLong: boolean): string
\`\`\`
Generates a unique position key from position parameters. The key format is \`account:marketAddress:collateralAddress:isLong\`.
\`\`\`typescript
const positionKey = getPositionKey(
"0x1234567890123456789012345678901234567890",
"0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
"0xfedcbafedcbafedcbafedcbafedcbafedcbafed",
true
);
// "0x1234...5678:0xabcd...abcd:0xfedc...afed:true"
\`\`\`
#### parsePositionKey
\`\`\`typescript
parsePositionKey(positionKey: string): {
account: string;
marketAddress: string;
collateralAddress: string;
isLong: boolean;
}
\`\`\`
Parses a position key back into its component parts. The \`isLong\` field is parsed from the string \`"true"\` / \`"false"\`.
\`\`\`typescript
const parsed = parsePositionKey("0x1234567890123456789012345678901234567890:0xabcdef...:0xfedcba...:true");
// { account: "0x1234...", marketAddress: "0xabcdef...", collateralAddress: "0xfedcba...", isLong: true }
\`\`\`
### Position value calculations
These functions compute USD-denominated metrics from raw position data. All values use 30-decimal fixed-point representation.
#### getEntryPrice
\`\`\`typescript
getEntryPrice(p: { sizeInUsd: bigint; sizeInTokens: bigint; indexToken: Token }): bigint | undefined
\`\`\`
Calculates the entry price of a position as \`sizeInUsd × 10^indexToken.decimals / sizeInTokens\`. Returns \`undefined\` when \`sizeInTokens <= 0\`.
\`\`\`typescript
const entryPrice = getEntryPrice({
sizeInUsd: 1800n \* 10n \*\* 30n, // $1800 (30-decimal)
sizeInTokens: 1n \* 10n \*\* 18n, // 1 WETH (18-decimal)
indexToken: wethToken,
});
// 1800n \* 10n \*\* 30n — price in 30-decimal format
\`\`\`
#### getPositionValueUsd
\`\`\`typescript
getPositionValueUsd(p: { indexToken: Token; sizeInTokens: bigint; markPrice: bigint }): bigint
\`\`\`
Calculates the current USD value of a position: \`convertToUsd(sizeInTokens, indexToken.decimals, markPrice)\`.
\`\`\`typescript
const valueUsd = getPositionValueUsd({
indexToken: wethToken,
sizeInTokens: 1n \* 10n \*\* 18n, // 1 WETH
markPrice: 2100n \* 10n \*\* 30n, // $2100 (30-decimal)
});
// 2100n \* 10n \*\* 30n
\`\`\`
#### getPositionPnlUsd
\`\`\`typescript
getPositionPnlUsd(p: {
marketInfo: MarketInfo;
sizeInUsd: bigint;
sizeInTokens: bigint;
markPrice: bigint;
isLong: boolean;
}): bigint
\`\`\`
Calculates the unrealized PnL of a position in USD (30-decimal). For profitable positions, the result is scaled down proportionally if the pool's total PnL exceeds its cap.
- Long PnL: \`positionValueUsd - sizeInUsd\`
- Short PnL: \`sizeInUsd - positionValueUsd\`
\`\`\`typescript
const pnl = getPositionPnlUsd({
marketInfo,
sizeInUsd: 1800n \* 10n \*\* 30n, // entry value
sizeInTokens: 1n \* 10n \*\* 18n, // 1 WETH
markPrice: 2100n \* 10n \*\* 30n, // current price
isLong: true,
});
// +300n \* 10n \*\* 30n ($300 profit, before pool cap adjustment)
\`\`\`
#### getPositionPendingFeesUsd
\`\`\`typescript
getPositionPendingFeesUsd(p: { pendingFundingFeesUsd: bigint; pendingBorrowingFeesUsd: bigint }): bigint
\`\`\`
Returns \`pendingBorrowingFeesUsd + pendingFundingFeesUsd\`.
\`\`\`typescript
const pendingFees = getPositionPendingFeesUsd({
pendingFundingFeesUsd: 1n \* 10n \*\* 30n, // $1
pendingBorrowingFeesUsd: 5n \* 10n \*\* 29n, // $0.5
});
// 1\_500\_000n \* 10n \*\* 24n ($1.5 in 30-decimal)
\`\`\`
#### getPositionNetValue
\`\`\`typescript
getPositionNetValue(p: {
totalPendingImpactDeltaUsd: bigint;
priceImpactDiffUsd: bigint;
collateralUsd: bigint;
pendingFundingFeesUsd: bigint;
pendingBorrowingFeesUsd: bigint;
pnl: bigint;
closingFeeUsd: bigint;
uiFeeUsd: bigint;
}): bigint
\`\`\`
Returns the net value of a position:
\`\`\`
collateralUsd - pendingFees - closingFeeUsd - uiFeeUsd + pnl + totalPendingImpactDeltaUsd + priceImpactDiffUsd
\`\`\`
\`\`\`typescript
const netValue = getPositionNetValue({
totalPendingImpactDeltaUsd: 0n,
priceImpactDiffUsd: 0n,
collateralUsd: 500n \* 10n \*\* 30n, // $500 collateral
pendingFundingFeesUsd: 1n \* 10n \*\* 30n,
pendingBorrowingFeesUsd: 5n \* 10n \*\* 29n,
pnl: 50n \* 10n \*\* 30n, // $50 profit
closingFeeUsd: 2n \* 10n \*\* 30n,
uiFeeUsd: 0n,
});
// $546.50 in 30-decimal
\`\`\`
#### getPositionPnlAfterFees
\`\`\`typescript
getPositionPnlAfterFees(params: {
pnl: bigint;
pendingBorrowingFeesUsd: bigint;
pendingFundingFeesUsd: bigint;
closingFeeUsd: bigint;
uiFeeUsd: bigint;
totalPendingImpactDeltaUsd: bigint;
priceImpactDiffUsd: bigint;
}): bigint
\`\`\`
Returns the position PnL after deducting all fees and adding price impact:
\`\`\`
pnl - pendingBorrowingFeesUsd - pendingFundingFeesUsd - closingFeeUsd - uiFeeUsd + totalPendingImpactDeltaUsd + priceImpactDiffUsd
\`\`\`
\`\`\`typescript
const pnlAfterFees = getPositionPnlAfterFees({
pnl: 100n \* 10n \*\* 30n,
pendingBorrowingFeesUsd: 1n \* 10n \*\* 30n,
pendingFundingFeesUsd: 5n \* 10n \*\* 29n,
closingFeeUsd: 2n \* 10n \*\* 30n,
uiFeeUsd: 0n,
totalPendingImpactDeltaUsd: 0n,
priceImpactDiffUsd: 0n,
});
// $96.50 in 30-decimal
\`\`\`
### Leverage and risk
These functions compute leverage and liquidation price for a position.
#### getLeverage
\`\`\`typescript
getLeverage(p: {
sizeInUsd: bigint;
collateralUsd: bigint;
pnl: bigint | undefined;
pendingFundingFeesUsd: bigint;
pendingBorrowingFeesUsd: bigint;
}): bigint | undefined
\`\`\`
Returns the current leverage in basis points (\`sizeInUsd × BASIS\_POINTS\_DIVISOR / remainingCollateralUsd\`), where \`remainingCollateralUsd = collateralUsd + pnl - pendingFees\`. Returns \`undefined\` when \`remainingCollateralUsd <= 0\`.
\`BASIS\_POINTS\_DIVISOR = 10000\`, so a return value of \`20000n\` means 2× leverage.
\`\`\`typescript
const leverage = getLeverage({
sizeInUsd: 1000n \* 10n \*\* 30n,
collateralUsd: 100n \* 10n \*\* 30n,
pnl: 10n \* 10n \*\* 30n,
pendingFundingFeesUsd: 1n \* 10n \*\* 30n,
pendingBorrowingFeesUsd: 5n \* 10n \*\* 29n,
});
// ~92593n bps ≈ 9.26×
\`\`\`
#### getLiquidationPrice
\`\`\`typescript
getLiquidationPrice(p: {
sizeInUsd: bigint;
sizeInTokens: bigint;
collateralAmount: bigint;
collateralUsd: bigint;
collateralToken: TokenData;
marketInfo: MarketInfo;
pendingFundingFeesUsd: bigint;
pendingBorrowingFeesUsd: bigint;
pendingImpactAmount: bigint;
minCollateralUsd: bigint;
isLong: boolean;
useMaxPriceImpact?: boolean;
userReferralInfo: UserReferralInfo | undefined;
}): bigint | undefined
\`\`\`
Calculates the liquidation price for a position. Returns \`undefined\` when \`sizeInUsd <= 0\`, \`sizeInTokens <= 0\`, the denominator is zero, or when the computed price is \`<= 0\`.
Two formulas are used depending on whether the collateral token is equivalent to the index token:
- \*\*Equivalent collateral\*\* (for example, long ETH/USDC collateralized in ETH): combines token amounts directly with \`sizeInTokens ± collateralAmount\` as denominator.
- \*\*Non-equivalent collateral\*\* (for example, long ETH/USDC collateralized in USDC): uses \`remainingCollateralUsd\` and \`sizeInTokens\` as denominator.
When \`useMaxPriceImpact\` is \`true\`, uses \`marketInfo.maxPositionImpactFactorForLiquidations\` instead of computing the actual price impact.
\`\`\`typescript
const liquidationPrice = getLiquidationPrice({
sizeInUsd: 1800n \* 10n \*\* 30n,
sizeInTokens: 1n \* 10n \*\* 18n,
collateralAmount: 100n \* 10n \*\* 6n, // 100 USDC (6-decimal collateral)
collateralUsd: 100n \* 10n \*\* 30n,
collateralToken: usdcTokenData,
marketInfo,
pendingFundingFeesUsd: 1n \* 10n \*\* 30n,
pendingBorrowingFeesUsd: 5n \* 10n \*\* 29n,
pendingImpactAmount: 0n,
minCollateralUsd: 10n \* 10n \*\* 30n,
isLong: true,
useMaxPriceImpact: false,
userReferralInfo: undefined,
});
\`\`\`
### Price impact calculations
These functions compute the net price impact when decreasing a position, including contributions from the pending impact pool.
#### getNetPriceImpactDeltaUsdForDecrease
\`\`\`typescript
getNetPriceImpactDeltaUsdForDecrease(params: {
marketInfo: MarketInfo;
sizeInUsd: bigint;
pendingImpactAmount: bigint;
priceImpactDeltaUsd: bigint;
sizeDeltaUsd: bigint;
}): {
totalImpactDeltaUsd: bigint;
proportionalPendingImpactDeltaUsd: bigint;
priceImpactDiffUsd: bigint;
}
\`\`\`
Calculates the net price impact when decreasing a position by combining the current price impact with a proportional share of the pending impact pool. The positive total is capped by \`maxPositionImpactFactor\`; the negative total is floored by the max impact pool limit.
\`\`\`typescript
const impact = getNetPriceImpactDeltaUsdForDecrease({
marketInfo,
sizeInUsd: 1800n \* 10n \*\* 30n,
pendingImpactAmount: 0n,
priceImpactDeltaUsd: -5n \* 10n \*\* 30n, // $5 adverse price impact
sizeDeltaUsd: 900n \* 10n \*\* 30n, // closing half the position
});
// impact.totalImpactDeltaUsd — net impact after caps
// impact.proportionalPendingImpactDeltaUsd — share of pending impact pool
// impact.priceImpactDiffUsd — capped-off portion (goes to holding pool)
\`\`\`
#### getPriceImpactDiffUsd
\`\`\`typescript
getPriceImpactDiffUsd(params: {
totalImpactDeltaUsd: bigint;
marketInfo: MarketInfo;
sizeDeltaUsd: bigint;
}): bigint
\`\`\`
Returns the portion of a negative price impact that exceeds the market's maximum negative impact factor. Returns \`0n\` when \`totalImpactDeltaUsd >= 0\`.
\`\`\`typescript
const diff = getPriceImpactDiffUsd({
totalImpactDeltaUsd: -10n \* 10n \*\* 30n, // $10 adverse impact
marketInfo,
sizeDeltaUsd: 500n \* 10n \*\* 30n,
});
// 0n if impact is within the max factor, otherwise the excess
\`\`\`
### API data fetching
Use \`fetchApiPositionsInfo\` to retrieve position data from the GMX REST API as an alternative to on-chain multicalls.
#### fetchApiPositionsInfo
\`\`\`typescript
fetchApiPositionsInfo(ctx: { api: IHttp }, params: {
address: string;
includeRelatedOrders?: boolean;
}): Promise
\`\`\`
Fetches position data from the GMX REST API instead of on-chain multicalls. Available on chains where \`isApiSupported(chainId)\` returns \`true\` (Arbitrum, Avalanche, and Arbitrum Sepolia). The response is deserialized with \`deserializeBigIntsInObject\`.
\`\`\`typescript
const apiSdk = new GmxApiSdk({ chainId: 42161 });
const positions = await fetchApiPositionsInfo(
apiSdk.ctx,
{ address: "0x1234...5678", includeRelatedOrders: true }
);
\`\`\`
### Position enrichment
These functions build fully computed position summaries from raw on-chain data and current market state.
#### getPositionInfo
\`\`\`typescript
getPositionInfo(p: {
position: Position;
marketInfo: MarketInfo;
minCollateralUsd: bigint;
userReferralInfo?: UserReferralInfo;
showPnlInLeverage?: boolean;
uiFeeFactor?: bigint;
}): PositionInfo
\`\`\`
Computes a comprehensive position summary from a raw position and market data. Returns an object with entry price, mark price, PnL, PnL after fees, leverage, liquidation price, net value, pending fees, and closing costs. This is the main function to use when you need a full picture of a position's current state.
\`\`\`typescript
const info = getPositionInfo({
position,
marketInfo,
minCollateralUsd: 10n \* 10n \*\* 30n,
userReferralInfo: undefined,
});
console.log(info.entryPrice); // entry price in 30-decimal
console.log(info.pnl); // unrealized PnL
console.log(info.pnlAfterFees); // PnL minus all fees
console.log(info.leverage); // current leverage in basis points
console.log(info.liquidationPrice); // liquidation price
console.log(info.netValue); // net position value
\`\`\`
#### getContractPositionDynamicFees
\`\`\`typescript
getContractPositionDynamicFees(p: {
position: {
sizeInUsd: bigint;
collateralTokenAddress: string;
isLong: boolean;
borrowingFactor: bigint;
fundingFeeAmountPerSize: bigint;
longTokenClaimableFundingAmountPerSize: bigint;
shortTokenClaimableFundingAmountPerSize: bigint;
};
marketInfo: MarketInfo;
marketFeeState: {
cumulativeBorrowingFactorLong: bigint;
cumulativeBorrowingFactorShort: bigint;
fundingFeeAmountPerSizeLongLong: bigint;
fundingFeeAmountPerSizeLongShort: bigint;
fundingFeeAmountPerSizeShortLong: bigint;
fundingFeeAmountPerSizeShortShort: bigint;
claimableFundingAmountPerSizeLongLong: bigint;
claimableFundingAmountPerSizeLongShort: bigint;
claimableFundingAmountPerSizeShortLong: bigint;
claimableFundingAmountPerSizeShortShort: bigint;
};
referralInfo?: UserReferralInfo;
}): {
pendingBorrowingFeesUsd: bigint;
fundingFeeAmount: bigint;
claimableLongTokenAmount: bigint;
claimableShortTokenAmount: bigint;
positionFeeAmount: bigint;
traderDiscountAmount: bigint;
uiFeeAmount: bigint;
}
\`\`\`
Calculates the dynamic fees for a position based on the current market fee state. Unlike the static fee fields on a position object, this function uses the latest cumulative borrowing and funding factors to compute up-to-date fee values.
\`\`\`typescript
const fees = getContractPositionDynamicFees({
position,
marketInfo,
marketFeeState,
referralInfo: undefined,
});
console.log(fees.pendingBorrowingFeesUsd); // current borrowing fees in USD
console.log(fees.fundingFeeAmount); // funding fee in collateral token units
\`\`\`
### Collateral factor
#### getMinCollateralFactorForPosition
\`\`\`typescript
getMinCollateralFactorForPosition(position: PositionInfoLoaded, openInterestDelta: bigint): bigint
\`\`\`
Returns the minimum collateral factor (in PRECISION units) required for the position's market side, given the current open interest plus \`openInterestDelta\`. The result is the greater of the OI-based factor and the market's baseline \`minCollateralFactor\`.
\`\`\`typescript
const minFactor = getMinCollateralFactorForPosition(
positionInfo,
-1000n \* 10n \*\* 30n // OI decreasing by $1000
);
\`\`\`
---
## prices
This module provides utilities for calculating prices, price impacts, and acceptable price ranges for GMX trading operations. This page also covers the related OHLCV read surface exposed through \`GmxApiSdk\`, because the candle types live in the same source area.
## Methods
The \`prices\` module exports utilities for two tasks: determining which side of the bid-ask spread to use for a given operation, and computing acceptable prices that encode a user's slippage tolerance into an on-chain parameter. The OHLCV section below is included because the public \`GmxApiSdk.fetchOhlcv()\` method uses the same source area, but \`@gmx-io/sdk/utils/prices\` does not export the fetch helper directly.
### getMarkPrice
\`\`\`typescript
getMarkPrice(p: { prices: TokenPrices; isIncrease: boolean; isLong: boolean }): bigint
\`\`\`
Returns the mark price for an operation. Long increases and short decreases use \`maxPrice\`; short increases and long decreases use \`minPrice\`. This matches the on-chain convention that the protocol uses the price least favorable to the trader.
\`\`\`typescript
const markPrice = getMarkPrice({
prices: {
minPrice: 1800n \* 10n \*\* 30n,
maxPrice: 1802n \* 10n \*\* 30n,
},
isIncrease: true,
isLong: true,
});
// Returns prices.maxPrice (worst price for a long increase)
\`\`\`
### getShouldUseMaxPrice
\`\`\`typescript
getShouldUseMaxPrice(isIncrease: boolean, isLong: boolean): boolean
\`\`\`
Returns \`true\` when the operation should use \`maxPrice\` and \`false\` when it should use \`minPrice\`. The rule is: \`isIncrease ? isLong : !isLong\`.
\`\`\`typescript
getShouldUseMaxPrice(true, true); // true — long increase uses maxPrice
getShouldUseMaxPrice(true, false); // false — short increase uses minPrice
getShouldUseMaxPrice(false, true); // false — long decrease uses minPrice
getShouldUseMaxPrice(false, false); // true — short decrease uses maxPrice
\`\`\`
### getOrderThresholdType
\`\`\`typescript
getOrderThresholdType(orderType: OrderType, isLong: boolean): TriggerThresholdType | undefined
\`\`\`
Returns the \`TriggerThresholdType\` (\`Above\` or \`Below\`) for a trigger order. Returns \`undefined\` for order types that don't use a trigger price (for example, Market Increase).
| Order type | Long | Short |
| -------------------------------- | ------- | ------- |
| Limit Increase (\`LimitIncrease\`) | \`Below\` | \`Above\` |
| Stop Market (\`StopIncrease\`) | \`Above\` | \`Below\` |
| Take-Profit (\`LimitDecrease\`) | \`Above\` | \`Below\` |
| Stop-Loss (\`StopLossDecrease\`) | \`Below\` | \`Above\` |
\`\`\`typescript
const thresholdType = getOrderThresholdType(OrderType.LimitIncrease, true);
// TriggerThresholdType.Below — trigger when price drops to or below target
\`\`\`
### getAcceptablePriceInfo
\`\`\`typescript
getAcceptablePriceInfo(p: {
marketInfo: MarketInfo;
isIncrease: boolean;
isLimit: boolean;
isLong: boolean;
indexPrice: bigint;
sizeDeltaUsd: bigint;
maxNegativePriceImpactBps?: bigint;
}): {
acceptablePrice: bigint;
acceptablePriceDeltaBps: bigint;
priceImpactDeltaAmount: bigint;
priceImpactDeltaUsd: bigint;
priceImpactDiffUsd: bigint;
balanceWasImproved: boolean;
}
\`\`\`
Computes the acceptable price and price impact for an order. There are two code paths:
- When \`maxNegativePriceImpactBps\` is provided (Limit and Trigger orders): the acceptable price is derived directly from the basis-points slippage tolerance, and price impact is back-calculated from that price.
- When \`maxNegativePriceImpactBps\` is omitted (Market orders): the on-chain pool price impact is computed via \`getCappedPositionImpactUsd\` and used to derive the acceptable price.
Returns zero values when \`sizeDeltaUsd\` is \`0\` or \`indexPrice\` is \`0n\`.
\`\`\`typescript
// Market order: derive acceptable price from live pool price impact
const result = getAcceptablePriceInfo({
marketInfo,
isIncrease: true,
isLimit: false,
isLong: true,
indexPrice: 1800n \* 10n \*\* 30n,
sizeDeltaUsd: 10000n \* 10n \*\* 30n, // $10,000 position
});
console.log("Acceptable price:", result.acceptablePrice);
console.log("Price impact USD:", result.priceImpactDeltaUsd);
// Limit order: pass explicit slippage tolerance (50 bps = 0.5%)
const limitResult = getAcceptablePriceInfo({
marketInfo,
isIncrease: true,
isLimit: true,
isLong: true,
indexPrice: 1800n \* 10n \*\* 30n,
sizeDeltaUsd: 10000n \* 10n \*\* 30n,
maxNegativePriceImpactBps: 50n,
});
\`\`\`
### getAcceptablePriceByPriceImpact
\`\`\`typescript
getAcceptablePriceByPriceImpact(p: {
isIncrease: boolean;
isLong: boolean;
indexPrice: bigint;
sizeDeltaUsd: bigint;
priceImpactDeltaUsd: bigint;
}): {
acceptablePrice: bigint;
acceptablePriceDeltaBps: bigint;
priceDelta: bigint;
}
\`\`\`
Converts a USD price impact into an acceptable price. The formula is:
\`\`\`
acceptablePrice = indexPrice × (sizeDeltaUsd + adjustedImpact) / sizeDeltaUsd
\`\`\`
where \`adjustedImpact\` flips the sign for longs versus shorts. Returns \`{ acceptablePrice: indexPrice, acceptablePriceDeltaBps: 0n, priceDelta: 0n }\` when \`sizeDeltaUsd\` is \`0\` or \`indexPrice\` is \`0n\`.
\`\`\`typescript
const { acceptablePrice, acceptablePriceDeltaBps, priceDelta } = getAcceptablePriceByPriceImpact({
isIncrease: true,
isLong: true,
indexPrice: 1800n \* 10n \*\* 30n,
sizeDeltaUsd: 10000n \* 10n \*\* 30n,
priceImpactDeltaUsd: -50n \* 10n \*\* 30n, // -$50 price impact
});
// acceptablePrice is slightly below indexPrice (worse for a long)
// acceptablePriceDeltaBps is the basis-point deviation from indexPrice
\`\`\`
### getDefaultAcceptablePriceImpactBps
\`\`\`typescript
getDefaultAcceptablePriceImpactBps(p: {
isIncrease: boolean;
isLong: boolean;
indexPrice: bigint;
sizeDeltaUsd: bigint;
priceImpactDeltaUsd: bigint;
acceptablePriceImapctBuffer?: number; // default: 30 (0.3%)
}): bigint
\`\`\`
Returns the recommended acceptable price impact in basis points for a given trade, including a safety buffer. The default buffer is \`30\` basis points (0.3%).
When \`priceImpactDeltaUsd\` is positive (favorable price impact), the function returns only the buffer. When it's negative, the function converts the impact to basis points and adds the buffer on top.
:::note
The parameter name \`acceptablePriceImapctBuffer\` contains a typo (\`Imapct\` instead of \`Impact\`). This matches the source code exactly and must be used as-is.
:::
\`\`\`typescript
const acceptableBps = getDefaultAcceptablePriceImpactBps({
isIncrease: true,
isLong: true,
indexPrice: 1800n \* 10n \*\* 30n,
sizeDeltaUsd: 10000n \* 10n \*\* 30n,
priceImpactDeltaUsd: -50n \* 10n \*\* 30n,
// acceptablePriceImapctBuffer: 30 // 30 bps buffer (default)
});
// Returns: |priceImpactBps| + 30
\`\`\`
### API data fetching
The prices module includes a utility for fetching OHLCV candle data from the GMX REST API. The public interface is the \`fetchOhlcv\` method on the \[\`GmxApiSdk\`\](../../../v2/readme.md) V2 client.
#### \`fetchOhlcv\` via \`GmxApiSdk\`
\`\`\`typescript
const apiSdk = new GmxApiSdk({ chainId: 42161 });
const candles: OhlcvCandle\[\] = await apiSdk.fetchOhlcv({
symbol: "BTC/USD",
timeframe: "1h",
limit: 100,
});
\`\`\`
The method sends a GET request to the \`/prices/ohlcv\` endpoint with the provided query parameters.
#### \`OhlcvParams\`
\`\`\`typescript
type OhlcvParams = {
symbol: string; // Trading pair, for example "BTC/USD"
timeframe: string; // Candle interval, for example "1h", "4h", "1d"
limit?: number; // Maximum number of candles to return
since?: number; // Unix timestamp to start from
};
\`\`\`
#### \`OhlcvCandle\`
Each candle in the returned array has this shape:
\`\`\`typescript
type OhlcvCandle = {
timestamp: number;
open: string;
high: string;
low: string;
close: string;
};
\`\`\`
The \`open\`, \`high\`, \`low\`, and \`close\` values are returned as strings.
:::note
The underlying \`fetchApiOhlcv\` function in \`utils/prices/api\` is not re-exported from \`@gmx-io/sdk/utils/prices\`. Use \`GmxApiSdk.fetchOhlcv()\` instead. The \`OhlcvCandle\` and \`OhlcvParams\` types are also available from \`@gmx-io/sdk/types/prices\`.
:::
---
## referrals
This module exports referral-code helpers and referral-related data types.
## Runtime exports
- \`MAX\_REFERRAL\_CODE\_LENGTH\`
- \`decodeReferralCode\`
- \`encodeReferralCode\`
## Re-exported types
- \`UserReferralInfo\`
- \`RebateDistributionType\`
- \`RebateDistribution\`
- \`CodeOwnershipInfo\`
- \`ReferralCodeStats\`
- \`AffiliateTotalStats\`
- \`TraderReferralTotalStats\`
- \`TierInfo\`
- \`ReferralsStats\`
- \`TotalReferralsStats\`
\`\`\`typescript
\`\`\`
---
## sidecarOrders
This module is a type-only re-export for sidecar stop-loss, take-profit, and limit-order entry shapes.
## Exports
- \`GroupPrefix\`
- \`EntryField\`
- \`InitialEntry\`
- \`SidecarOrderEntryBase\`
- \`SidecarSlTpOrderEntry\`
- \`SidecarSlTpOrderEntryValid\`
- \`SidecarLimitOrderEntry\`
- \`SidecarLimitOrderEntryValid\`
- \`SidecarOrderEntry\`
- \`SidecarOrderEntryGroupBase\`
- \`SidecarOrderEntryGroup\`
\`\`\`typescript
\`\`\`
---
## findReachableTokens
This module provides functionality to find all tokens that can be reached from each token in a markets graph through swap operations, respecting maximum path length constraints.
## Methods
The \`findReachableTokens\` function is exported from \`@gmx-io/sdk/utils/swap\`.
### findReachableTokens
\`\`\`typescript
findReachableTokens(graph: MarketsGraph): Record
\`\`\`
Performs a breadth-first search from every token in \`graph\` and returns a map of \`tokenAddress → reachableTokenAddresses\[\]\`. The search stops at \`MAX\_EDGE\_PATH\_LENGTH\` hops (currently \`3\`). Each token's own address is always included in its reachable set.
For most SDK use cases, prefer \`findAllReachableTokens(chainId, from)\` from \`@gmx-io/sdk/utils/swap\`, which provides an O(1) lookup using precomputed data. Use \`findReachableTokens\` directly when you've built a custom \`MarketsGraph\` with \`buildMarketsAdjacencyGraph\`.
\`\`\`typescript
// Build a custom graph (for example, to exclude certain markets)
const filteredMarketsMap = Object.fromEntries(
Object.entries(MARKETS\[42161\]).filter((\[addr\]) => addr !== excludedMarketAddress)
);
const graph = buildMarketsAdjacencyGraph(filteredMarketsMap);
// Compute reachability for all tokens in the custom graph
const reachableTokens = findReachableTokens(graph);
// reachableTokens\[wethAddress\] — all tokens reachable from WETH in ≤3 hops
// including wethAddress itself
\`\`\`
---
## findSwapPathsBetweenTokens
This module computes all valid intermediate-token sequences for swapping between any two tokens in a \`MarketsGraph\`. The result is a precomputed lookup table that swap routing uses to enumerate candidate routes.
## Methods
This module exports a single function that builds a full swap-path lookup table from a markets graph.
### findSwapPathsBetweenTokens
\`\`\`typescript
findSwapPathsBetweenTokens(graph: MarketsGraph): SwapPaths
\`\`\`
Runs a breadth-first search from every token in \`graph\` to every other token and returns a \`SwapPaths\` map. Each entry in the map is an array of intermediate-token paths: the sequence of tokens the swap passes through between the source and destination. A direct swap with no intermediate hops is represented as an empty array \`\[\]\`.
The search is bounded by \`MAX\_EDGE\_PATH\_LENGTH = 3\`, which limits the total number of market edges (hops) in any path. An intermediate-token list therefore contains at most 2 addresses.
Tokens with no reachable targets are omitted from the result.
#### Path pruning rules
\`findSwapPathsBetweenTokens\` applies two pruning rules during the search to discard routes that would almost always produce a loss:
1. \*\*Single-market A → B → A loop.\*\* If the path visits token \`X\`, then \`Y\`, then \`X\` again, and there is only one market between \`X\` and \`Y\`, the path is pruned. With a single market, the two legs incur price impact twice on the same pool, guaranteeing a net loss.
2. \*\*Consecutive same-token visit.\*\* If the last two tokens in the path are identical, the path is pruned as a degenerate loop.
Same-token swaps (for example, ETH → ETH) are valid when multiple markets connect that token to itself and the path includes at least one intermediate token.
#### Return type
\`\`\`typescript
type SwapPaths = {
\[fromToken: string\]: {
\[toToken: string\]: string\[\]\[\]; // array of intermediate-token sequences
};
};
\`\`\`
Each \`string\[\]\` entry is one candidate route described by its intermediate tokens. For a direct single-hop swap, the entry is \`\[\]\`. For a two-hop swap through USDC, the entry is \`\["0xUSDC"\]\`.
#### Example
\`\`\`typescript
const graph = buildMarketsAdjacencyGraph(MARKETS\[42161\]);
const swapPaths = findSwapPathsBetweenTokens(graph);
// Direct swap ETH → USDC and indirect via BTC
// swapPaths\[wethAddress\]\[usdcAddress\] might be:
// \[\[\], \["0xBTC..."\]\]
// ^ ^
// | two-hop: ETH → BTC → USDC
// direct: ETH → USDC
const routes = swapPaths\[wethAddress\]?.\[usdcAddress\] ?? \[\];
for (const intermediates of routes) {
if (intermediates.length === 0) {
console.log("Direct swap");
} else {
console.log("Via:", intermediates.join(" → "));
}
}
\`\`\`
:::note
\`findSwapPathsBetweenTokens\` returns the raw graph-level paths (intermediate tokens only). To evaluate which path gives the best output for a specific swap amount, pass these paths to \`getBestSwapPath\` from \[\`utils/swap/swapRouting\`\](./swapRouting.md), which applies live market data to score each route.
:::
:::note
For most use cases, use the pre-computed constants from \[\`utils/swap/preparedSwapData\`\](./preparedSwapData.md) instead: \`TOKEN\_SWAP\_PATHS\`, \`MARKETS\_ADJACENCY\_GRAPH\`, and \`REACHABLE\_TOKENS\` are built from \`findSwapPathsBetweenTokens\` at module load time and are optimized for repeated lookups.
:::
---
## preparedSwapData
This module provides pre-computed swap data structures for efficient token swapping operations across different chains. It contains adjacency graphs, swap paths, and reachable token mappings that are built at module initialization time from the static \`MARKETS\` configuration.
These constants are exported from \`@gmx-io/sdk/utils/swap\` (not as a separate sub-path).
## Constants
Three pre-computed constants are available, each keyed by chain ID.
### MARKETS\_ADJACENCY\_GRAPH
\`MARKETS\_ADJACENCY\_GRAPH: { \[chainId: number\]: MarketsGraph }\`
Pre-computed adjacency graph for each chain representing connections between tokens through shared markets. Built once at module load from \`MARKETS\`.
\`\`\`typescript
const arbitrumGraph = MARKETS\_ADJACENCY\_GRAPH\[42161\];
const wethConnections = arbitrumGraph\["0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"\];
\`\`\`
### TOKEN\_SWAP\_PATHS
\`TOKEN\_SWAP\_PATHS: { \[chainId: number\]: SwapPaths }\`
Pre-computed swap paths between all reachable token pairs for each chain. Built once at module load from \`MARKETS\_ADJACENCY\_GRAPH\`.
\`\`\`typescript
const arbitrumSwapPaths = TOKEN\_SWAP\_PATHS\[42161\];
const wethAddress = "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1";
const usdcAddress = "0xaf88d065e77c8cC2239327C5EDb3A432268e5831";
const swapPath = arbitrumSwapPaths\[wethAddress\]?.\[usdcAddress\];
\`\`\`
### REACHABLE\_TOKENS
\`REACHABLE\_TOKENS: { \[chainId: number\]: { \[token: string\]: string\[\] } }\`
Mapping of token addresses to all other tokens they can be reached from through swaps on each chain. Built once at module load.
\`\`\`typescript
const reachableFromWeth = REACHABLE\_TOKENS\[42161\]\["0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"\];
\`\`\`
---
## swap
This module provides utilities for calculating swap statistics and values in the GMX protocol. It includes functions for computing swap fees, price impact, and other swap-related metrics.
## Methods
The \`@gmx-io/sdk/utils/swap\` module re-exports all functions from its sub-modules. The table below maps each function group to its documentation page.
| Sub-module | Description |
| ------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- |
| \[\`swapPath\`\](./swapPath.md) | Path discovery: \`createFindSwapPath\`, \`getWrappedAddress\` |
| \[\`swapValues\`\](./swapValues.md) | Amount calculation: \`getSwapAmountsByFromValue\`, \`getSwapAmountsByToValue\`, \`getSwapPathComparator\` |
| \[\`swapStats\`\](./swapStats.md) | Fee and price impact stats per swap step |
| \[\`swapRouting\`\](./swapRouting.md) | Route selection: \`getBestSwapPath\`, naive pre-selection |
| \[\`findSwapPathsBetweenTokens\`\](./findSwapPathsBetweenTokens.md) | Graph traversal for all token-pair paths |
| \[\`findReachableTokens\`\](./findReachableTokens.md) | Reachability analysis from a source token |
| \[\`preparedSwapData\`\](./preparedSwapData.md) | Pre-computed constants: \`MARKETS\_ADJACENCY\_GRAPH\`, \`TOKEN\_SWAP\_PATHS\`, \`REACHABLE\_TOKENS\` |
---
## swapPath
This module provides utilities for finding optimal swap paths between tokens in the GMX protocol. It handles path discovery, liquidity analysis, and gas cost estimation to determine the most efficient routes for token swaps.
## Methods
The swapPath module exports a utility for address normalization and the main factory for building swap-path finders. Import any function directly from \`@gmx-io/sdk/utils/swap\`.
### getWrappedAddress
\`\`\`typescript
getWrappedAddress(chainId: number, address: string | undefined): string | undefined
\`\`\`
Converts a token address to its wrapped equivalent for the chain (for example, native ETH → WETH). Returns \`undefined\` when \`address\` is \`undefined\`.
\`\`\`typescript
const wrappedAddress = getWrappedAddress(42161, nativeTokenAddress);
// Returns WETH address for Arbitrum
\`\`\`
### createFindSwapPath
\`\`\`typescript
createFindSwapPath(params: {
chainId: number;
fromTokenAddress: string | undefined;
toTokenAddress: string | undefined;
marketsInfoData: MarketsInfoData | undefined;
gasEstimationParams?: {
gasPrice: bigint;
gasLimits: GasLimitsConfig;
tokensData: TokensData;
};
swapPricingType: SwapPricingType | undefined;
disabledMarkets?: string\[\];
manualPath?: string\[\];
}): FindSwapPath
\`\`\`
Creates a closure that finds the best swap path between two tokens. Call it once with the current market data, then call the returned \`FindSwapPath\` function for each input amount or sorting preference you want to evaluate.
The returned \`FindSwapPath\` function has the signature:
\`\`\`typescript
(usdIn: bigint, opts?: { order?: ("liquidity" | "length")\[\] }) => SwapPathStats | undefined;
\`\`\`
Results are cached per \`(usdIn, order)\` combination.
\*\*Routing logic:\*\*
- When \`manualPath\` is provided, the closure uses it directly and skips automatic routing.
- When \`opts.order\` is provided or \`usdIn === 0n\`, the closure uses the max-liquidity path (optionally filtered to shortest paths when \`order\[0\] === "length"\`).
- Otherwise, the closure runs the full two-phase routing: naive pre-selection followed by accurate scoring via \`getBestSwapPath\`.
When \`marketsInfoData\` is \`undefined\`, the returned function always returns \`undefined\`.
When \`swapPricingType\` is \`SwapPricingType.AtomicSwap\`, markets unavailable for Express Trading are automatically added to \`disabledMarkets\`.
:::note
The parameter is \`swapPricingType: SwapPricingType\` (an enum), not \`isExpressFeeSwap: boolean\` as earlier documentation stated.
:::
The returned \`SwapPathStats\` contains:
| Field | Type | Description |
| ------------------------------ | ------------- | ------------------------------------------- |
| \`swapPath\` | \`string\[\]\` | Market addresses in hop order |
| \`swapSteps\` | \`SwapStats\[\]\` | Per-hop stats (fees, price impact, amounts) |
| \`tokenInAddress\` | \`string\` | Input token address |
| \`tokenOutAddress\` | \`string\` | Output token address |
| \`usdOut\` | \`bigint\` | Estimated USD output (30-decimal) |
| \`amountOut\` | \`bigint\` | Estimated output token amount |
| \`totalSwapFeeUsd\` | \`bigint\` | Total fees in USD across all hops |
| \`totalSwapPriceImpactDeltaUsd\` | \`bigint\` | Total price impact in USD |
| \`totalFeesDeltaUsd\` | \`bigint\` | Combined fees and price impact |
\`\`\`typescript
const findSwapPath = createFindSwapPath({
chainId: 42161,
fromTokenAddress: wethAddress,
toTokenAddress: usdcAddress,
marketsInfoData,
gasEstimationParams: {
gasPrice: 1000000000n,
gasLimits,
tokensData,
},
swapPricingType: SwapPricingType.Swap,
});
// Find best path for a $1000 swap
const result = findSwapPath(1000n \* 10n \*\* 30n);
if (result) {
console.log("Market path:", result.swapPath);
console.log("USD out:", result.usdOut);
console.log("Total fees:", result.totalFeesDeltaUsd);
}
// Find highest-liquidity path (useful for showing available capacity)
const liquidityPath = findSwapPath(0n, { order: \["liquidity"\] });
\`\`\`
---
## 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
\`\`\`typescript
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.
\`\`\`typescript
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
\`\`\`typescript
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.
\`\`\`typescript
const getLiquidity = createMarketEdgeLiquidityGetter(marketsInfoData);
const edge = { marketAddress: "0xMarketAddress", from: "0xUSDC", to: "0xWETH" };
const availableLiquidity = getLiquidity(edge); // bigint in USD (30 decimals)
\`\`\`
#### createNaiveSwapEstimator
\`\`\`typescript
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.
\`\`\`typescript
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
\`\`\`typescript
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.
\`\`\`typescript
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
\`\`\`typescript
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.
\`\`\`typescript
createSwapEstimator,
createNaiveNetworkEstimator,
getBestSwapPath,
marketRouteToMarketEdges,
} from "@gmx-io/sdk/utils/swap";
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
\`\`\`typescript
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.
\`\`\`typescript
createNaiveSwapEstimator,
createNaiveNetworkEstimator,
getNaiveBestMarketSwapPathsFromTokenSwapPaths,
getTokenSwapPathsForTokenPairPrebuilt,
getMarketAdjacencyGraph,
} from "@gmx-io/sdk/utils/swap";
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
\`\`\`typescript
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.
\`\`\`typescript
const graph = getMarketAdjacencyGraph(42161);
const markets = getMarketsForTokenPair(graph, wethAddress, usdcAddress);
// markets: \["0xETH-USD-MarketAddress", ...\]
\`\`\`
#### getBestMarketForTokenEdge
\`\`\`typescript
getBestMarketForTokenEdge(params: {
marketAddresses: string\[\];
usdIn: bigint;
tokenInAddress: string;
tokenOutAddress: string;
estimator: NaiveSwapEstimator;
marketPath?: string\[\];
calculatedCache?: Record;
}): { 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.
\`\`\`typescript
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
\`\`\`typescript
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.
\`\`\`typescript
// 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
\`\`\`typescript
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).
\`\`\`typescript
// All intermediate-token paths from WETH to USDC
const paths = getTokenSwapPathsForTokenPair(tokenSwapPaths, wethAddress, usdcAddress);
// paths: \[\[\], \["0xWBTC"\], \["0xLINK", "0xWBTC"\]\] (direct, 1-hop, 2-hop)
\`\`\`
#### getTokenSwapPathsForTokenPairPrebuilt
\`\`\`typescript
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.
\`\`\`typescript
const paths = getTokenSwapPathsForTokenPairPrebuilt(42161, wethAddress, usdcAddress);
\`\`\`
#### getMarketAdjacencyGraph
\`\`\`typescript
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.
\`\`\`typescript
const graph = getMarketAdjacencyGraph(42161); // Arbitrum
// graph\["0xWETH"\]\["0xUSDC"\] → \["0xETH-USD-MarketAddress"\]
\`\`\`
#### findAllReachableTokens
\`\`\`typescript
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.
\`\`\`typescript
const reachable = findAllReachableTokens(42161, wethAddress);
// reachable: \["0xUSDC", "0xWBTC", "0xARB", ...\]
\`\`\`
#### getMaxLiquidityMarketSwapPathFromTokenSwapPaths
\`\`\`typescript
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.
\`\`\`typescript
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
\`\`\`typescript
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).
\`\`\`typescript
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)
\`\`\`
---
## swapStats
This module provides utilities for calculating swap statistics, capacity, and liquidity for token swaps within GMX markets. It includes functions for analyzing swap paths, calculating fees and price impacts, and determining available liquidity.
## Methods
The swapStats module exports functions for computing pool capacity, simulating swap paths, and calculating per-step swap statistics. Import any function directly from \`@gmx-io/sdk/utils/swap\`. When passing \`swapPricingType\`, use the \`SwapPricingType\` enum imported from \`@gmx-io/sdk/utils/orders\`.
### getSwapCapacityUsd
\`\`\`typescript
getSwapCapacityUsd(marketInfo: MarketInfo, isLong: boolean): bigint
\`\`\`
Returns the remaining swap capacity in USD for the specified pool side: \`convertToUsd(maxPoolAmount - poolAmount, token.decimals, getMidPrice(token.prices))\`.
\`\`\`typescript
const longCapacity = getSwapCapacityUsd(marketInfo, true); // long pool remaining capacity
const shortCapacity = getSwapCapacityUsd(marketInfo, false); // short pool remaining capacity
\`\`\`
### getSwapPathOutputAddresses
\`\`\`typescript
getSwapPathOutputAddresses(p: {
marketsInfoData: MarketsInfoData;
initialCollateralAddress: string;
swapPath: string\[\];
wrappedNativeTokenAddress: string;
shouldUnwrapNativeToken: boolean;
isIncrease: boolean;
}): { outTokenAddress: string | undefined; outMarketAddress: string | undefined }
\`\`\`
Determines the output token and market addresses for a given swap path by walking the path and following opposite-collateral pointers at each step.
When \`swapPath\` is empty: for increase operations the \`initialCollateralAddress\` is returned as-is (increase targets are always ERC-20); for decrease operations the address is returned, or \`NATIVE\_TOKEN\_ADDRESS\` if \`shouldUnwrapNativeToken\` and the token is the wrapped native token.
When any market in the path is not found, both fields are \`undefined\`.
\`\`\`typescript
const { outTokenAddress, outMarketAddress } = getSwapPathOutputAddresses({
marketsInfoData,
initialCollateralAddress: wethAddress,
swapPath: \[ethUsdcMarketAddress\],
wrappedNativeTokenAddress: wethAddress,
shouldUnwrapNativeToken: true,
isIncrease: false,
});
// outTokenAddress: NATIVE\_TOKEN\_ADDRESS (unwrapped ETH for decrease)
// outMarketAddress: ethUsdcMarketAddress
\`\`\`
### getSwapPathStats
\`\`\`typescript
getSwapPathStats(p: {
marketsInfoData: MarketsInfoData;
swapPath: string\[\];
initialCollateralAddress: string;
wrappedNativeTokenAddress: string;
usdIn: bigint;
shouldUnwrapNativeToken: boolean;
shouldApplyPriceImpact: boolean;
swapPricingType: SwapPricingType;
}): SwapPathStats | undefined
\`\`\`
Simulates a multi-step swap along \`swapPath\` and returns aggregate statistics. Returns \`undefined\` when \`swapPath\` is empty or any market in the path is not found.
The \`SwapPathStats\` return type:
| Field | Type | Description |
| ------------------------------ | --------------------- | ------------------------------------------------ |
| \`swapPath\` | \`string\[\]\` | Market addresses traversed |
| \`swapSteps\` | \`SwapStats\[\]\` | Per-step statistics |
| \`targetMarketAddress\` | \`string \\| undefined\` | Last market in path |
| \`tokenInAddress\` | \`string\` | Initial collateral address |
| \`tokenOutAddress\` | \`string\` | Final output token address |
| \`usdOut\` | \`bigint\` | Output value in USD (30-decimal) |
| \`amountOut\` | \`bigint\` | Output token amount (token decimals) |
| \`totalSwapFeeUsd\` | \`bigint\` | Sum of fees across all steps |
| \`totalSwapPriceImpactDeltaUsd\` | \`bigint\` | Sum of price impacts across all steps |
| \`totalFeesDeltaUsd\` | \`bigint\` | \`totalSwapPriceImpactDeltaUsd - totalSwapFeeUsd\` |
\`\`\`typescript
const pathStats = getSwapPathStats({
marketsInfoData,
swapPath: \[ethUsdcMarketAddress\],
initialCollateralAddress: wethAddress,
wrappedNativeTokenAddress: wethAddress,
usdIn: 1000n \* 10n \*\* 30n, // $1000 (30-decimal)
shouldUnwrapNativeToken: false,
shouldApplyPriceImpact: true,
swapPricingType: SwapPricingType.Swap,
});
if (pathStats) {
console.log("Total fee USD:", pathStats.totalSwapFeeUsd);
console.log("Amount out:", pathStats.amountOut);
console.log("USD out:", pathStats.usdOut);
}
\`\`\`
### getSwapStats
\`\`\`typescript
getSwapStats(p: {
marketInfo: MarketInfo;
tokenInAddress: string;
tokenOutAddress: string;
usdIn: bigint;
shouldApplyPriceImpact: boolean;
swapPricingType: SwapPricingType;
}): SwapStats
\`\`\`
Computes detailed statistics for a single swap step. Uses \`tokenIn.prices.minPrice\` for \`amountIn\` conversion and \`tokenOut.prices.maxPrice\` for \`amountOut\` conversion.
When \`getPriceImpactForSwap\` throws (market out of capacity), returns a zero-output \`SwapStats\` with \`isOutLiquidity: true\` and \`isOutCapacity\` set based on whether the pool capacity is exceeded.
The \`SwapStats\` return type:
| Field | Type | Description |
| --------------------- | ---------------------- | ------------------------------------------ |
| \`marketAddress\` | \`string\` | Market being swapped through |
| \`tokenInAddress\` | \`string\` | Input token address |
| \`tokenOutAddress\` | \`string\` | Output token address |
| \`isWrap\` | \`boolean\` | \`tokenInAddress === NATIVE\_TOKEN\_ADDRESS\` |
| \`isUnwrap\` | \`boolean\` | \`tokenOutAddress === NATIVE\_TOKEN\_ADDRESS\` |
| \`isOutLiquidity\` | \`boolean \\| undefined\` | Output exceeds available liquidity |
| \`isOutCapacity\` | \`boolean \\| undefined\` | Input exceeds pool capacity |
| \`amountIn\` | \`bigint\` | Input token amount |
| \`amountInAfterFees\` | \`bigint\` | Input amount after fee deduction |
| \`usdIn\` | \`bigint\` | Input USD value (30-decimal) |
| \`swapFeeAmount\` | \`bigint\` | Fee in input token units |
| \`swapFeeUsd\` | \`bigint\` | Fee in USD (30-decimal) |
| \`priceImpactDeltaUsd\` | \`bigint\` | Capped price impact (30-decimal) |
| \`amountOut\` | \`bigint\` | Output token amount |
| \`usdOut\` | \`bigint\` | Output USD value (30-decimal) |
\`\`\`typescript
const swapStats = getSwapStats({
marketInfo,
tokenInAddress: wethAddress,
tokenOutAddress: usdcAddress,
usdIn: 1000n \* 10n \*\* 30n, // $1000 (30-decimal)
shouldApplyPriceImpact: true,
swapPricingType: SwapPricingType.Swap,
});
console.log("Swap fee:", swapStats.swapFeeUsd);
console.log("Price impact:", swapStats.priceImpactDeltaUsd);
console.log("Amount out:", swapStats.amountOut);
console.log("Out of liquidity:", swapStats.isOutLiquidity);
\`\`\`
### getMaxSwapPathLiquidity
\`\`\`typescript
getMaxSwapPathLiquidity(p: {
marketsInfoData: MarketsInfoData;
swapPath: string\[\];
initialCollateralAddress: string;
}): bigint
\`\`\`
Returns the minimum available output liquidity across all steps in the swap path — the bottleneck that limits the maximum swap size. Returns \`0n\` when \`swapPath\` is empty or any market in the path is not found.
\`\`\`typescript
const maxLiquidity = getMaxSwapPathLiquidity({
marketsInfoData,
swapPath: \[ethUsdcMarketAddress\],
initialCollateralAddress: wethAddress,
});
// Compare against desired swap size before submitting
if (maxLiquidity < desiredUsdIn) {
console.warn("Swap exceeds available liquidity");
}
\`\`\`
---
## swapValues
This module provides utilities for calculating swap amounts and values for token exchanges in the GMX protocol. It handles both internal GMX swaps and external swap integrations, supporting limit orders and market orders with various optimization strategies.
## Methods
The module exports three functions for computing swap amounts and sorting swap routes.
### getSwapAmountsByFromValue
\`\`\`typescript
getSwapAmountsByFromValue(p: {
tokenIn: TokenData;
tokenOut: TokenData;
amountIn: bigint;
triggerRatio?: TokensRatio;
isLimit: boolean;
swapOptimizationOrder?: SwapOptimizationOrderArray;
allowedSwapSlippageBps?: bigint;
uiFeeFactor: bigint;
marketsInfoData: MarketsInfoData | undefined;
chainId: number;
externalSwapQuoteParams: ExternalSwapQuoteParams | undefined;
findSwapPath: FindSwapPath;
allowSameTokenSwap: boolean;
}): SwapAmounts
\`\`\`
Calculates \`SwapAmounts\` for a given input token amount. The returned \`SwapAmounts\` contains:
| Field | Type | Description |
| ----------------- | ------------------------------- | --------------------------------------- |
| \`amountIn\` | \`bigint\` | Input token amount |
| \`usdIn\` | \`bigint\` | Input value in USD (30-decimal) |
| \`amountOut\` | \`bigint\` | Expected output token amount |
| \`usdOut\` | \`bigint\` | Expected output value in USD |
| \`priceIn\` | \`bigint\` | Input token price used |
| \`priceOut\` | \`bigint\` | Output token price used |
| \`minOutputAmount\` | \`bigint\` | Minimum acceptable output amount |
| \`swapStrategy\` | \`SwapStrategyForIncreaseOrders\` | Internal/external swap strategy details |
For limit orders (\`isLimit: true\`), \`triggerRatio\` is required to compute the target output; without it the function returns zero-output amounts.
For wrap/unwrap operations, no swap path is needed and amounts are returned directly.
\`\`\`typescript
const swapAmounts = getSwapAmountsByFromValue({
tokenIn: wethToken,
tokenOut: usdcToken,
amountIn: 1n \* 10n \*\* 18n, // 1 WETH
isLimit: false,
uiFeeFactor: 0n,
marketsInfoData,
chainId: 42161,
externalSwapQuoteParams: undefined,
findSwapPath: myFindSwapPath,
allowSameTokenSwap: false,
});
console.log(swapAmounts.amountOut); // Expected USDC output
console.log(swapAmounts.minOutputAmount); // Minimum USDC (after fees)
\`\`\`
### getSwapAmountsByToValue
\`\`\`typescript
getSwapAmountsByToValue(p: {
tokenIn: TokenData;
tokenOut: TokenData;
amountOut: bigint;
triggerRatio?: TokensRatio;
isLimit: boolean;
swapOptimizationOrder?: SwapOptimizationOrderArray;
allowedSwapSlippageBps?: bigint;
uiFeeFactor: bigint;
marketsInfoData: MarketsInfoData | undefined;
chainId: number;
externalSwapQuoteParams: ExternalSwapQuoteParams | undefined;
findSwapPath: FindSwapPath;
allowSameTokenSwap: boolean;
}): SwapAmounts
\`\`\`
Calculates \`SwapAmounts\` for a desired output token amount. Determines how much input is required to receive \`amountOut\`. Returns the same \`SwapAmounts\` structure as \`getSwapAmountsByFromValue\`.
\`\`\`typescript
const swapAmounts = getSwapAmountsByToValue({
tokenIn: wethToken,
tokenOut: usdcToken,
amountOut: 2000n \* 10n \*\* 6n, // 2000 USDC
isLimit: false,
uiFeeFactor: 0n,
marketsInfoData,
chainId: 42161,
externalSwapQuoteParams: undefined,
findSwapPath: myFindSwapPath,
allowSameTokenSwap: false,
});
console.log(swapAmounts.amountIn); // Required WETH input
\`\`\`
### getSwapPathComparator
\`\`\`typescript
getSwapPathComparator(order?: SwapOptimizationOrderArray): (a: SwapRoute, b: SwapRoute) => number
\`\`\`
Returns a comparator function for sorting \`SwapRoute\` objects. The sort criteria are applied in order:
- \`"liquidity"\` — sort by \`route.liquidity\` descending (higher is better)
- \`"length"\` — sort by \`route.path.length\` ascending (shorter is better)
When \`order\` is \`undefined\` or empty, the comparator returns \`0\` for all pairs (stable, no-op sort).
\`\`\`typescript
const comparator = getSwapPathComparator(\["liquidity", "length"\]);
const sorted = swapRoutes.sort(comparator);
// sorted\[0\] — highest liquidity; ties broken by shortest path
\`\`\`
---
## time
This module exports simple period-conversion helpers.
## Exports
- \`secondsFrom\`
- \`secondsToPeriod\`
- \`periodToSeconds\`
- \`nowInSeconds\`
\`\`\`typescript
\`\`\`
---
## tokens(Utils)
This module provides utilities for token price conversions, amount calculations, and token relationship operations in the GMX protocol. It handles conversions between USD values and token amounts, price formatting for contracts, and various token comparison utilities.
## Methods
The \`tokens\` utility module exports functions for price format conversions, token amount calculations, token data lookups, relationship checks, and ratio utilities.
### Price conversions
#### parseContractPrice
\`\`\`typescript
parseContractPrice(price: bigint, tokenDecimals: number): bigint
\`\`\`
Converts a contract-format price (\`price × 10^tokenDecimals\`) to a 30-decimal SDK price (\`price × 10^30\`). Internally: \`price × expandDecimals(1, tokenDecimals)\`.
\`\`\`typescript
const sdkPrice = parseContractPrice(contractPrice, 18);
\`\`\`
#### convertToContractPrice
\`\`\`typescript
convertToContractPrice(price: bigint, tokenDecimals: number): ContractPrice
\`\`\`
Converts a 30-decimal SDK price to contract format by dividing by \`10^tokenDecimals\`.
\`\`\`typescript
const contractPrice = convertToContractPrice(1800n \* 10n \*\* 30n, 18);
\`\`\`
#### convertToContractTokenPrices
\`\`\`typescript
convertToContractTokenPrices(prices: TokenPrices, tokenDecimals: number): { min: ContractPrice; max: ContractPrice }
\`\`\`
Converts both \`minPrice\` and \`maxPrice\` from 30-decimal SDK format to contract format.
\`\`\`typescript
const contractPrices = convertToContractTokenPrices({ minPrice: 1800n \* 10n \*\* 30n, maxPrice: 1802n \* 10n \*\* 30n }, 18);
\`\`\`
#### getMidPrice
\`\`\`typescript
getMidPrice(prices: TokenPrices): bigint
\`\`\`
Returns \`(minPrice + maxPrice) / 2\`.
\`\`\`typescript
const midPrice = getMidPrice({ minPrice: 1800n \* 10n \*\* 30n, maxPrice: 1802n \* 10n \*\* 30n });
\`\`\`
### Token amount conversions
#### convertToTokenAmount
\`\`\`typescript
convertToTokenAmount(
usd: bigint | undefined,
tokenDecimals: number | undefined,
price: bigint | undefined
): bigint | undefined
\`\`\`
Converts a USD value (30-decimal) to a token amount. Returns \`undefined\` when any argument is \`undefined\` or \`price <= 0\`.
\`\`\`typescript
const wethAmount = convertToTokenAmount(
1000n \* 10n \*\* 30n, // $1000 USD
18, // WETH decimals
1800n \* 10n \*\* 30n // WETH price
);
// ≈ 0.556 WETH in 18-decimal units
\`\`\`
#### convertToUsd
\`\`\`typescript
convertToUsd(
tokenAmount: bigint | undefined,
tokenDecimals: number | undefined,
price: bigint | undefined
): bigint | undefined
\`\`\`
Converts a token amount to USD (30-decimal). Returns \`undefined\` when any argument is \`undefined\`.
\`\`\`typescript
const usdValue = convertToUsd(
5n \* 10n \*\* 17n, // 0.5 WETH
18,
1800n \* 10n \*\* 30n // WETH price
);
// $900 as 30-decimal bigint
\`\`\`
#### convertBetweenTokens
\`\`\`typescript
convertBetweenTokens(
tokenAmount: bigint | undefined,
fromToken: TokenData | undefined,
toToken: TokenData | undefined,
maximize: boolean
): bigint | undefined
\`\`\`
Converts \`tokenAmount\` of \`fromToken\` to an equivalent amount of \`toToken\`. Returns \`tokenAmount\` directly when the two tokens are equivalent.
When \`maximize\` is \`true\`, uses \`fromToken.prices.maxPrice\` and \`toToken.prices.minPrice\` (maximizes value received). When \`false\`, uses \`fromToken.prices.minPrice\` and \`toToken.prices.maxPrice\` (minimizes value received, conservative estimate).
\`\`\`typescript
// Estimate how much USDC you get for 1 WETH (maximize=false → conservative)
const usdcAmount = convertBetweenTokens(1n \* 10n \*\* 18n, wethTokenData, usdcTokenData, false);
\`\`\`
### Token data lookups
#### getTokenData
\`\`\`typescript
getTokenData(
tokensData?: TokensData,
address?: string,
convertTo?: "wrapped" | "native"
): TokenData | undefined
\`\`\`
Looks up a token by address in \`tokensData\`. When \`convertTo\` is provided, follows the token's \`wrappedAddress\` or \`nativeTokenAddress\` pointer before returning.
\`\`\`typescript
const wethData = getTokenData(tokensData, nativeEthAddress, "wrapped");
const nativeData = getTokenData(tokensData, wethAddress, "native");
\`\`\`
#### getGmToken
\`\`\`typescript
getGmToken(chainId: ContractsChainId, marketTokenAddress: string): Token
\`\`\`
Returns a \`Token\` for a GM pool token by cloning the GM stub token and replacing its address with \`marketTokenAddress\`.
\`\`\`typescript
const gmToken = getGmToken(42161, marketTokenAddress);
\`\`\`
#### getGlvToken
\`\`\`typescript
getGlvToken(chainId: ContractsChainId, glvTokenAddress: string): Token
\`\`\`
Returns a \`Token\` for a GLV vault token by cloning the GLV stub token and replacing its address with \`glvTokenAddress\`.
\`\`\`typescript
const glvToken = getGlvToken(42161, glvTokenAddress);
\`\`\`
### Token relationship checks
#### getIsEquivalentTokens
\`\`\`typescript
getIsEquivalentTokens(token1: Token, token2: Token): boolean
\`\`\`
Returns \`true\` when the tokens are interchangeable: same address, a native/wrapped pair, or two synthetic tokens with the same symbol.
\`\`\`typescript
getIsEquivalentTokens(nativeEthToken, wethToken); // true
\`\`\`
#### getIsWrap / getIsUnwrap / getIsStake / getIsUnstake
\`\`\`typescript
getIsWrap(token1: Token, token2: Token): boolean
getIsUnwrap(token1: Token, token2: Token): boolean
getIsStake(token1: Token, token2: Token): boolean
getIsUnstake(token1: Token, token2: Token): boolean
\`\`\`
Classify a token-pair operation as wrap (native → wrapped), unwrap (wrapped → native), stake (native or wrapped → staking token), or unstake (staking token → wrapped). Used by swap routing to short-circuit path selection for these special cases.
\`\`\`typescript
getIsWrap(nativeEthToken, wethToken); // true
getIsUnwrap(wethToken, nativeEthToken); // true
\`\`\`
### Ratio utilities
#### getTokensRatioByPrice
\`\`\`typescript
getTokensRatioByPrice(p: {
fromToken: Token;
toToken: Token;
fromPrice: bigint;
toPrice: bigint;
}): TokensRatio
\`\`\`
Computes a \`TokensRatio\` (exchange rate and which token is "largest") from two prices.
\`\`\`typescript
const ratio = getTokensRatioByPrice({
fromToken: wethToken,
toToken: usdcToken,
fromPrice: 1800n \* 10n \*\* 30n,
toPrice: 1n \* 10n \*\* 30n,
});
\`\`\`
#### getTokensRatioByAmounts
\`\`\`typescript
getTokensRatioByAmounts(p: {
fromToken: Token;
toToken: Token;
fromTokenAmount: bigint;
toTokenAmount: bigint;
}): TokensRatio
\`\`\`
Computes a \`TokensRatio\` from two token amounts.
\`\`\`typescript
const ratio = getTokensRatioByAmounts({
fromToken: wethToken,
toToken: usdcToken,
fromTokenAmount: 1n \* 10n \*\* 18n,
toTokenAmount: 1800n \* 10n \*\* 6n,
});
\`\`\`
#### getTokensRatioByMinOutputAmountAndTriggerPrice
\`\`\`typescript
getTokensRatioByMinOutputAmountAndTriggerPrice(p: {
fromToken: Token;
toToken: Token;
fromTokenAmount: bigint;
toTokenAmount: bigint;
triggerPrice: bigint;
minOutputAmount: bigint;
}): TokensRatioAndSlippage
\`\`\`
Extends \`getTokensRatioByAmounts\` to also compute the allowed slippage in basis points based on the trigger price and minimum output amount.
\`\`\`typescript
const ratioAndSlippage = getTokensRatioByMinOutputAmountAndTriggerPrice({
fromToken: wethToken,
toToken: usdcToken,
fromTokenAmount: 1n \* 10n \*\* 18n,
toTokenAmount: 1800n \* 10n \*\* 6n,
triggerPrice: 1800n \* 10n \*\* 30n,
minOutputAmount: 1790n \* 10n \*\* 6n, // 1790 USDC minimum
});
\`\`\`
#### getAmountByRatio
\`\`\`typescript
getAmountByRatio(p: {
fromToken: Token;
toToken: Token;
fromTokenAmount: bigint;
ratio: bigint;
shouldInvertRatio?: boolean;
allowedSwapSlippageBps?: bigint;
}): bigint
\`\`\`
Converts \`fromTokenAmount\` to a target-token amount using a pre-computed \`TokensRatio.ratio\`. Pass \`allowedSwapSlippageBps\` to reduce the output by a slippage tolerance.
\`\`\`typescript
const usdcOut = getAmountByRatio({
fromToken: wethToken,
toToken: usdcToken,
fromTokenAmount: 1n \* 10n \*\* 18n,
ratio: triggerRatio.ratio,
shouldInvertRatio: triggerRatio.largestToken.address === usdcToken.address,
allowedSwapSlippageBps: 50n, // 0.5% slippage
});
\`\`\`
---
## decrease
This module provides utilities for calculating decrease position amounts, fees, and next position values when closing or reducing trading positions. It handles complex calculations including PnL realization, fee deductions, collateral adjustments, and swap requirements.
## Methods
The decrease trade module exports functions for computing position close amounts, determining full-close conditions, calculating collateral costs, and projecting the next position state. Import any function directly from \`@gmx-io/sdk/utils/trade\`.
### getDecreasePositionAmounts
\`\`\`typescript
getDecreasePositionAmounts(p: {
marketInfo: MarketInfo;
collateralToken: TokenData;
isLong: boolean;
position: PositionInfoLoaded | undefined;
closeSizeUsd: bigint;
keepLeverage: boolean;
triggerPrice?: bigint;
fixedAcceptablePriceImpactBps?: bigint;
acceptablePriceImpactBuffer?: number;
userReferralInfo: UserReferralInfo | undefined;
minCollateralUsd: bigint;
minPositionSizeUsd: bigint;
uiFeeFactor: bigint;
isLimit?: boolean;
limitPrice?: bigint;
triggerOrderType?: DecreasePositionAmounts\["triggerOrderType"\];
isSetAcceptablePriceImpactEnabled: boolean;
receiveToken?: TokenData;
}): DecreasePositionAmounts
\`\`\`
Computes a complete \`DecreasePositionAmounts\` result for a Market Decrease, Limit Decrease, Stop-Loss, or Take-Profit order. The result includes all pricing, fee, PnL, collateral, and receive-amount fields needed to build the on-chain order.
When \`position\` is \`undefined\` or has zero size, only the fee and price fields are computed; amounts relating to PnL and collateral are left at zero.
When \`receiveToken\` is omitted, it defaults to \`collateralToken\`.
\`\`\`typescript
const decreaseAmounts = getDecreasePositionAmounts({
marketInfo,
collateralToken: usdcToken,
isLong: true,
position: currentPosition,
closeSizeUsd: 1000n \* 10n \*\* 30n, // close $1000 of position
keepLeverage: false,
userReferralInfo: undefined,
minCollateralUsd: 5000n \* 10n \*\* 30n,
minPositionSizeUsd: 1000n \* 10n \*\* 30n,
uiFeeFactor: 0n,
isSetAcceptablePriceImpactEnabled: true,
});
console.log("Receive token amount:", decreaseAmounts.receiveTokenAmount);
console.log("Receive USD:", decreaseAmounts.receiveUsd);
console.log("Realized PnL:", decreaseAmounts.realizedPnl);
console.log("Position fee:", decreaseAmounts.positionFeeUsd);
console.log("Acceptable price:", decreaseAmounts.acceptablePrice);
\`\`\`
### getIsFullClose
\`\`\`typescript
getIsFullClose(p: {
position: PositionInfoLoaded;
sizeDeltaUsd: bigint;
indexPrice: bigint;
remainingCollateralUsd: bigint;
minCollateralUsd: bigint;
minPositionSizeUsd: bigint;
}): boolean
\`\`\`
Returns \`true\` when the decrease must be treated as a full close. This happens when:
- The remaining position size would be \`< $1\` after the decrease, or
- A loss would leave the remaining collateral below the minimum factor threshold, and the remaining collateral + PnL is below \`minCollateralUsd\` or the remaining size is below \`minPositionSizeUsd\`.
\`\`\`typescript
const isFullClose = getIsFullClose({
position: currentPosition,
sizeDeltaUsd: 500n \* 10n \*\* 30n,
indexPrice: currentPosition.markPrice,
remainingCollateralUsd: 100n \* 10n \*\* 30n,
minCollateralUsd: 5000n \* 10n \*\* 30n,
minPositionSizeUsd: 1000n \* 10n \*\* 30n,
});
\`\`\`
### getMinCollateralUsdForLeverage
\`\`\`typescript
getMinCollateralUsdForLeverage(position: PositionInfoLoaded, openInterestDelta: bigint): bigint
\`\`\`
Returns the minimum collateral required to keep the current position's leverage within the market's allowed range, given an open interest change.
\`\`\`typescript
const minCollateral = getMinCollateralUsdForLeverage(
currentPosition,
-1000n \* 10n \*\* 30n // OI decreasing by $1000
);
\`\`\`
### payForCollateralCost
\`\`\`typescript
payForCollateralCost(p: {
initialCostUsd: bigint;
collateralToken: TokenData;
collateralPrice: bigint;
outputAmount: bigint;
remainingCollateralAmount: bigint;
}): {
outputAmount: bigint;
remainingCollateralAmount: bigint;
paidOutputAmount: bigint;
paidRemainingCollateralAmount: bigint;
}
\`\`\`
Deducts \`initialCostUsd\` from \`outputAmount\` first, then from \`remainingCollateralAmount\`. Returns the updated balances and the amounts paid from each source.
\`\`\`typescript
const result = payForCollateralCost({
initialCostUsd: 100n \* 10n \*\* 30n,
collateralToken: usdcToken,
collateralPrice: 1n \* 10n \*\* 30n, // $1 per USDC
outputAmount: 50\_000\_000n, // 50 USDC (6 decimals)
remainingCollateralAmount: 1\_000\_000\_000n,
});
// result.paidOutputAmount — deducted from output
// result.paidRemainingCollateralAmount — deducted from remaining collateral
\`\`\`
### estimateCollateralCost
\`\`\`typescript
estimateCollateralCost(baseUsd: bigint, collateralToken: TokenData, collateralPrice: bigint): {
amount: bigint;
usd: bigint;
}
\`\`\`
Converts \`baseUsd\` to the collateral token's amount using \`collateralToken.prices.minPrice\`, then converts back to USD using \`collateralPrice\`. Used to estimate costs denominated in the collateral token.
\`\`\`typescript
const { amount, usd } = estimateCollateralCost(
50n \* 10n \*\* 30n, // $50
usdcToken,
1n \* 10n \*\* 30n // $1 per USDC
);
// amount: token units of the cost
// usd: cost in USD at collateralPrice
\`\`\`
### getTotalFeesUsdForDecrease
\`\`\`typescript
getTotalFeesUsdForDecrease(p: {
positionFeeUsd: bigint;
borrowingFeeUsd: bigint;
fundingFeeUsd: bigint;
swapProfitFeeUsd: bigint;
swapUiFeeUsd: bigint;
uiFeeUsd: bigint;
pnlUsd: bigint;
totalPendingImpactDeltaUsd: bigint;
}): bigint
\`\`\`
Returns the total cost that must be covered by the position's output. Only negative contributions are counted: a negative \`pnlUsd\` (loss) and a negative \`totalPendingImpactDeltaUsd\` (adverse price impact) are added as absolute values.
\`\`\`typescript
const totalCost = getTotalFeesUsdForDecrease({
positionFeeUsd: 10n \* 10n \*\* 30n,
borrowingFeeUsd: 5n \* 10n \*\* 30n,
fundingFeeUsd: 2n \* 10n \*\* 30n,
swapProfitFeeUsd: 1n \* 10n \*\* 30n,
swapUiFeeUsd: 0n,
uiFeeUsd: 0n,
pnlUsd: -10n \* 10n \*\* 30n, // $10 loss is added to total cost
totalPendingImpactDeltaUsd: -5n \* 10n \*\* 30n, // negative impact is added
});
// totalCost = 10 + 5 + 2 + 1 + 10 + 5 = $33
\`\`\`
### getNextPositionValuesForDecreaseTrade
\`\`\`typescript
getNextPositionValuesForDecreaseTrade(p: {
existingPosition?: PositionInfo;
marketInfo: MarketInfo;
collateralToken: TokenData;
sizeDeltaUsd: bigint;
sizeDeltaInTokens: bigint;
realizedPnl: bigint;
estimatedPnl: bigint;
collateralDeltaUsd: bigint;
collateralDeltaAmount: bigint;
payedRemainingCollateralUsd: bigint;
payedRemainingCollateralAmount: bigint;
proportionalPendingImpactDeltaUsd: bigint;
showPnlInLeverage: boolean;
isLong: boolean;
minCollateralUsd: bigint;
userReferralInfo: UserReferralInfo | undefined;
}): NextPositionValues
\`\`\`
Computes the projected position state after a decrease: remaining size, collateral, leverage, PnL percentage, and liquidation price. Use this to populate UI previews before order submission.
\`\`\`typescript
const nextValues = getNextPositionValuesForDecreaseTrade({
existingPosition: currentPosition,
marketInfo,
collateralToken: usdcToken,
sizeDeltaUsd: decreaseAmounts.sizeDeltaUsd,
sizeDeltaInTokens: decreaseAmounts.sizeDeltaInTokens,
realizedPnl: decreaseAmounts.realizedPnl,
estimatedPnl: decreaseAmounts.estimatedPnl,
collateralDeltaUsd: decreaseAmounts.collateralDeltaUsd,
collateralDeltaAmount: decreaseAmounts.collateralDeltaAmount,
payedRemainingCollateralUsd: decreaseAmounts.payedRemainingCollateralUsd,
payedRemainingCollateralAmount: decreaseAmounts.payedRemainingCollateralAmount,
proportionalPendingImpactDeltaUsd: decreaseAmounts.proportionalPendingImpactDeltaUsd,
showPnlInLeverage: true,
isLong: true,
minCollateralUsd: 5000n \* 10n \*\* 30n,
userReferralInfo: undefined,
});
console.log("Next size:", nextValues.nextSizeUsd);
console.log("Next leverage:", nextValues.nextLeverage);
console.log("Next liq price:", nextValues.nextLiqPrice);
\`\`\`
---
## increase
This module provides utilities for calculating increase position amounts, prices, and next position values for GMX trading operations. It handles different trading strategies including leverage by size, leverage by collateral, and independent position management.
## Methods
This module exports functions for computing the full set of amounts required to open or increase a leveraged position. All USD values use 30-decimal precision (\`USD\_DECIMALS = 30\`). Leverage values use basis-point encoding (10,000 = 1x, so 20x = \`200000n\`).
:::note
All functions in this module are exported from \`@gmx-io/sdk/utils/trade\`. Import them individually as shown in each example.
:::
### getIncreasePositionAmounts
\`\`\`typescript
getIncreasePositionAmounts(params: IncreasePositionParams): IncreasePositionAmounts
\`\`\`
Computes the complete set of amounts needed to open or increase a leveraged position. This is the primary function to call when constructing an increase order — it calculates size, collateral, fees (position fee, borrow fee, funding fee, UI fee), price impact, acceptable price, and any required collateral swap.
The function supports three strategies:
| Strategy | Input required | Description |
| ------------------------ | --------------------------------------------------- | --------------------------------------------------------------------------------------- |
| \`"leverageByCollateral"\` | \`initialCollateralAmount\` + \`leverage\` | User specifies how much collateral to deposit; size is derived from the leverage target |
| \`"leverageBySize"\` | \`indexTokenAmount\` + \`leverage\` | User specifies position size in tokens; collateral is derived from the leverage target |
| \`"independent"\` | \`indexTokenAmount\` and/or \`initialCollateralAmount\` | Size and collateral are set independently; leverage is computed from the result |
The acceptable price is computed automatically. For limit orders, the default acceptable price impact buffer is 30 bps (0.3%) unless overridden by \`fixedAcceptablePriceImpactBps\` or \`acceptablePriceImpactBuffer\`.
\*\*Parameters:\*\*
| Parameter | Type | Required | Description |
| ----------------------------------- | ---------------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------- |
| \`marketInfo\` | \`MarketInfo\` | Yes | Target market |
| \`indexToken\` | \`TokenData\` | Yes | Index token for the position |
| \`initialCollateralToken\` | \`TokenData\` | Yes | Token the user deposits (may differ from \`collateralToken\` if a swap is needed) |
| \`collateralToken\` | \`TokenData\` | Yes | Final collateral token used by the position after any swap |
| \`isLong\` | \`boolean\` | Yes | \`true\` for long, \`false\` for short |
| \`strategy\` | \`"leverageBySize" \\| "leverageByCollateral" \\| "independent"\` | Yes | Size calculation strategy |
| \`findSwapPath\` | \`FindSwapPath\` | Yes | Function for resolving collateral swap paths |
| \`uiFeeFactor\` | \`bigint\` | Yes | UI fee factor (30-decimal fraction) |
| \`chainId\` | \`number\` | Yes | Chain ID (for example, \`42161\` for Arbitrum) |
| \`isSetAcceptablePriceImpactEnabled\` | \`boolean\` | Yes | When \`false\`, acceptable price is set to \`maxUint256\` (longs) or \`0\` (shorts) for limit orders |
| \`initialCollateralAmount\` | \`bigint \\| undefined\` | Conditional | Required for \`"leverageByCollateral"\` and \`"independent"\` |
| \`indexTokenAmount\` | \`bigint \\| undefined\` | Conditional | Required for \`"leverageBySize"\` and \`"independent"\` |
| \`leverage\` | \`bigint \\| undefined\` | Conditional | Required for \`"leverageBySize"\` and \`"leverageByCollateral"\` (basis points: \`200000n\` = 20x) |
| \`position\` | \`PositionInfo \\| undefined\` | No | Existing position — used to pull pending borrow and funding fees |
| \`triggerPrice\` | \`bigint \\| undefined\` | No | Trigger price for limit orders (30-decimal precision) |
| \`limitOrderType\` | \`OrderType.LimitIncrease \\| OrderType.StopIncrease \\| undefined\` | No | Set for limit and stop-market orders |
| \`fixedAcceptablePriceImpactBps\` | \`bigint \\| undefined\` | No | Override the recommended acceptable price impact buffer |
| \`acceptablePriceImpactBuffer\` | \`number \\| undefined\` | No | Additional buffer on top of estimated impact (default: \`30\` bps = 0.3%) |
| \`userReferralInfo\` | \`UserReferralInfo \\| undefined\` | No | Referral data for position fee discount |
| \`marketsInfoData\` | \`MarketsInfoData \\| undefined\` | No | All markets data, used for finding swap paths |
| \`externalSwapQuote\` | \`ExternalSwapQuote \\| undefined\` | No | Pre-computed quote from an external aggregator; skips internal swap path finding |
| \`externalSwapQuoteParams\` | \`ExternalSwapQuoteParams \\| undefined\` | No | Parameters for external swap quotes |
\*\*Returns:\*\* \`IncreasePositionAmounts\` — includes \`sizeDeltaUsd\`, \`collateralDeltaUsd\`, \`positionFeeUsd\`, \`borrowingFeeUsd\`, \`fundingFeeUsd\`, \`uiFeeUsd\`, \`acceptablePrice\`, \`positionPriceImpactDeltaUsd\`, and more.
\`\`\`typescript
// Open a 20x long ETH position with 1 USDC collateral
const amounts = getIncreasePositionAmounts({
marketInfo,
indexToken: ethToken,
initialCollateralToken: usdcToken,
collateralToken: usdcToken,
isLong: true,
initialCollateralAmount: 1\_000000n, // 1 USDC (6 decimals)
leverage: 200000n, // 20x (200000 / 10000)
strategy: "leverageByCollateral",
findSwapPath,
uiFeeFactor: 0n,
chainId: 42161,
marketsInfoData,
externalSwapQuote: undefined,
externalSwapQuoteParams: undefined,
position: undefined,
userReferralInfo: undefined,
isSetAcceptablePriceImpactEnabled: true,
});
console.log("Size (USD):", amounts.sizeDeltaUsd);
console.log("Collateral (USD):", amounts.collateralDeltaUsd);
console.log("Position fee (USD):", amounts.positionFeeUsd);
console.log("Acceptable price:", amounts.acceptablePrice);
console.log("Price impact (USD):", amounts.positionPriceImpactDeltaUsd);
\`\`\`
### getTokensRatio
\`\`\`typescript
getTokensRatio(params: {
fromToken: TokenData;
toToken: TokenData;
triggerRatioValue: bigint;
markPrice: bigint;
}): { markRatio: TokensRatio; triggerRatio?: TokensRatio }
\`\`\`
Computes the mark ratio and (optionally) the trigger ratio between two tokens. Use this when displaying or computing trigger order prices expressed as a token-to-token ratio (for example, "sell ETH when it reaches 2000 USDC").
The \`fromToken\` price used is always \`fromToken.prices.minPrice\`. The \`markPrice\` parameter is the current mark price of \`toToken\` in terms of \`fromToken\` (for example, USDC per ETH).
| Parameter | Type | Description |
| ------------------- | ----------- | ------------------------------------------------------------------------------ |
| \`fromToken\` | \`TokenData\` | Source token (for example, ETH for an ETH/USDC pair) |
| \`toToken\` | \`TokenData\` | Target token (for example, USDC) |
| \`triggerRatioValue\` | \`bigint\` | User-specified trigger ratio; if \`0n\` or undefined, defaults to the mark ratio |
| \`markPrice\` | \`bigint\` | Current mark price of \`toToken\` per \`fromToken\` |
\`\`\`typescript
// Set a trigger to sell ETH when it reaches 2000 USDC; current mark is 1950 USDC
const ratios = getTokensRatio({
fromToken: ethToken,
toToken: usdcToken,
triggerRatioValue: 2\_000000000000000000000n, // 2000 USDC per ETH (token-precision scaled)
markPrice: 1\_950000000000000000000n, // 1950 USDC per ETH
});
console.log("Mark ratio:", ratios.markRatio.ratio);
console.log("Trigger ratio:", ratios.triggerRatio?.ratio);
// triggerRatio is undefined when triggerRatioValue is 0n or undefined
\`\`\`
### leverageBySizeValues
\`\`\`typescript
leverageBySizeValues(params: {
collateralToken: TokenData;
leverage: bigint;
sizeDeltaUsd: bigint;
collateralPrice: bigint;
uiFeeFactor: bigint;
positionFeeUsd: bigint;
borrowingFeeUsd: bigint;
uiFeeUsd: bigint;
swapUiFeeUsd: bigint;
fundingFeeUsd: bigint;
}): {
collateralDeltaUsd: bigint;
collateralDeltaAmount: bigint;
baseCollateralUsd: bigint;
baseCollateralAmount: bigint;
}
\`\`\`
Calculates the collateral requirements for the \`"leverageBySize"\` strategy, where the user specifies a position size and the required collateral is derived from the leverage target. The \`collateralDeltaUsd\` is \`sizeDeltaUsd / leverage\`, and \`baseCollateralUsd\` adds all fees on top.
This function is a building block used internally by \`getIncreasePositionAmounts\`. You may also call it directly when you need just the collateral breakdown without constructing a full order.
| Parameter | Type | Description |
| ----------------- | ----------- | ------------------------------------------------------------ |
| \`collateralToken\` | \`TokenData\` | Collateral token for token-amount conversion |
| \`leverage\` | \`bigint\` | Target leverage in basis points (\`200000n\` = 20x) |
| \`sizeDeltaUsd\` | \`bigint\` | Desired position size increase in USD (30-decimal precision) |
| \`collateralPrice\` | \`bigint\` | Collateral token price in USD (30-decimal precision) |
| \`uiFeeFactor\` | \`bigint\` | UI fee factor (present in the type; not used in calculation) |
| \`positionFeeUsd\` | \`bigint\` | Position fee in USD |
| \`borrowingFeeUsd\` | \`bigint\` | Pending borrow fee in USD |
| \`uiFeeUsd\` | \`bigint\` | UI fee in USD |
| \`swapUiFeeUsd\` | \`bigint\` | Swap UI fee in USD |
| \`fundingFeeUsd\` | \`bigint\` | Pending funding fee in USD |
\`\`\`typescript
// 20x long with $20 size (USD, 30-decimal): collateral should be ~$1
const values = leverageBySizeValues({
collateralToken: usdcToken,
leverage: 200000n, // 20x
sizeDeltaUsd: 20\_000000000000000000000000000000n, // $20
collateralPrice: 1\_000000000000000000000000000000n, // $1 per USDC
uiFeeFactor: 0n,
positionFeeUsd: 10000000000000000000000000000n, // $0.01 position fee
borrowingFeeUsd: 0n,
uiFeeUsd: 0n,
swapUiFeeUsd: 0n,
fundingFeeUsd: 0n,
});
console.log("Collateral delta (USD):", values.collateralDeltaUsd); // ~$1
console.log("Base collateral (USD):", values.baseCollateralUsd); // ~$1 + fees
console.log("Collateral amount (tokens):", values.collateralDeltaAmount);
\`\`\`
### getIncreasePositionPrices
\`\`\`typescript
getIncreasePositionPrices(params: {
triggerPrice?: bigint;
indexToken: TokenData;
initialCollateralToken: TokenData;
collateralToken: TokenData;
isLong: boolean;
limitOrderType?: OrderType.LimitIncrease | OrderType.StopIncrease;
}): {
indexPrice: bigint;
initialCollateralPrice: bigint;
collateralPrice: bigint;
triggerThresholdType?: TriggerThresholdType;
triggerPrice?: bigint;
}
\`\`\`
Selects the correct prices to use for position calculations based on order type. For market orders, prices come from live token price feeds. For limit and stop-increase orders, the trigger price is used as the index price (and as the collateral price if the collateral token matches the index token).
| Parameter | Type | Description |
| ------------------------ | ---------------------------------------------------------------- | ------------------------------------------------------------------------ |
| \`triggerPrice\` | \`bigint \\| undefined\` | User-set trigger price (30-decimal precision); required for limit orders |
| \`indexToken\` | \`TokenData\` | Index token with live price data |
| \`initialCollateralToken\` | \`TokenData\` | Token the user deposits |
| \`collateralToken\` | \`TokenData\` | Final position collateral token |
| \`isLong\` | \`boolean\` | \`true\` for long, \`false\` for short |
| \`limitOrderType\` | \`OrderType.LimitIncrease \\| OrderType.StopIncrease \\| undefined\` | Set for non-market orders; \`undefined\` means market order |
\`triggerThresholdType\` indicates the price crossing direction: \`">"\` (Above) means the order executes when the price rises above the trigger; \`"<"\` (Below) means it executes when the price falls below.
\`\`\`typescript
// Limit increase: buy ETH long when price drops to $1900
const prices = getIncreasePositionPrices({
triggerPrice: 1\_900000000000000000000000000000n, // $1900 (30-decimal)
indexToken: ethToken,
initialCollateralToken: usdcToken,
collateralToken: usdcToken,
isLong: true,
limitOrderType: OrderType.LimitIncrease,
});
console.log("Index price:", prices.indexPrice); // 1\_900000000000000000000000000000n
console.log("Threshold type:", prices.triggerThresholdType); // "<" (Below) — executes when price ≤ $1900
\`\`\`
### getNextPositionValuesForIncreaseTrade
\`\`\`typescript
getNextPositionValuesForIncreaseTrade(p: {
existingPosition?: PositionInfo;
marketInfo: MarketInfo;
collateralToken: TokenData;
positionPriceImpactDeltaUsd: bigint;
sizeDeltaUsd: bigint;
sizeDeltaInTokens: bigint;
collateralDeltaUsd: bigint;
collateralDeltaAmount: bigint;
indexPrice: bigint;
isLong: boolean;
showPnlInLeverage: boolean;
minCollateralUsd: bigint;
userReferralInfo: UserReferralInfo | undefined;
}): NextPositionValues
\`\`\`
Projects position values after an increase trade executes. Pass the outputs from \`getIncreasePositionAmounts\` along with the current position (if any) to show users their post-trade size, leverage, entry price, and liquidation price.
Pending borrow and funding fees are treated as zero because they are deducted at order execution time.
| Parameter | Type | Description |
| ----------------------------- | ------------------------------- | ------------------------------------------------------------------- |
| \`existingPosition\` | \`PositionInfo \\| undefined\` | Current open position; pass \`undefined\` for a new position |
| \`marketInfo\` | \`MarketInfo\` | Market info for liquidation price computation |
| \`collateralToken\` | \`TokenData\` | Collateral token for the position |
| \`positionPriceImpactDeltaUsd\` | \`bigint\` | Price impact from \`getIncreasePositionAmounts\` (may be negative) |
| \`sizeDeltaUsd\` | \`bigint\` | Size increase in USD |
| \`sizeDeltaInTokens\` | \`bigint\` | Size increase in index token units |
| \`collateralDeltaUsd\` | \`bigint\` | Collateral added in USD |
| \`collateralDeltaAmount\` | \`bigint\` | Collateral added in token units |
| \`indexPrice\` | \`bigint\` | Current or trigger index price |
| \`isLong\` | \`boolean\` | \`true\` for long positions |
| \`showPnlInLeverage\` | \`boolean\` | When \`true\`, unrealized PnL is included in the leverage denominator |
| \`minCollateralUsd\` | \`bigint\` | Minimum collateral threshold used for liquidation price calculation |
| \`userReferralInfo\` | \`UserReferralInfo \\| undefined\` | Referral data for fee discount in liquidation price |
\*\*Returns:\*\* \`NextPositionValues\` — \`nextSizeUsd\`, \`nextCollateralUsd\`, \`nextEntryPrice\`, \`nextLeverage\`, \`nextLiqPrice\`, \`nextPendingImpactDeltaUsd\`, \`potentialPriceImpactDiffUsd\`.
\`\`\`typescript
const amounts = getIncreasePositionAmounts({
/\* ... see above ... \*/
});
const nextValues = getNextPositionValuesForIncreaseTrade({
existingPosition: currentPosition, // undefined for new positions
marketInfo,
collateralToken: usdcToken,
positionPriceImpactDeltaUsd: amounts.positionPriceImpactDeltaUsd,
sizeDeltaUsd: amounts.sizeDeltaUsd,
sizeDeltaInTokens: amounts.sizeDeltaInTokens,
collateralDeltaUsd: amounts.collateralDeltaUsd,
collateralDeltaAmount: amounts.collateralDeltaAmount,
indexPrice: amounts.indexPrice,
isLong: true,
showPnlInLeverage: false,
minCollateralUsd: 1\_000000000000000000000000000000n, // $1 minimum
userReferralInfo: undefined,
});
console.log("Next size (USD):", nextValues.nextSizeUsd);
console.log("Next leverage:", nextValues.nextLeverage); // bigint, basis points (10000 = 1x)
console.log("Next liquidation price:", nextValues.nextLiqPrice);
console.log("Next entry price:", nextValues.nextEntryPrice);
\`\`\`
### Related
- \[Decrease position utilities\](./decrease.md) — symmetric functions for closing or reducing positions
- \[Trade utilities\](./trade.md) — shared helpers for both increase and decrease operations
- \[Fees module\](../fees/fees.md) — position fee and price impact calculation functions
---
## trade
This module provides utility functions for trade operations including slippage calculations, swap counting, and trade flag creation for the GMX protocol.
## Methods
This module exports four utility functions used in trade calculations.
### applySlippageToPrice
\`\`\`typescript
applySlippageToPrice(allowedSlippage: number, price: bigint, isIncrease: boolean, isLong: boolean): bigint
\`\`\`
Adjusts an acceptable price by the given slippage in basis points. For operations that use \`maxPrice\` (long increases and short decreases), slippage is added — resulting in a higher acceptable price. For operations that use \`minPrice\` (short increases and long decreases), slippage is subtracted.
\`\`\`typescript
// Long increase: acceptable price is 0.5% above mark price
const acceptablePrice = applySlippageToPrice(
50, // 50 bps = 0.5%
1800n \* 10n \*\* 30n, // mark price
true, // isIncrease
true // isLong
);
// acceptablePrice ≈ 1800 × 1.005 = 1809
\`\`\`
### applySlippageToMinOut
\`\`\`typescript
applySlippageToMinOut(allowedSlippage: number, minOutputAmount: bigint): bigint
\`\`\`
Reduces \`minOutputAmount\` by the given slippage in basis points. Always reduces the minimum — use this to set the \`minOut\` parameter in swap orders.
\`\`\`typescript
const minOut = applySlippageToMinOut(
100, // 100 bps = 1%
1000n \* 10n \*\* 6n // 1000 USDC (6 decimals)
);
// minOut = 990 USDC — accept up to 1% slippage
\`\`\`
### getSwapCount
\`\`\`typescript
getSwapCount(params: {
isSwap: boolean;
isIncrease: boolean;
swapAmounts?: SwapAmounts;
increaseAmounts?: IncreasePositionAmounts;
decreaseAmounts?: DecreasePositionAmounts;
}): number | undefined
\`\`\`
Returns the number of market swaps in the current trade. Returns \`undefined\` when the required amounts object is not provided.
- For swaps: returns \`swapAmounts.swapStrategy.swapPathStats?.swapPath.length ?? 0\`
- For increase orders: returns \`increaseAmounts.swapStrategy.swapPathStats?.swapPath.length ?? 0\`
- For decrease orders: returns \`1\` when \`decreaseSwapType !== NoSwap\`, otherwise \`0\`
\`\`\`typescript
// 2-hop swap path
const swapCount = getSwapCount({
isSwap: true,
isIncrease: false,
swapAmounts,
});
// swapCount = swapAmounts.swapStrategy.swapPathStats?.swapPath.length ?? 0
\`\`\`
### createTradeFlags
\`\`\`typescript
createTradeFlags(tradeType: TradeType, tradeMode: TradeMode): TradeFlags
\`\`\`
Creates a \`TradeFlags\` object that derives all boolean flags from a \`(TradeType, TradeMode)\` pair. The derivation rules are:
| Flag | Rule |
| ------------ | ----------------------------------------------------------------------- |
| \`isLong\` | \`tradeType === TradeType.Long\` |
| \`isShort\` | \`tradeType === TradeType.Short\` |
| \`isSwap\` | \`tradeType === TradeType.Swap\` |
| \`isPosition\` | \`isLong \\|\\| isShort\` |
| \`isMarket\` | \`tradeMode === TradeMode.Market\` |
| \`isLimit\` | \`tradeMode === TradeMode.Limit \\|\\| tradeMode === TradeMode.StopMarket\` |
| \`isTrigger\` | \`tradeMode === TradeMode.Trigger\` |
| \`isTwap\` | \`tradeMode === TradeMode.Twap\` |
| \`isIncrease\` | \`isPosition && (isMarket \\|\\| isLimit \\|\\| isTwap)\` |
:::note
Both \`TradeMode.Limit\` and \`TradeMode.StopMarket\` produce \`isLimit: true\`. A Trigger decrease (\`TradeMode.Trigger\`) produces \`isIncrease: false\`.
:::
\`\`\`typescript
const flags = createTradeFlags(TradeType.Long, TradeMode.Market);
// { isLong: true, isShort: false, isSwap: false, isPosition: true,
// isIncrease: true, isMarket: true, isLimit: false, isTrigger: false, isTwap: false }
const triggerFlags = createTradeFlags(TradeType.Long, TradeMode.Trigger);
// isIncrease: false — trigger decrease, not an increase
\`\`\`
---
## tradeHistory
This module exports typed helpers for transforming Subsquid trade history records into SDK trade actions.
## Runtime exports
- \`createRawTradeActionTransformer\`
- \`bigNumberify\`
## Re-exported types
- \`TradeActionType\`
- \`PositionTradeAction\`
- \`SwapTradeAction\`
- \`TradeAction\`
- \`isPositionTradeAction\`
- \`isSwapTradeAction\`
\`\`\`typescript
\`\`\`
---
## twap(Utils)
This module exports helpers for validating and deriving TWAP order timing.
## Exports
- \`getIsValidTwapParams\`
- \`getTwapDurationInSeconds\`
- \`getTwapValidFromTime\`
- \`changeTwapNumberOfPartsValue\`
- \`getTwapOrderKey\`
- \`makeTwapValidFromTimeGetter\`
- Re-exported types: \`TwapDuration\`, \`TwapOrderParams\`, \`TwapPartParams\`
\`\`\`typescript
\`\`\`
---
## types
This module exports small shared TypeScript utility types.
## Exports
- \`mustNeverExist\`
- \`DeepPartial\`
\`\`\`typescript
\`\`\`
---
## Integration guide(V1)
Use this page when you want exact steps instead of a function-by-function reference. The \[Getting Started\](./readme.mdx) page explains the SDK surface area, and the \[Exports\](./exports/exports.md) pages document individual helpers. This page focuses on common workflows and the operational details that matter in production.
## What SDK v1 covers today
SDK v1 (\`GmxSdk\`) is the full client. It reads markets, tokens, positions, orders, trades, and account delegates, and it submits or cancels orders through a connected wallet.
| Workflow | Status | Notes |
| -------- | ------ | ----- |
| Read market, token, position, order, and trade data | ✅ | Available through \`markets\`, \`tokens\`, \`positions\`, \`orders\`, \`trades\`, and \`accounts\` |
| Submit and cancel orders | ✅ | Available through \`orders.long\`, \`orders.short\`, \`orders.swap\`, \`create\*Order\`, and \`cancelOrders\` |
| Built-in transaction receipt polling | ❌ | Order methods return a transaction hash; your app must wait for receipts and refetch state |
| Built-in idempotency keys or client order IDs | ❌ | Prevent duplicate submits in your app layer |
| Automatic retry and backoff for RPC reads | ⚠️ | Default viem HTTP clients are created with \`retryCount: 0\` |
If you are designing delegated trader, subaccount, or one-click trading flows, use \[Delegated trading integration\](../../api/contracts/delegated-trading.md) together with this SDK guide. The delegated trading architecture spans contracts, optional relay routers, and your own signer/session model.
## Read account state for one wallet
Use one market and token snapshot across the whole read flow. This avoids mixing data from different polls when you render positions, active orders, and recent trades together.
\`\`\`typescript
const sdk = new GmxSdk({
chainId: 42161,
rpcUrl: "https://arb1.arbitrum.io/rpc",
oracleUrl: "https://arbitrum-api.gmxinfra.io",
subsquidUrl: "https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql",
});
sdk.setAccount("0x9f7198eb1b9Ccc0Eb7A07eD228d8FbC12963ea33");
const { marketsInfoData, tokensData } = await sdk.markets.getMarketsInfo();
if (!marketsInfoData || !tokensData) {
throw new Error("Failed to load market snapshot");
}
const \[{ positionsData }, { ordersInfoData }, trades\] = await Promise.all(\[\
sdk.positions.getPositions({\
marketsData: marketsInfoData,\
tokensData,\
}),\
sdk.orders.getOrders({\
marketsInfoData,\
tokensData,\
}),\
sdk.trades.getTradeHistory({\
pageSize: 25,\
pageIndex: 0,\
marketsInfoData,\
tokensData,\
}),\
\]);
console.log({
positions: Object.values(positionsData ?? {}),
orders: Object.values(ordersInfoData ?? {}),
recentTrades: trades,
});
\`\`\`
## Open a Market Increase order
If you want the SDK to calculate swap paths, fees, and order amounts for you, start with the quick helper methods. The helper returns a transaction hash after submission. After that, you still need to wait for the receipt and refetch positions or orders.
\`\`\`typescript
const account = privateKeyToAccount("0x...your-private-key");
const walletClient = createWalletClient({
account,
chain: arbitrum,
transport: http("https://arb1.arbitrum.io/rpc"),
});
const sdk = new GmxSdk({
chainId: 42161,
rpcUrl: "https://arb1.arbitrum.io/rpc",
oracleUrl: "https://arbitrum-api.gmxinfra.io",
subsquidUrl: "https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql",
walletClient,
account: account.address,
});
const txHash = await sdk.orders.long({
payAmount: 100031302n,
marketAddress: "0x70d95587d40A2caf56bd97485aB3Eec10Bee6336",
payTokenAddress: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
collateralTokenAddress: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
allowedSlippageBps: 125,
leverage: 50000n,
});
const receipt = await sdk.publicClient.waitForTransactionReceipt({ hash: txHash });
if (receipt.status !== "success") {
throw new Error("Order transaction reverted");
}
const { marketsInfoData, tokensData } = await sdk.markets.getMarketsInfo();
const { ordersInfoData } = await sdk.orders.getOrders({
marketsInfoData: marketsInfoData!,
tokensData: tokensData!,
});
console.log("Submitted tx:", txHash);
console.log("Active orders:", Object.keys(ordersInfoData));
\`\`\`
## Cancel active orders
Fetch the latest active orders first, then cancel by on-chain order key. This matters if your UI lets the user cancel and replace orders quickly.
\`\`\`typescript
const { marketsInfoData, tokensData } = await sdk.markets.getMarketsInfo();
if (!marketsInfoData || !tokensData) {
throw new Error("Failed to load market snapshot");
}
const { ordersInfoData } = await sdk.orders.getOrders({
marketsInfoData,
tokensData,
});
const orderKeys = Object.keys(ordersInfoData);
if (orderKeys.length === 0) {
throw new Error("No active orders to cancel");
}
const txHash = await sdk.orders.cancelOrders(orderKeys);
await sdk.publicClient.waitForTransactionReceipt({ hash: txHash });
const refreshed = await sdk.orders.getOrders({
marketsInfoData,
tokensData,
});
console.log("Remaining orders:", Object.keys(refreshed.ordersInfoData));
\`\`\`
## Operational notes
### Data freshness and consistency
- Quick helpers fetch \`marketsInfoData\` and \`tokensData\` for you when you do not pass them in.
- If your app already has a fresh snapshot, pass the same \`marketsInfoData\` and \`tokensData\` through the whole flow. This gives you a more consistent view than mixing independent reads.
- After a write, treat reads as eventually consistent. Transaction submission, order creation, keeper execution, and indexed reads do not complete at the same time.
### Simulation behavior
- Market increases simulate before submit unless you pass \`skipSimulation: true\`.
- Limit increases skip simulation in the current implementation.
- Market swaps simulate before submit. \`Limit Swap\` orders do not.
- \`createDecreaseOrder()\` currently sets \`skipSimulation: true\`. If you expose that flow, validate inputs before submit and handle chain-level failures explicitly.
### Retries and timeouts
- The default viem HTTP clients created by \`GmxSdk\` disable transport retries with \`retryCount: 0\`.
- SDK multicalls use a \`40000\` ms timeout.
- Add your own retry and backoff policy around read paths that can be repeated safely. Persist transaction hashes from write paths so you can recover after client restarts.
### Idempotency and race conditions
- SDK v1 order methods do not take idempotency keys or client-generated order IDs.
- Disable duplicate submit actions in your UI while a transaction is pending.
- When you cancel or replace orders, refetch active orders just before choosing \`orderKeys\`.
## Next steps
- Go back to \[Getting Started\](./readme.mdx) for constructor options and module reference.
- See \[Examples\](./examples.md) for smaller focused snippets.
- Use \[Exports\](./exports/exports.md) when you need lower-level helpers such as fee estimation, price impact, or custom trade amount calculation.
---
## Troubleshooting(V1)
Use this page when SDK v1 reads or writes do not behave the way you expect. Most production issues fall into one of five buckets: missing receipt handling, stale follow-up reads, duplicate submits, transport failures, or workflow assumptions that belong to SDK v2 or GraphQL instead.
## The SDK returned a transaction hash, but my UI is still pending
That is expected. SDK v1 order methods submit the transaction and return the hash. They do not wait for the receipt for you.
Recommended pattern:
1. Persist the transaction hash as soon as you receive it.
2. Wait for the receipt with \`sdk.publicClient.waitForTransactionReceipt\`.
3. Only after the receipt succeeds should you start polling positions, orders, or trade history.
If the client reloads before confirmation, recover from the saved transaction hash instead of resubmitting.
## The transaction succeeded, but the order or position is not visible yet
Treat follow-up reads as eventually consistent.
- Transaction inclusion, order creation, keeper execution, and indexed history do not complete at the same time.
- \`orders.getOrders()\` shows active on-chain orders, but trade history comes from Subsquid and can lag behind live chain state.
- If you need a coherent account snapshot, refresh one \`marketsInfoData\` and \`tokensData\` snapshot and reuse it across position and order reads.
## I accidentally submitted the same action twice
SDK v1 does not support idempotency keys or client order IDs.
Recommended client behavior:
1. Disable repeat submit actions while a transaction is pending.
2. Persist the last in-flight transaction hash per user action.
3. Require an explicit retry action after a failure instead of auto-resubmitting writes.
## Cancel or replace shows unexpected order state
This is usually a race between an old UI snapshot and current on-chain order keys.
- Refetch active orders immediately before calling \`cancelOrders\`.
- Cancel by the latest on-chain order keys, not by cached UI state from an earlier poll.
- After cancel or replace, refetch orders again instead of assuming the previous list is still valid.
## Read calls fail with timeouts or transient RPC errors
The default SDK-created viem transports set \`retryCount: 0\`, and SDK multicalls use a \`40000\` ms timeout.
Recommended client behavior:
1. Add retry and backoff around safe read paths.
2. Keep write submission separate from read retries so you do not duplicate transactions.
3. Consider supplying your own viem clients if you need a custom transport strategy.
If you inject a custom viem \`publicClient\`, make sure it includes \`BATCH\_CONFIGS\` from \`@gmx-io/sdk/configs/batch\`. The SDK-created default clients already do this for you, but custom clients do not inherit it automatically.
Without the SDK batch config, large GMX multicalls may be fragmented into many smaller requests instead of one client-side multicall. Common symptoms include unexpectedly high RPC request counts, public RPC rate limits, and browser-side transport failures during otherwise normal read or order-helper flows.
## A limit order did not simulate before submit
That can be current behavior, not necessarily a bug.
- Market increases simulate by default unless you opt out.
- Limit increases skip simulation in the current implementation.
- Market swaps simulate by default, while \`Limit Swap\` orders do not.
- \`createDecreaseOrder()\` currently skips simulation.
If your UI exposes these flows, validate inputs before submission and surface chain-level errors clearly.
## Next steps
- Use the \[Integration guide\](./integration-guide.md) for exact SDK v1 workflows.
- Use \[Getting Started\](./readme.mdx) for constructor and module reference.
- Use \[SDK Overview\](../overview.md) when you need to choose between SDK v1 and SDK v2.
---
## Getting Started
If you only need read-only HTTP data without RPC calls, use the read-only API client:
Install the shared SDK package first:
\`\`\`bash
npm install @gmx-io/sdk
\`\`\`
Then import the read-only client from the \`v2\` subpath:
\`\`\`typescript
const apiSdk = new GmxApiSdk({ chainId: 42161 }); // Arbitrum
const markets = await apiSdk.fetchMarkets();
const marketsInfo = await apiSdk.fetchMarketsInfo();
const tickers = await apiSdk.fetchMarketsTickers({
symbols: \["BTC/USD"\],
});
const tokens = await apiSdk.fetchTokens();
const tokensData = await apiSdk.fetchTokensData();
const pairs = await apiSdk.fetchPairs();
const rates = await apiSdk.fetchRates({ period: "7d" });
const apy = await apiSdk.fetchApy({ period: "7d" });
const annualized = await apiSdk.fetchPerformanceAnnualized({
period: "30d",
});
const snapshots = await apiSdk.fetchPerformanceSnapshots({
period: "30d",
});
const positions = await apiSdk.fetchPositionsInfo({
address: "0x9f7198eb1b9Ccc0Eb7A07eD228d8FbC12963ea33",
includeRelatedOrders: true,
});
const orders = await apiSdk.fetchOrders({
address: "0x9f7198eb1b9Ccc0Eb7A07eD228d8FbC12963ea33",
});
const candles = await apiSdk.fetchOhlcv({
symbol: "BTC/USD",
timeframe: "1h",
limit: 100,
});
\`\`\`
\`GmxApiSdk\` calls the GMX REST API directly — no RPC endpoint, oracle URL, or Subsquid URL required. It supports Arbitrum, Avalanche, and Arbitrum Sepolia. The constructor throws for unsupported chains.
\`@gmx-io/sdk/v2\` is an import path inside the \`@gmx-io/sdk\` package, not a separate npm package.
If you're using CommonJS, require the v2 client from the \`v2\` subpath:
\`\`\`javascript
const { GmxApiSdk } = require("@gmx-io/sdk/v2");
const apiSdk = new GmxApiSdk({ chainId: 42161 });
\`\`\`
TypeScript subpath resolution is supported for \`@gmx-io/sdk/v2\` and the SDK's utility, config, ABI, and type-only entrypoints.
## What SDK v2 covers today
| Workflow | Status | Notes |
| -------- | ------ | ----- |
| Read market catalogs, tickers, and token data over HTTP | ✅ | Available through \`fetchMarkets()\`, \`fetchMarketsInfo()\`, \`fetchMarketsTickers()\`, \`fetchTokens()\`, and \`fetchTokensData()\` |
| Read pairs, rates, APY, and performance analytics over HTTP | ✅ | Available through \`fetchPairs()\`, \`fetchRates()\`, \`fetchApy()\`, \`fetchPerformanceAnnualized()\`, and \`fetchPerformanceSnapshots()\` |
| Read one account's positions and orders over HTTP | ✅ | Available through \`fetchPositionsInfo()\` and \`fetchOrders()\` |
| Read OHLCV candles over HTTP | ✅ | Available through \`fetchOhlcv()\` |
| Read protocol buyback stats over HTTP | ✅ | Available through \`fetchBuybackWeeklyStats()\` |
| Read staking power over HTTP | ✅ | Available through \`fetchStakingPower()\` |
| Submit or cancel orders | ❌ | Use \[SDK v1\](../v1/readme.mdx) or direct contracts |
| Trade history reads | ❌ | Use \[SDK v1\](../v1/readme.mdx) or \[GraphQL\](../../api/graphql.mdx) |
Use \[SDK Overview\](../overview.md) if you want a quick capability comparison before wiring an integration.
## Methods
\`GmxApiSdk\` exposes the following methods. All of them call the GMX REST API directly -- no RPC, oracle, or Subsquid connection is required.
| Method | Parameters | Returns | Notes |
| ------ | ---------- | ------- | ----- |
| \`fetchMarkets()\` | -- | \`MarketWithTiers\[\]\` | Market catalog data from \`/markets\` |
| \`fetchMarketsInfo()\` | -- | \`RawMarketInfo\[\]\` | Market definitions and pricing from \`/markets/info\` |
| \`fetchMarketsTickers(params?)\` | \`addresses?: string\[\]\`, \`symbols?: string\[\]\` | \`MarketTicker\[\]\` | Filterable market tickers from \`/markets/tickers\` |
| \`fetchTokens()\` | -- | \`Token\[\]\` | Static token catalog from \`/tokens\` |
| \`fetchTokensData()\` | -- | \`TokenData\[\]\` | Token metadata and current prices from \`/tokens/info\` |
| \`fetchPairs()\` | -- | \`Pair\[\]\` | Pair-level summary data from \`/pairs\` |
| \`fetchRates(params?)\` | \`period?: ApiParameterPeriod\`, \`averageBy?: "1d" | "7d" | "30d"\`, \`address?: string\` | \`MarketRates\[\]\` | Hourly funding and borrowing rate snapshots from \`/rates\`. For near-live rates, use \`/markets/info\` or \`fetchMarketsInfo()\` instead |
| \`fetchApy(params?)\` | \`period?: ApiParameterPeriod\` | \`ApyResponse\` | Market and GLV APY data from \`/apy\` |
| \`fetchPerformanceAnnualized(params?)\` | \`period?: ApiParameterPeriod\`, \`address?: string\` | \`PerformanceAnnualized\[\]\` | Annualized performance summaries from \`/performance/annualized\` |
| \`fetchPerformanceSnapshots(params?)\` | \`period?: ApiParameterPeriod\`, \`address?: string\` | \`PerformanceSnapshots\[\]\` | Historical performance snapshot series from \`/performance/snapshots\` |
| \`fetchPositionsInfo(params)\` | \`address: string\`, \`includeRelatedOrders?: boolean\` | \`ApiPositionInfo\[\]\` | Position objects for an address; optionally includes related orders |
| \`fetchOrders(params)\` | \`address: string\` | \`ApiOrderInfo\[\]\` | Active order objects for an address |
| \`fetchOhlcv(params)\` | \`symbol: string\`, \`timeframe: string\`, \`limit?: number\`, \`since?: number\` | \`OhlcvCandle\[\]\` | OHLCV candle data from \`/prices/ohlcv\` |
| \`fetchBuybackWeeklyStats()\` | -- | \`BuybackWeeklyStatsResponse\` | Weekly buyback accrual data and cumulative summary from \`/buyback/weekly-stats\` |
| \`fetchStakingPower(params)\` | \`address: string\` | \`StakingPowerResponse\` | Staking power, loyalty ratio, and reward share data for an address from \`/staking/power\` |
### Staking power timestamps
\`StakingPowerResponse\` includes two protocol-level timestamps that are constant across all addresses:
| Field | Type | Description |
| ----- | ---- | ----------- |
| \`powerAccrualStart\` | unix seconds | The moment power began accumulating for staked GMX. Set to \`1772582400\` (March 4, 2026 00:00:00 UTC). |
| \`loyaltyTrackingStart\` | unix seconds | The moment loyalty tracking became active. Before this time, unstaking did not affect the historical peak used for loyalty enforcement. Set to \`1774396800\` (March 25, 2026 00:00:00 UTC). |
After \`loyaltyTrackingStart\`, if an account's staked balance drops below 80% of its historical peak, accumulated power resets to zero. See \[Rewards\](../../tokenomics/rewards.md#loyalty-threshold) for the user-facing description of how the loyalty threshold works.
## When to use SDK v2
Use \`GmxApiSdk\` for read-only API integrations that need market, ticker, token, pair, rate, APY, performance, position, order, OHLCV, buyback, or staking-power data without requiring RPC or oracle connections. Use the full \[\`GmxSdk\` (SDK v1)\](../v1/readme.mdx) when you need trade history or write operations such as submitting or cancelling orders.
:::note
\`GmxApiSdk\` is under active development and will expand to cover the full SDK surface over time, replacing the need for direct RPC, oracle, and Subsquid connections. The \[OpenAPI Reference\](/docs/category/api-v2-openapi-reference) documents most of the underlying REST API that \`GmxApiSdk\` wraps, but the checked-in generated reference does not yet list the staking or buyback endpoints exposed through \`fetchStakingPower()\` and \`fetchBuybackWeeklyStats()\`.
:::
---
## Contract addresses
This page lists the key contract addresses for each supported chain. For the complete list of all deployed contracts (100+ per chain), see the \[gmx-synthetics deployments folder\](https://github.com/gmx-io/gmx-synthetics/tree/updates/docs). The machine-readable \`contracts.json\` in that folder covers mainnet deployments, while testnet deployments are published in the per-network markdown files.
:::warning
Contract addresses change when logic contracts are upgraded. Subscribe to the \[Updates and support\](../updates-support.md) channels for upgrade notifications.
\`DataStore\` and \`RoleStore\` addresses are permanent and don't change across upgrades.
:::
## Mainnet
The tables below list the key integrator-facing contracts for each mainnet chain. For the full list of all deployed contracts on each chain, see the deployment files linked from each section.
### Arbitrum (Chain ID: 42161)
Explorer: \[arbiscan.io\](https://arbiscan.io) | \[Full deployment list\](https://github.com/gmx-io/gmx-synthetics/blob/updates/docs/arbitrum-deployments.md)
| Contract | Address |
| --------------------- | -------------------------------------------- |
| DataStore | \`0xFD70de6b91282D8017aA4E741e9Ae325CAb992d8\` |
| RoleStore | \`0x3c3d99FD298f679DBC2CEcd132b4eC4d0F5e6e72\` |
| Reader | \`0x470fbC46bcC0f16532691Df360A07d8Bf5ee0789\` |
| ExchangeRouter | \`0x1C3fa76e6E1088bCE750f23a5BFcffa1efEF6A41\` |
| Router | \`0x7452c558d45f8afC8c83dAe62C3f8A5BE19c71f6\` |
| Oracle | \`0x7F01614cA5198Ec979B1aAd1DAF0DE7e0a215BDF\` |
| OrderVault | \`0x31eF83a530Fde1B38EE9A18093A333D8Bbbc40D5\` |
| DepositVault | \`0xF89e77e8Dc11691C9e8757e84aaFbCD8A67d7A55\` |
| WithdrawalVault | \`0x0628D46b5D145f183AdB6Ef1f2c97eD1C4701C55\` |
| ShiftVault | \`0xfe99609C4AA83ff6816b64563Bdffd7fa68753Ab\` |
| OrderHandler | \`0x63492B775e30a9E6b4b4761c12605EB9d071d5e9\` |
| DepositHandler | \`0x33871b8568eDC4adf33338cdD8cF52a0eCC84D42\` |
| WithdrawalHandler | \`0x11e9E7464f3Bc887a7290ec41fCd22f619b177fd\` |
| AdlHandler | \`0x262df96a3a35D0A7950C5669238662df58Ae8bf7\` |
| LiquidationHandler | \`0xaf157Eb8e2398A8E1Fc1dA929974652b9ba9BC25\` |
| ShiftHandler | \`0x5F66cBb8D1766e6CE3c1ffba0987aeDe7a1DFf53\` |
| GlvHandler | \`0x3f6dF0c3A7221BA1375E87e7097885a601B41Afc\` |
| GlvVault | \`0x393053B58f9678C9c28c2cE941fF6cac49C3F8f9\` |
| EventEmitter | \`0xC8ee91A54287DB53897056e12D9819156D3822Fb\` |
| MarketFactory | \`0xf5F30B10141E1F63FC11eD772931A8294a591996\` |
| GlvRouter | \`0x7EAdEE2ca1b4D06a0d82fDF03D715550c26AA12F\` |
| GlvReader | \`0x2C670A23f1E798184647288072e84054938B5497\` |
| SubaccountRouter | \`0xdD00F639725E19a209880A44962Bc93b51B1B161\` |
| Multicall3 | \`0xe79118d6D92a4b23369ba356C90b9A7ABf1CB961\` |
| Config | \`0x33D1a645B9E9fc19b06Fe02981180c8DDAeE75B1\` |
| ConfigTimelockController | \`0xC77E6C0ca99E02660A23c00A860Dd5a8912DEaF5\` |
| GovTimelockController | \`0xFBEff82f2DD5E51B8AF34b57cf788b4b09d466F9\` |
| Timelock | \`0x7A967D114B8676874FA2cFC1C14F3095C88418Eb\` |
| TimelockConfig | \`0x4A1D9e342E2dB5f4a02c9eF5cB29CaF289f31599\` |
#### Multichain contracts (Arbitrum)
| Contract | Address |
| -------------------------- | -------------------------------------------- |
| MultichainOrderRouter | \`0xD38111f8aF1A7Cd809457C8A2303e15aE2170724\` |
| MultichainGmRouter | \`0xC6782854A8639cC3b40f9497797d6B33797CA592\` |
| MultichainGlvRouter | \`0xabcBbe23BD8E0dDD344Ff5fd1439b785B828cD2d\` |
| MultichainClaimsRouter | \`0x277B4c0e8A76Fa927C9881967a4475Fd6E234e95\` |
| MultichainTransferRouter | \`0xfaBEb65bB877600be3A2C2a03aA56a95F9f845B9\` |
| MultichainSubaccountRouter | \`0x70AaAd50d53732b2D5534bb57332D00aE20cAd36\` |
| MultichainReader | \`0xC17AEf8559006e73B325C742143Eb2Aa1d6f79B2\` |
| MultichainVault | \`0xCeaadFAf6A8C489B250e407987877c5fDfcDBE6E\` |
#### Relay and oracle provider contracts (Arbitrum)
| Contract | Address |
| --------------------------- | -------------------------------------------- |
| GelatoRelayRouter | \`0xa9090E2fd6cD8Ee397cF3106189A7E1CFAE6C59C\` |
| SubaccountGelatoRelayRouter | \`0x517602BaC704B72993997820981603f5E4901273\` |
| ChainlinkDataStreamProvider | \`0xE1d5a068c5b75E0c7Ea1A9Fe8EA056f9356C6fFD\` |
| ChainlinkPriceFeedProvider | \`0x38B8dB61b724b51e42A88Cb8eC564CD685a0f53B\` |
| EdgeDataStreamProvider | \`0x24A01E28077C2b831166Dd4099DFfD4056a336a1\` |
| LayerZeroProvider | \`0xB6DE222dAef5029f31b8fABE498D34f3c491Ef85\` |
### Avalanche (Chain ID: 43114)
Explorer: \[snowtrace.io\](https://snowtrace.io) | \[Full deployment list\](https://github.com/gmx-io/gmx-synthetics/blob/updates/docs/avalanche-deployments.md)
| Contract | Address |
| --------------------- | -------------------------------------------- |
| DataStore | \`0x2F0b22339414ADeD7D5F06f9D604c7fF5b2fe3f6\` |
| RoleStore | \`0xA44F830B6a2B6fa76657a3B92C1fe74fcB7C6AfD\` |
| Reader | \`0x62Cb8740E6986B29dC671B2EB596676f60590A5B\` |
| ExchangeRouter | \`0x8f550E53DFe96C055D5Bdb267c21F268fCAF63B2\` |
| Router | \`0x820F5FfC5b525cD4d88Cd91aCf2c28F16530Cc68\` |
| Oracle | \`0xE1d5a068c5b75E0c7Ea1A9Fe8EA056f9356C6fFD\` |
| OrderVault | \`0xD3D60D22d415aD43b7e64b510D86A30f19B1B12C\` |
| DepositVault | \`0x90c670825d0C62ede1c5ee9571d6d9a17A722DFF\` |
| WithdrawalVault | \`0xf5F30B10141E1F63FC11eD772931A8294a591996\` |
| ShiftVault | \`0x7fC46CCb386e9bbBFB49A2639002734C3Ec52b39\` |
| OrderHandler | \`0x823b558B4bC0a2C4974a0d8D7885AA1102D15dEC\` |
| DepositHandler | \`0xCC2645E961514A694bca228686ec664933c70647\` |
| WithdrawalHandler | \`0x334237f7d75497a22B1443f44DDCcF95e72904A0\` |
| AdlHandler | \`0x858559D39fe8B2fDfE452f895db36077859130e1\` |
| LiquidationHandler | \`0xad7F00b4080BACFfAaE7f44d67560C818d8e5468\` |
| ShiftHandler | \`0x6AdF7026D53057CED269DFDa318103db4F0Aa4Ba\` |
| GlvHandler | \`0x48486CaF8851ed0085432789D28A8820bEcbfd45\` |
| GlvVault | \`0x527FB0bCfF63C47761039bB386cFE181A92a4701\` |
| EventEmitter | \`0xDb17B211c34240B014ab6d61d4A31FA0C0e20c26\` |
| MarketFactory | \`0xc57C155FacCd93F62546F329D1483E0E5b9C1241\` |
| GlvRouter | \`0x7E425c47b2Ff0bE67228c842B9C792D0BCe58ae6\` |
| GlvReader | \`0x5C6905A3002f989E1625910ba1793d40a031f947\` |
| SubaccountRouter | \`0xf43F559774d2cF7882e6E846fCb87BDe183a6Da7\` |
| Multicall3 | \`0x50474CAe810B316c294111807F94F9f48527e7F8\` |
| Config | \`0x11e9E7464f3Bc887a7290ec41fCd22f619b177fd\` |
| ConfigTimelockController | \`0x20D56cf90fD3C8f3bEb9BAC03AfdA3241093DE36\` |
| GovTimelockController | \`0xA2aAaa1CbBd4B4f1Fd548f0a3f58B924EE36f266\` |
| Timelock | \`0xdF23692341538340db0ff04C65017F51b69a29f6\` |
| TimelockConfig | \`0x37e1AeB6118B0106810D2eF7662875C414e39Ca4\` |
#### Multichain contracts (Avalanche)
| Contract | Address |
| -------------------------- | -------------------------------------------- |
| MultichainOrderRouter | \`0xd099565957046a2d2CF41B0CC9F95e14a8afD13b\` |
| MultichainGmRouter | \`0xA191Bc0B72332e4c2022dB50a9d619079cc6c4fD\` |
| MultichainGlvRouter | \`0xEEE61742bC4cf361c60Cd65826864560Bf2D0bB6\` |
| MultichainClaimsRouter | \`0xd10B10b816030347ff4E6767d340371B40b9F03D\` |
| MultichainTransferRouter | \`0x5A44a3b026d50EC039582fDb3aFDD88e2092E211\` |
| MultichainSubaccountRouter | \`0x5872E84e5ea23292b40183BE86D25fb428621fC1\` |
| MultichainReader | \`0xf7B962B085775A96A99E3dD38dfFf09D7e270088\` |
| MultichainVault | \`0x6D5F3c723002847B009D07Fe8e17d6958F153E4e\` |
#### Relay and oracle provider contracts (Avalanche)
| Contract | Address |
| --------------------------- | -------------------------------------------- |
| GelatoRelayRouter | \`0xEE2d3339CbcE7A42573C96ACc1298A79a5C996Df\` |
| SubaccountGelatoRelayRouter | \`0xfaBEb65bB877600be3A2C2a03aA56a95F9f845B9\` |
| ChainlinkDataStreamProvider | \`0xC181eB022F33b8ba808AD96348B03e8A753A859b\` |
| ChainlinkPriceFeedProvider | \`0x05d97cee050bfb81FB3EaD4A9368584F8e72C88e\` |
| EdgeDataStreamProvider | \`0x176fD214bc59005fFd722AE3F8fA12a31391F6Ae\` |
| LayerZeroProvider | \`0xF85Fd576bBe22Bce785B68922C1c9849d62737c0\` |
### Botanix (Chain ID: 3637)
Explorer: \[botanixscan.io\](https://botanixscan.io) | \[Full deployment list\](https://github.com/gmx-io/gmx-synthetics/blob/updates/docs/botanix-deployments.md)
| Contract | Address |
| --------------------- | -------------------------------------------- |
| DataStore | \`0xA23B81a89Ab9D7D89fF8fc1b5d8508fB75Cc094d\` |
| RoleStore | \`0x51Aa17ca59E9e9C3cEc3c3c05c2B35f473b35D39\` |
| Reader | \`0x922766ca6234cD49A483b5ee8D86cA3590D0Fb0E\` |
| ExchangeRouter | \`0xBCB5eA3a84886Ce45FBBf09eBF0e883071cB2Dc8\` |
| Router | \`0x3d472afcd66F954Fe4909EEcDd5c940e9a99290c\` |
| Oracle | \`0x40d680E41FC4Bf973F0EA664981f6359195a6383\` |
| OrderVault | \`0xe52B3700D17B45dE9de7205DEe4685B4B9EC612D\` |
| DepositVault | \`0x4D12C3D3e750e051e87a2F3f7750fBd94767742c\` |
| WithdrawalVault | \`0x46BAeAEdbF90Ce46310173A04942e2B3B781Bf0e\` |
| ShiftVault | \`0xa7EE2737249e0099906cB079BCEe85f0bbd837d4\` |
| OrderHandler | \`0xBAD04dDcc5CC284A86493aFA75D2BEb970C72216\` |
| DepositHandler | \`0x839B6e19E54A5862da61974A01675a5f6CC5c8b4\` |
| WithdrawalHandler | \`0x5bB6DCb09010069228B2aA766FAE513EF7923472\` |
| AdlHandler | \`0xec0e4A27a9fbfc64e4915c254B961260df28054c\` |
| LiquidationHandler | \`0x1bC32eeCAa8F504D2225096649A0347153A37f10\` |
| ShiftHandler | \`0xAD712E1667bC8AAa6C4EA5f47dcD487ddd96BC35\` |
| GlvHandler | \`0xB75AdE19252A9db51ea861E9A39C80BB0D7aAd82\` |
| GlvVault | \`0xd336087512BeF8Df32AF605b492f452Fd6436CD8\` |
| EventEmitter | \`0xAf2E131d483cedE068e21a9228aD91E623a989C2\` |
| MarketFactory | \`0xcb7656751B0f8aFCBe15D135D7aC58727DE06768\` |
| GlvRouter | \`0xC92741F0a0D20A95529873cBB3480b1f8c228d9F\` |
| GlvReader | \`0x955Aa50d2ecCeffa59084BE5e875eb676FfAFa98\` |
| SubaccountRouter | \`0xa1793126B6Dc2f7F254a6c0E2F8013D2180C0D10\` |
| Multicall3 | \`0x4BaA24f93a657f0c1b4A0Ffc72B91011E35cA46b\` |
| Config | \`0x5a1344252f0CdfDB765DD5ab97C98734f1D7ED6d\` |
| ConfigTimelockController | \`0x3d6BA4a91Ffde7C519379F8dCA5FE58b7125c294\` |
| GovTimelockController | \`0x610701662CD64De835d53B2dE508d342781CC1Bd\` |
| Timelock | \`0xca3e30b51A7c3bd40bFc52a61AB0cE57B3Ab3ad8\` |
| TimelockConfig | \`0x72a30e76827Ce83cEf0b1BEd7e9aAF9F4a576990\` |
#### Multichain contracts (Botanix)
| Contract | Address |
| -------------------------- | -------------------------------------------- |
| MultichainOrderRouter | \`0xbC074fF8b85f9b66884E1EdDcE3410fde96bd798\` |
| MultichainGmRouter | \`0x6a960F397eB8F2300F9FfA746F11375A613C5027\` |
| MultichainGlvRouter | \`0x9C11DFa4DAFA9227Ef172cc1d87D4D5008804C47\` |
| MultichainClaimsRouter | \`0x421eB756B8f887f036e7332801288BC2bbA600aC\` |
| MultichainTransferRouter | \`0x844D38f2c3875b8351feB4764718E1c64bD55c46\` |
| MultichainSubaccountRouter | \`0x8138Ce254Bc0AfE40369FDC2D1e46cE90944406d\` |
| MultichainReader | \`0x9511FAb77C8d7Acf56c9D8AE9278Cd3bd8Bd9D5c\` |
| MultichainVault | \`0x9a535f9343434D96c4a39fF1d90cC685A4F6Fb20\` |
#### Relay and oracle provider contracts (Botanix)
| Contract | Address |
| --------------------------- | -------------------------------------------- |
| GelatoRelayRouter | \`0x98e86155abf8bCbA566b4a909be8cF4e3F227FAf\` |
| SubaccountGelatoRelayRouter | \`0xd6b16f5ceE328310B1cf6d8C0401C23dCd3c40d4\` |
| ChainlinkDataStreamProvider | \`0x1A4D623301b9f58405d3Fff7a63624411d5eb940\` |
| ChainlinkPriceFeedProvider | \`0xDc613305e9267f0770072dEaB8c03162e0554b2d\` |
| EdgeDataStreamProvider | \`0x02E209c2c47956e4E2934A7516d81e86d88A5Dbc\` |
| LayerZeroProvider | \`0x9E721ef9b908B4814Aa18502692E4c5666d1942e\` |
### MegaETH (Chain ID: 4326)
Explorer: \[megaeth.blockscout.com\](https://megaeth.blockscout.com) | \[Full deployment list\](https://github.com/gmx-io/gmx-synthetics/blob/updates/docs/megaEth-deployments.md)
| Contract | Address |
| --------------------- | -------------------------------------------- |
| DataStore | \`0xE43C7B694f6b652a9F4A0f275C008d18758Dce35\` |
| RoleStore | \`0xecA46636BDDbb4F451ca2B7062C7E36744934655\` |
| Reader | \`0x0f038EB4a38B08cd3c937a3256b51aa01904a684\` |
| ExchangeRouter | \`0x73B3593F01CF8e573a412D1d0c972b581794ebE0\` |
| Router | \`0x1eAfB14236C489C28845EC04F78DECA5Fb9879Aa\` |
| Oracle | \`0x611640B004719e4843552F60996360Ea6B39E75e\` |
| OrderVault | \`0xD5AE04762E2afb1506695b3F36286EBE7B0E6772\` |
| DepositVault | \`0x8231A60862F9b0bA93fFA050c0E94AC902D901d2\` |
| WithdrawalVault | \`0x0Ec53dda9676219dE63eC703212219b07811F33C\` |
| ShiftVault | \`0xC255c70b50623054CADbAD9A02E1CFE73d286666\` |
| OrderHandler | \`0x7d5F99Bab016b831648e278B208579e0eCdb3974\` |
| DepositHandler | \`0x0d776a8A8aB967193Ad50c3b220996834D5550c7\` |
| WithdrawalHandler | \`0x8ca83c6243b7461Ae24b5cB167912F5C055F80b0\` |
| AdlHandler | \`0xf97835F08c2Bc0DA66F0e354Aa6C22b1c99657E6\` |
| LiquidationHandler | \`0x74fCc13e7D2bf35eAaA06BC2CB3307eD6a852414\` |
| ShiftHandler | \`0xBb54059D79d6E887f17aF86f724Bb1634b2C6758\` |
| GlvVault | \`0x52e4875EB5603d21912d30A1dBA6B0B97192459A\` |
| EventEmitter | \`0xAf2E131d483cedE068e21a9228aD91E623a989C2\` |
| MarketFactory | \`0x5Fb9121Ca153B93dD70ae53280Dc3b64E1805940\` |
| GlvRouter | \`0x505F0cCADA00F0CcB4EEbf6467531cF4dd907B0E\` |
| GlvReader | \`0x424527a588D56513cB2F5161958D83883EE8aB0f\` |
| SubaccountRouter | \`0x3133aC88af73d3187f1700a2426AD95B5d6E0562\` |
| Multicall3 | \`0xF516BC01c50eebdBad4d7E506c8f690ae8EAFc52\` |
| Config | \`0xb7779724235Bc038e41B8b39CA3212411aDD1284\` |
| ConfigTimelockController | \`0xBf96f66932C1D826C172a80bE7c062ab6b26a4CC\` |
| GovTimelockController | \`0x0a42516de743D87572f5788cac23F0a2c1a39f69\` |
| TimelockConfig | \`0x9d5f3fac443748c28FB5dc964D74F8419F686F6D\` |
#### Multichain contracts (MegaETH)
| Contract | Address |
| -------------------------- | -------------------------------------------- |
| MultichainOrderRouter | \`0x976363dFbA3AeB8Fb10b733baD74e7099cCB558A\` |
| MultichainGmRouter | \`0x041336A3DaF0a12d004a95f1511393d9A3d7236d\` |
| MultichainGlvRouter | \`0x7EF7d01316425de5d7C2EFDf8b802A250c222faB\` |
| MultichainClaimsRouter | \`0xfE9fD31e499bA6d8733Aec49ECe5b41381103433\` |
| MultichainTransferRouter | \`0xCa62C570D8667a00A56EB989881ECbA4364BFe9e\` |
| MultichainSubaccountRouter | \`0xeB8f828A4B89dc3A854f278227A2A5E136E50bF9\` |
| MultichainReader | \`0xcdA9c0f9Ad580DBf564a3b5a5Ca58D09F11f4FA8\` |
| MultichainVault | \`0xd6922E889cE4CF14e59427F20e7d857ff81A5A9D\` |
#### Relay and oracle provider contracts (MegaETH)
| Contract | Address |
| --------------------------- | -------------------------------------------- |
| GelatoRelayRouter | \`0x24eD625B9C47fDEbF088A4d12B7f9B4B2f556297\` |
| SubaccountGelatoRelayRouter | \`0xD515fA0B4d704f3E2C57270F1F53BEeE16348B3b\` |
| ChainlinkDataStreamProvider | \`0xfdD24de4974fFCeBBA126fF1D17bF18E4a9AE5ac\` |
| ChainlinkPriceFeedProvider | \`0x7452c558d45f8afC8c83dAe62C3f8A5BE19c71f6\` |
| EdgeDataStreamProvider | \`0xb9a3e10Fd35e10387B4d3a24AEa443577600E89b\` |
| LayerZeroProvider | \`0x9c41F854f123a7905907FfcF2578dFB7E47D02E0\` |
## Testnet
Testnet contracts are redeployed more frequently than mainnet. Verify addresses before integrating. Arbitrum Sepolia is usually the most current testnet, but Avalanche Fuji deployment artifacts are also published in the \`updates\` branch.
### Arbitrum Sepolia (Chain ID: 421614)
Explorer: \[sepolia.arbiscan.io\](https://sepolia.arbiscan.io) | \[Full deployment list\](https://github.com/gmx-io/gmx-synthetics/blob/updates/docs/arbitrumSepolia-deployments.md)
The Arbitrum Sepolia deployment is the most current testnet. For a frontend that connects to testnet, see \[Testnet frontend\](../frontend-integration.md#testnet-frontend).
| Contract | Address |
| ------------------------ | -------------------------------------------- |
| DataStore | \`0xCF4c2C4c53157BcC01A596e3788fFF69cBBCD201\` |
| RoleStore | \`0x433E3C47885b929aEcE4149E3c835E565a20D95c\` |
| Reader | \`0x4750376b9378294138Cf7B7D69a2d243f4940f71\` |
| ExchangeRouter | \`0xEd50B2A1eF0C35DAaF08Da6486971180237909c3\` |
| Router | \`0x72F13a44C8ba16a678CAD549F17bc9e06d2B8bD2\` |
| Oracle | \`0x0dC4e24C63C24fE898Dda574C962Ba7Fbb146964\` |
| OrderVault | \`0x1b8AC606de71686fd2a1AEDEcb6E0EFba28909a2\` |
| DepositVault | \`0x809Ea82C394beB993c2b6B0d73b8FD07ab92DE5A\` |
| WithdrawalVault | \`0x7601c9dBbDCf1f5ED1E7Adba4EFd9f2cADa037A5\` |
| ShiftVault | \`0x6b6F9B7B9a6b69942DAE74FB95E694ec277117af\` |
| OrderHandler | \`0x000F692690F6C39660AfB878D277f038fb3a8eC6\` |
| DepositHandler | \`0xdD0228e2806A348209F777c82C90515f9da1b790\` |
| WithdrawalHandler | \`0x039Ddee97368eb6ed20CE921dE7AD37A92A1A566\` |
| AdlHandler | \`0x6d8437132784CDDF0cCa3Da249EF49F92947EEE4\` |
| LiquidationHandler | \`0x268FA5c1dafeefd5E7Bc31CF517c780cb36E7a84\` |
| ShiftHandler | \`0xC72ea16031bd6731dE2812074cEca8028B8493b9\` |
| GlvVault | \`0x40bD50de0977c68ecB958ED4A065E14E1091ce64\` |
| EventEmitter | \`0xa973c2692C1556E1a3d478e745e9a75624AEDc73\` |
| MarketFactory | \`0x1934838E3d85416A6cF5bF7A5E619f12BE01C4b2\` |
| GlvRouter | \`0x21b044Bb4a2Ba667723aA3d15ba7b4bCc628084D\` |
| GlvReader | \`0x9B7D08AB020D9c180E4bAc370fB545317124Cf22\` |
| SubaccountRouter | \`0xCF45A7E8bB46738f454eC6766631E5612DA90836\` |
| Multicall3 | \`0xD84793ae65842fFac5C20Ab8eaBD699ea1FC79F3\` |
| Config | \`0xE2169693147dF45EDc84b759488Aa0E34FD9F939\` |
| ConfigTimelockController | \`0x8722Df9218bA7d7ee06AE48e990ef38B76750111\` |
| GovTimelockController | \`0xb1854C5CfB3D25be6198972d5c3AEa0592e933a4\` |
| TimelockConfig | \`0x674c5Cda9fA404B14D3834D54D7eF258b91BA4a8\` |
### Avalanche Fuji (Chain ID: 43113)
Explorer: \[testnet.snowtrace.io\](https://testnet.snowtrace.io) | \[Full deployment list\](https://github.com/gmx-io/gmx-synthetics/blob/updates/docs/avalancheFuji-deployments.md)
| Contract | Address |
| ------------------------ | -------------------------------------------- |
| DataStore | \`0xEA1BFb4Ea9A412dCCd63454AbC127431eBB0F0d4\` |
| RoleStore | \`0x19a8085537078e7847a332A76ABaDD5b02B1e736\` |
| Reader | \`0xf82Cc6EB57F8FF86bc5c5e90B8BA83DbBFB517eE\` |
| ExchangeRouter | \`0x0a458C96Ac0B2a130DA4BdF1aAdD4cb7Be036d11\` |
| Router | \`0x5e7d61e4C52123ADF651961e4833aCc349b61491\` |
| Oracle | \`0xae7c79ED2807Fe544f5757890ca8afB9d553f17c\` |
| OrderVault | \`0x25D23e8E655727F2687CC808BB9589525A6F599B\` |
| DepositVault | \`0x2964d242233036C8BDC1ADC795bB4DeA6fb929f2\` |
| WithdrawalVault | \`0x74d49B6A630Bf519bDb6E4efc4354C420418A6A2\` |
| ShiftVault | \`0x257D0EA0B040E2Cd1D456fB4C66d7814102aD346\` |
| OrderHandler | \`0xb525036363BC44695d36fD56Bcb86CEF39cd444A\` |
| DepositHandler | \`0x12383b2AB771471003185a83cf983c98A826bD4E\` |
| WithdrawalHandler | \`0xe80Fea80cA767a105A65D67bFA970ecF1B4e9127\` |
| AdlHandler | \`0x96b2004d52d30b21385E6757b1EEbd1565864f6A\` |
| LiquidationHandler | \`0x4092cC8E8dC0893f93f35f5998585a6109d91a46\` |
| ShiftHandler | \`0xd96Eb278505EF101B3a1328636DFb2F215Bb6bA5\` |
| GlvVault | \`0x76f93b5240DF811a3fc32bEDd58daA5784e46C96\` |
| EventEmitter | \`0xc67D98AC5803aFD776958622CeEE332A0B2CabB9\` |
| MarketFactory | \`0x89810f23585FDCfAFfB1712e5B76d9b0F722e1d6\` |
| GlvRouter | \`0x6B6595389A0196F882C0f66CB1F401f1D24afEdC\` |
| GlvReader | \`0xdeaC9ea3c72C102f2a9654b8E1A14Ef86Cdd3146\` |
| SubaccountRouter | \`0xD5EE3ECAF5754CE5Ff74847d0caf094EBB12ed5e\` |
| Multicall3 | \`0x966D1F5c54a714C6443205F0Ec49eEF81F10fdfD\` |
| Config | \`0x63725E32b05324042Fe78C34be3E72497C91e1E0\` |
| ConfigTimelockController | \`0xc120bD6756171691fC2e2D5EE876ae79526412c1\` |
| GovTimelockController | \`0x8beF3F7f3B2d8b8490Cf30b42c728293D1C2a9Ef\` |
| Timelock | \`0x0f0c78405A4E6dAfc188d539D61C69D74f42f9dB\` |
| TimelockConfig | \`0xa2c59bf9999915C2DF87998739c2e3Efa9c856f4\` |
:::note
Testnet deployments may include additional test contracts (\`MockPriceFeed\`, test tokens) not present on mainnet. See the full deployment list linked above for all testnet contracts.
:::
## Contract categories
The sections below describe the purpose of each contract category listed in the address tables.
### Multichain contracts
The \`Multichain\*\` contracts enable cross-chain operations through the \[GMX Account\](../../trading/overview.md#gmx-account-multichain) system. They let users on one chain submit orders, manage positions, and transfer funds to GMX deployments on other chains via LayerZero messaging.
| Contract | Purpose |
| -------------------------- | --------------------------------------------------------- |
| MultichainOrderRouter | Routes cross-chain order creation requests |
| MultichainGmRouter | Routes cross-chain GM token deposit/withdrawal requests |
| MultichainGlvRouter | Routes cross-chain GLV deposit/withdrawal requests |
| MultichainClaimsRouter | Routes cross-chain claim requests (funding fees, rebates) |
| MultichainTransferRouter | Routes cross-chain token transfers |
| MultichainSubaccountRouter | Routes cross-chain subaccount operations |
| MultichainReader | Reads cross-chain state and pending operations |
| MultichainVault | Holds funds in transit during cross-chain operations |
### Gelato relay contracts
The Gelato relay contracts enable gasless transaction submission. Users sign a message off-chain, and a Gelato relay network submits the transaction on their behalf. This powers the Express Trading mode in the GMX interface.
| Contract | Purpose |
| --------------------------- | ------------------------------------------------ |
| GelatoRelayRouter | Accepts relay requests for standard operations |
| SubaccountGelatoRelayRouter | Accepts relay requests for subaccount operations |
### Oracle provider contracts
Multiple oracle providers feed price data into the protocol. The \`Oracle\` contract aggregates prices from these providers, selecting the most appropriate source for each token.
| Contract | Purpose |
| --------------------------- | --------------------------------------------------------------------------- |
| ChainlinkDataStreamProvider | Fetches prices from Chainlink Data Streams (primary source for most tokens) |
| ChainlinkPriceFeedProvider | Fetches prices from Chainlink Price Feeds (fallback and reference) |
| EdgeDataStreamProvider | Fetches prices from Edge oracle data streams |
### Governance and configuration contracts
The governance and configuration contracts control protocol parameters and enforce time-delayed updates. Changes to protocol parameters flow through the \`Config\` contract, which is gated by the \`ConfigTimelockController\` to ensure a mandatory delay before changes take effect. Higher-level governance actions are managed through \`GovTimelockController\` and \`Timelock\`.
| Contract | Purpose |
| ------------------------ | ----------------------------------------------------------------------- |
| Config | Applies parameter changes to the protocol through the timelock system |
| ConfigTimelockController | Enforces time delays on configuration updates submitted via Config |
| GovTimelockController | Controls governance-level actions with time-delayed execution |
| Timelock | Manages protocol upgrades, role assignments, and privileged operations |
| TimelockConfig | Stores timelock duration settings for different operation categories |
### Cross-chain messaging
| Contract | Purpose |
| ----------------- | ------------------------------------------------- |
| LayerZeroProvider | Handles cross-chain message and data verification |
---
## Advanced entry points
This page covers the contract surfaces beyond the core \`ExchangeRouter\` / \`GlvRouter\` flow: delegated subaccount trading, gasless relay routers, and multichain GMX Account routers. Some of these are end-user or integrator entry points, while others are specialized router or controller surfaces.
If you need an end-to-end implementation pattern for delegated trader flows rather than just the raw contract surface, see \[Delegated trading integration\](./delegated-trading.md).
For the core request lifecycle, see \[Architecture\](./architecture.md). For standard GM and GLV actions, see \[ExchangeRouter\](./exchange-router.md) and \[GlvRouter\](./glv-router.md).
## SubaccountRouter
\`SubaccountRouter\` is a legacy contract that is still deployed but no longer used for order operations. The current GMX interface only calls it for wallet-based subaccount removal outside the express flow. New integrations should use \`SubaccountGelatoRelayRouter\` for delegated order execution.
The contract originally let a main account delegate order management to a subaccount without giving that subaccount full custody of the account.
### Management functions
| Function | Purpose |
| --- | --- |
| \`addSubaccount(address subaccount)\` | Authorize a delegated subaccount |
| \`removeSubaccount(address subaccount)\` | Remove a delegated subaccount |
| \`setSubaccountExpiresAt(address subaccount, bytes32 actionType, uint256 expiresAt)\` | Set an expiry timestamp for a delegated action type |
| \`setMaxAllowedSubaccountActionCount(address subaccount, bytes32 actionType, uint256 maxAllowedCount)\` | Cap how many actions a subaccount can perform |
| \`setSubaccountAutoTopUpAmount(address subaccount, uint256 amount)\` | Configure automatic native-token top-ups for the subaccount |
| \`setIntegrationId(address subaccount, bytes32 integrationId)\` | Bind the subaccount to an integration identifier |
### Order functions
\`SubaccountRouter\` only exposes delegated order actions:
| Function | Purpose |
| --- | --- |
| \`createOrder(address account, CreateOrderParams params)\` | Create an order for the main account |
| \`updateOrder(bytes32 key, ...)\` | Update a pending order |
| \`cancelOrder(bytes32 key)\` | Cancel a pending order |
### Integration notes
- Subaccount order actions are gated by \`Keys.SUBACCOUNT\_ORDER\_ACTION\`.
- The router validates the main account's integration id before handling the action.
- For swap and increase orders, the router transfers the main account's collateral into \`OrderVault\` through the core \`Router\` plugin mechanism.
- Auto top-up uses the main account's WNT allowance and balance, then unwraps native token to the subaccount. The top-up amount is capped to the native tokens actually spent on gas plus execution fee.
For the exact implementation, see \[\`SubaccountRouter.sol\`\](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/router/SubaccountRouter.sol).
## Gelato relay routers
GMX exposes two relay entry points for gasless order management:
| Contract | Purpose |
| --- | --- |
| \`GelatoRelayRouter\` | Gasless create / update / cancel / batch order flow for the main account |
| \`SubaccountGelatoRelayRouter\` | Gasless delegated order flow for subaccounts, plus \`removeSubaccount\` |
### Supported actions
| Function | \`GelatoRelayRouter\` | \`SubaccountGelatoRelayRouter\` |
| --- | --- | --- |
| \`batch(...)\` | Yes | Yes |
| \`createOrder(...)\` | Yes | Yes |
| \`updateOrder(...)\` | Yes | Yes |
| \`cancelOrder(...)\` | Yes | Yes |
| \`removeSubaccount(...)\` | No | Yes |
### RelayParams structure
Relay calls share the \`IRelayUtils.RelayParams\` envelope:
- \`oracleParams\`: optional oracle data for GMX-based fee swaps
- \`externalCalls\`: optional external swap / call bundle
- \`tokenPermits\`: optional EIP-2612 permits
- \`fee\`: \`feeToken\`, \`feeAmount\`, and optional \`feeSwapPath\`
- \`userNonce\`: replay-protection nonce chosen by the user
- \`deadline\`: signature expiry
- \`signature\`: signed relay authorization
- \`desChainId\`: destination chain id expected by the signature
### Integration notes
- Relay routers do not expose \`multicall\` or \`sendTokens\`; token movements for external calls must be declared through \`externalCalls.sendTokens\` and \`externalCalls.sendAmounts\`.
- Relay fees are paid from the main account, not the relayer.
- \`SubaccountGelatoRelayRouter\` additionally validates a \`SubaccountApproval\` signature and per-account nonce.
- External calls are rejected for subaccount relay orders.
For the exact implementation, see \[\`GelatoRelayRouter.sol\`\](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/router/relay/GelatoRelayRouter.sol), \[\`SubaccountGelatoRelayRouter.sol\`\](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/router/relay/SubaccountGelatoRelayRouter.sol), and \[\`IRelayUtils.sol\`\](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/router/relay/IRelayUtils.sol).
## Multichain routers
The multichain contracts power GMX Account flows and other cross-chain operations.
### Action routers
| Contract | Notable surface |
| --- | --- |
| \`MultichainOrderRouter\` | \`batch\`, \`createOrder\`, \`updateOrder\`, \`cancelOrder\`, \`setTraderReferralCode\`, \`registerCode\` |
| \`MultichainGmRouter\` | \`createDeposit\`, \`createWithdrawal\`, \`createShift\` |
| \`MultichainGlvRouter\` | \`createGlvDeposit\`, \`createGlvWithdrawal\` |
| \`MultichainClaimsRouter\` | \`claimFundingFees\`, \`claimCollateral\`, \`claimAffiliateRewards\` |
| \`MultichainTransferRouter\` | \`bridgeIn\`, \`bridgeOut\`, \`transferOut\` |
### Reader surface
\`MultichainReader\` is the cross-chain read helper. Its notable entry points are:
- \`quoteReadFee(...)\` to estimate the LayerZero read fee
- \`sendReadRequests(...)\` to dispatch read requests across configured chains
- \`lzReceive(...)\` to receive LayerZero read responses and forward them to the registered originator
### Integration notes
- Multichain action routers take both \`account\` and \`srcChainId\`, because the action may originate from a different chain than the settlement chain.
- GM and GLV multichain routers also take \`TransferRequests\` so funds can be routed into the correct vaults before the action is created.
- Claim routes send outputs into \`MultichainVault\` first, then record the transfer for the destination receiver.
- \`MultichainTransferRouter.bridgeOutFromController(...)\` is controller-only infrastructure for protocol-driven bridge-outs after execution, not a general user-facing entry point.
- \`MultichainReader.quoteReadFee(...)\` is a public read helper, but \`sendReadRequests(...)\` is controller-gated and intended for authorized originators rather than general end users.
- \`lzReceive(...)\` is part of the LayerZero receive path and not a normal end-user entry point.
For the exact implementation, see \[\`IMultichainOrderRouter.sol\`\](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/multichain/IMultichainOrderRouter.sol), \[\`IMultichainGmRouter.sol\`\](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/multichain/IMultichainGmRouter.sol), \[\`IMultichainGlvRouter.sol\`\](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/multichain/IMultichainGlvRouter.sol), \[\`IMultichainTransferRouter.sol\`\](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/multichain/IMultichainTransferRouter.sol), \[\`MultichainClaimsRouter.sol\`\](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/multichain/MultichainClaimsRouter.sol), and \[\`MultichainReader.sol\`\](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/multichain/MultichainReader.sol).
## Next steps
- \[Contract addresses\](./addresses.md) for live deployments
- \[Delegated trading integration\](./delegated-trading.md) for end-to-end subaccount and relay patterns
- \[ExchangeRouter\](./exchange-router.md) for standard order, deposit, withdrawal, and shift flows
- \[GlvRouter\](./glv-router.md) for GLV request flows
- \[Known issues\](./known-issues.md) for integration caveats and operational risks
---
## Architecture
This page covers the GMX smart contract architecture, execution model, keeper network, and integration considerations. For contract function references, see \[Reader\](./reader.md), \[ExchangeRouter\](./exchange-router.md), and \[GLV Reader\](./glv-reader.md).
## Contract structure
The GMX protocol separates concerns across four contract categories. These categories describe the internal contract architecture, not the subset of contracts most integrations call directly day to day.
| Category | Role | Examples |
| --- | --- | --- |
| \*\*Bank contracts\*\* | Hold funds. Only these contracts custody tokens. | \`Bank\`, \`StrictBank\`, \`MarketToken\`, \`DepositVault\`, \`OrderVault\`, \`WithdrawalVault\`, \`ShiftVault\`, \`GlvVault\` |
| \*\*Data storage\*\* | Maintain all protocol state in a single store. | \`DataStore\`, \`RoleStore\`, \`OracleStore\` |
| \*\*Logic contracts\*\* | Stateless execution logic. Read from DataStore, compute results, emit events. | \`ExchangeRouter\`, \`GlvRouter\`, \`Reader\`, \`GlvReader\`, \`OrderHandler\`, \`DepositHandler\`, \`WithdrawalHandler\`, \`ShiftHandler\`, \`LiquidationHandler\`, \`AdlHandler\`, all \`\*Utils\` contracts |
| \*\*Event utilities\*\* | Generalized event emission for indexing and monitoring. | \`EventEmitter\` |
This separation enables contract upgrades without migrating funds. When a logic contract is upgraded, a new version is deployed and granted the appropriate roles in \`RoleStore\`. The bank contracts and \`DataStore\` remain unchanged — no fund migration is required.
For most integrations, the main entry points are \`ExchangeRouter\` for writes and \`Reader\` / \`GlvReader\` for reads. \`GlvRouter\` handles GLV-specific operations (deposits, withdrawals). Many of the other contracts listed above are supporting handlers, storage contracts, or utilities used internally by those entry points.
Struct data is serialized into \`DataStore\` through \`\*StoreUtils\` contracts (for example, \`OrderStoreUtils\`, \`PositionStoreUtils\`, \`ShiftStoreUtils\`, \`MarketStoreUtils\`, \`GlvStoreUtils\`), which allows new keys to be added to structs without requiring storage migration. Order and position lists are stored on-chain using \`EnumerableSet\` rather than relying on indexers, so interfaces and keepers can query accurate data without waiting for indexer sync delays.
:::warning
\`RoleStore\` and \`DataStore\` must not change after deployment. Replacing either requires migrating all funds and reconfiguring every dependent contract. New handlers and routers receive different addresses; integrations must support multiple handler versions temporarily during transitions.
:::
### Role-based access control
All privileged operations are gated through \`RoleStore\`, which maps addresses to roles using an \`EnumerableSet\`-backed store with a \`roleCache\` mapping for gas-efficient lookups. Handlers, keepers, and governance controllers each hold specific roles that authorize their actions. The \`Config\` contract applies parameter changes through a \`ConfigTimelockController\` (extending OpenZeppelin's \`TimelockController\`) that enforces time delays on sensitive updates.
### EventEmitter
Rather than emitting events from each contract individually, the protocol routes all events through a shared \`EventEmitter\` contract. This provides a single address to monitor for all protocol activity. The \`EventEmitter\` uses three structured event types (\`EventLog\`, \`EventLog1\`, \`EventLog2\`) with different numbers of indexed topics for efficient filtering, plus raw \`emitDataLog1\` through \`emitDataLog4\` functions for general-purpose log emission.
For monitoring integration examples, see \[Events\](./events.md).
## Execution model
Most user actions follow a two-phase request-execution pattern:
\`\`\`mermaid
sequenceDiagram
participant User
participant Contract as ExchangeRouter
participant Keeper as Order Keeper
participant Oracle as Oracle Keeper
participant Archive as Archive Node
User->>Contract: 1. createOrder(params)
Note over Contract: Request stored on-chain
Oracle->>Archive: Sign and publish prices
Keeper->>Archive: 2. Fetch signed prices
Keeper->>Contract: 3. executeOrder(key, oraclePrices)
Note over Contract: Validates prices, executes logic
Contract-->>User: Order filled or reverted
\`\`\`
\*\*Phase 1 — Request:\*\* The user submits a transaction (via \`ExchangeRouter\`) that stores the request parameters on-chain — order type, size, collateral, acceptable price, and execution fee. No oracle prices are needed at this stage.
\*\*Phase 2 — Execution:\*\* A keeper observes the request, fetches signed oracle prices from archive nodes, and submits an execution transaction that bundles the prices with the request key. The contract validates the prices and executes the order atomically.
Execution uses a try/catch pattern in \`OrderHandler.executeOrder\`. If the error is a keeper issue (insufficient gas, missing oracle prices), the entire transaction reverts so that the user's request is not unnecessarily cancelled. For market orders, user-side errors (unmet conditions, insufficient funds) cancel the request and return funds. For limit and trigger orders, the order is frozen instead of cancelled to prevent gaming — see \[Frozen orders\](#frozen-orders) below.
This two-phase design prevents front-running: the user's intent is committed on-chain before oracle prices are included, so no actor can see the execution price before the request is recorded.
### Execution latency
The two-phase model introduces a brief delay between request and execution (typically a few seconds), during which the market price may move. The \`acceptablePrice\` parameter protects users — if the execution price exceeds their tolerance, the order is not fulfilled at that price.
### Simulations
You can dry-run actions before keeper execution by calling the simulation functions on \`ExchangeRouter\` (for example, \`simulateExecuteLatestOrder\`, \`simulateExecuteLatestDeposit\`, \`simulateExecuteLatestWithdrawal\`, \`simulateExecuteLatestShift\`, \`simulateExecuteLatestJitOrder\`) and \`GlvRouter\` (for example, \`simulateExecuteLatestGlvDeposit\`, \`simulateExecuteLatestGlvWithdrawal\`). These are public router entry points intended for preflight checks, while the actual execution functions live on keeper-gated handlers. Simulations use the \`withSimulatedOraclePrices\` modifier and revert with \`EndOfOracleSimulation\` on success (not failure). See \[Simulations\](./simulations.md) for details.
## Keeper network
Three components work together to execute orders:
### Oracle keepers
Oracle keepers fetch prices from oracle providers. The primary provider is \`ChainlinkDataStreamProvider\`, which sources prices from \[Chainlink Data Streams\](https://docs.chain.link/data-streams). Additional providers include \`EdgeDataStreamProvider\` and \`GmOracleProvider\`. Each price report includes both a minimum price (\`min\`) and a maximum price (\`max\`), capturing the bid-ask spread. All prices use 30-decimal precision (\`FLOAT\_PRECISION = 10^30\`) and represent the USD value of one full token unit, so conversions require no unit adjustment on the token amount:
\`\`\`
fiatValue = tokenAmount \* oraclePrice
tokenAmount = fiatValue / oraclePrice
\`\`\`
The protocol validates oracle prices against Chainlink reference feeds using the \`MAX\_ORACLE\_REF\_PRICE\_DEVIATION\_FACTOR\` parameter, rejecting any price that deviates beyond the configured threshold. Not all tokens have a \`ChainlinkPriceFeedProvider\` configured as a reference price source.
### Order keepers
Order keepers monitor the chain for pending requests (orders, deposits, withdrawals, shifts). When a request is detected, the keeper:
1. Fetches signed prices from the configured oracle providers.
2. Bundles the prices with the request key into an execution transaction.
3. Submits the transaction. The execution fee (paid by the user at request time) covers the keeper's gas cost.
If gas prices spike, the keeper may wait or the user can cancel the request after a cancellation period. Execution fees include a buffer to account for gas price volatility — any excess is refunded after execution.
### Frozen orders
If an order cannot be fulfilled at execution time (for example, the order size exceeds available liquidity, or position constraints aren't met), the order is frozen rather than cancelled. This prevents gaming where a user could create a limit order with size greater than available pool liquidity, wait for the trigger price to be hit, then deposit into the pool to allow execution at a favorable price.
Frozen orders can be retried by dedicated frozen order keepers when conditions improve. Users can also call \`updateOrder\` to unfreeze and modify the order, or cancel it entirely.
## Integration considerations
### Contract versioning
Integrations must handle contract address changes during upgrades. When logic contracts are upgraded, new handler and router contracts are deployed at different addresses. During transition periods:
- Multiple handler versions may be active simultaneously.
- Callback contracts must whitelist both old and new handler addresses.
- Use configurable contract addresses rather than hardcoding them.
Subscribe to the channels in the \[Updates and Support\](../updates-support.md) page for contract update notifications.
### ETH and WETH handling
When the protocol needs to send ETH (for example, returning execution fee refunds), it first attempts a native ETH transfer with a configurable gas limit (\`NATIVE\_TOKEN\_TRANSFER\_GAS\_LIMIT\`). If the transfer fails (for example, the recipient contract lacks a \`receive\` function or doesn't have enough gas), the protocol wraps the ETH as WETH and sends that instead.
### First market deposit
The first deposit into a newly created market must set the receiver to \`address(1)\` and meet a minimum market token threshold (\`MIN\_MARKET\_TOKENS\_FOR\_FIRST\_DEPOSIT\`). The minted market tokens are sent to \`address(1)\`, effectively locking them. This prevents manipulation of the market token price through rounding on the initial deposit. Subsequent deposits mint market tokens to the depositor normally.
### Token compatibility
The protocol is designed for standard ERC-20 tokens. The following token types are \*\*not compatible\*\*:
- \*\*Rebasing tokens\*\* — tokens that automatically adjust balances (for example, stETH in rebasing mode)
- \*\*ERC-777 tokens\*\* — tokens with transfer hooks that could enable reentrancy
- \*\*Fee-on-transfer tokens\*\* — tokens that deduct a fee on every transfer
- \*\*Tokens with built-in burn mechanisms\*\* — tokens where the supply decreases on transfer
### Token airdrops to GM holders
If airdropping tokens to GM token holders, the airdrop must be claimable by contracts (not just EOAs). Integrating protocols that hold GM tokens on behalf of users need to be able to claim and distribute the airdrop to their users.
## Known issues
For the full list of known issues, token compatibility constraints, and integration considerations, see the dedicated \[Known issues\](./known-issues.md) page.
## Next steps
- \[Contract addresses\](./addresses.md) — Deployment addresses for all supported chains.
- \[ExchangeRouter\](./exchange-router.md) — Create orders, deposits, withdrawals, and shifts.
- \[GlvRouter\](./glv-router.md) — Create GLV deposits and withdrawals.
- \[Reader\](./reader.md) — Query market, position, and pricing data.
- \[GLV Reader\](./glv-reader.md) — Query GLV vault data and pricing.
- \[Advanced entry points\](./advanced-entrypoints.md) — Delegated subaccount trading, Gelato relay flows, and multichain routers.
- \[Simulations\](./simulations.md) — Dry-run actions before submitting on-chain.
- \[Events\](./events.md) — Monitor protocol activity through EventEmitter.
---
## Delegated trading integration
This page explains how to build delegated trading flows on GMX V2 using the subaccount and relay surfaces documented in \[Advanced entry points\](./advanced-entrypoints.md). It is intended for integrators who need an end-to-end implementation pattern, not just a function reference.
Use this guide when your application needs a model like:
- an account owner retains primary control of funds
- a delegated trader can place, update, and cancel orders
- delegated access expires automatically or is limited by action count
- your backend, relayer, or UI coordinates the signing flow
If you only need the raw contract surfaces, start with \[Advanced entry points\](./advanced-entrypoints.md). If you need read-path architecture and freshness guidance, also see the \[API integration guide\](../integration-guide.md) and \[Reader\](./reader.md).
## What GMX exposes
The delegated trading surface is built around:
- \`SubaccountGelatoRelayRouter\` for same-chain delegated order management (gasless, relay-based)
- \`MultichainSubaccountRouter\` for cross-chain delegated order management
- \`DataStore\` and \`Keys\` for delegated-access state such as expiry, action count, and integration id
A legacy \`SubaccountRouter\` contract is still deployed but is no longer used for order operations. The current GMX interface only calls it for wallet-based \`removeSubaccount(...)\` when the user is not going through the express flow. For new integrations, use \`SubaccountGelatoRelayRouter\` for same-chain delegated order execution and \`MultichainSubaccountRouter\` for cross-chain delegated order execution.
At the contract level, the main account can authorize or remove a subaccount, set an expiry timestamp for delegated actions, cap how many delegated actions may be performed, and bind a subaccount to an integration id. The delegated subaccount can then create, update, and cancel orders through the delegated trading surface.
## Permission model
The GMX subaccount model is scoped to delegated trading, not broad account delegation. Delegated access is designed for order management — it is narrower than giving a third party full account ownership, and it does not turn the delegated signer into a general-purpose owner of the account.
### Boundaries
| Area | Behavior |
| --- | --- |
| Order outputs | Constrained to the main account |
| Collateral and WNT | The delegated flow can spend the main account's collateral and WNT within the supported order flow |
| Deposits, withdrawals, shifts, claims | Not delegated — these use their own routers and flows |
For a summary of integration caveats, also review \[Known issues\](./known-issues.md).
## Roles in a delegated trading flow
Most integrations end up with three roles:
### 1. Main account owner
The owner wallet is the trust anchor for the trading account. It decides which delegated signer is allowed to trade, sets expiry and action-count limits, revokes delegated access, and optionally binds the subaccount to an \`integrationId\`.
### 2. Delegated trader or subaccount signer
This signer executes delegated trading actions within the limits the owner authorized. Depending on your design, it may be a key generated and stored locally in the user's browser for one-click trading, a key generated and managed by your backend or trading service, or a wallet controlled directly by a trader operating under your system's authorization flow.
### 3. Backend or relayer
Your backend may orchestrate owner-authorization flows, store or broker delegated session metadata, relay gasless order flow through \`SubaccountGelatoRelayRouter\`, and monitor expiry, action count, order lifecycle, and risk state.
## Common integration patterns
GMX supports multiple delegated trading patterns. The right one depends on your custody and trust model.
### Browser-local one-click signer
This is the closest match to the GMX interface's one-click trading flow described in \[Trading overview\](../../trading/overview.md#express-trading-and-one-click-trading). The delegated signer is created client-side, the key stays in the browser or local device storage, the owner authorizes delegated access with expiry and action limits, and the UI uses the delegated signer for order flow. This is the lowest-backend-custody model, but it shifts key-security risk to the browser environment.
### Backend-managed delegated signer
This pattern is useful when your product already operates managed trading infrastructure. Your backend provisions and manages the delegated signer, the owner authorizes that signer as a subaccount, and your backend handles session lifecycle, revocation, and monitoring. This gives you more operational control, but the delegated signer becomes part of your key-management perimeter — treat it as a hot operational key with strict lifecycle controls.
### Relay-first owner approval flow
This pattern is useful when you want owner-controlled authorization, delegated trading without repeated wallet popups, and gasless or sponsored execution. The owner signs the subaccount approval payload, the delegated signer signs the trade payload, and your relayer or backend submits through \`SubaccountGelatoRelayRouter\`. This is the most natural path when you want tight control over expiry, nonce handling, and replay protection while still delivering a low-friction user experience.
## Recommended end-to-end flow
The most common delegated trading sequence looks like this:
### Step 1 — Choose the delegated signer model
Decide whether the delegated signer will be browser-local, backend-managed, or externally controlled by the delegated trader.
### Step 2 — Create or identify the delegated signer
This signer becomes the subaccount address that the main account owner authorizes.
### Step 3 — Owner authorizes delegated trading
The owner enables delegated trading by setting the subaccount address, the delegated action type, expiry, maximum allowed action count, and an optional integration id.
### Step 4 — Store delegated session metadata
Your application should track:
| State | Notes |
| --- | --- |
| Subaccount address | The delegated signer's address |
| Authorization status | Whether the subaccount is currently active |
| Expiry | When delegated access expires |
| Remaining action budget | How many actions remain before re-authorization |
| Nonce state | Required if you are using relay-based approvals |
| Integration id | If you use one |
### Step 5 — Execute delegated orders
Use \`SubaccountGelatoRelayRouter\` for same-chain delegated order execution or \`MultichainSubaccountRouter\` for cross-chain delegated order execution.
### Step 6 — Monitor and refresh
Your system should detect expiry approaching, action count approaching the cap, nonce invalidation, and revoked delegated access.
### Step 7 — Re-authorize or revoke
When the delegated session is no longer valid, the owner can refresh authorization with a new expiry or action budget, or remove the subaccount entirely.
## Router selection
Use \`SubaccountGelatoRelayRouter\` for same-chain delegated trading. This is the primary delegated order path used by the current GMX interface — it supports gasless delegated order creation, updates, cancellation, and subaccount removal, with owner-signed approval payloads and delegated trade payloads in one relay flow. Use \`MultichainSubaccountRouter\` for cross-chain delegated trading flows.
A legacy \`SubaccountRouter\` contract remains deployed on all networks but is no longer used for order operations. The GMX interface only calls it for wallet-based subaccount removal outside the express flow.
## SDK, API, and contract responsibilities
GMX does not currently package delegated trading as a single turnkey integration surface. In practice, delegated trading integrations compose three layers:
| Layer | Role | Notes |
| --- | --- | --- |
| Contracts | Source of truth for delegated authorization, order execution, and expiry/action-count/integration-id enforcement | Always the canonical state |
| SDK | Typed read helpers, order-building convenience, and wallet-client integration | Useful in delegated flows, but you own the overall authorization and session architecture |
| API | Near-live positions and orders over HTTP, lighter-weight read integration, and separation between read polling and write submission | See \[API integration guide\](../integration-guide.md) for freshness and consistency expectations |
## Monitoring architecture
If delegated trading is part of a risk-managed product, design the monitoring layer intentionally rather than treating every read surface as interchangeable.
| Surface | Best for | Latency | Examples |
| --- | --- | --- | --- |
| \`Reader\`, \`DataStore\`, \`Multicall3\` | Tight on-chain state loops | Lowest — same-block | Subaccount expiry, action-count consumption, delegated access status, position state for risk controls |
| API and SDK reads | Application state and account views | Near-live | Dashboards, trader-facing views, normal order monitoring, eventual-consistency workflows after writes |
| GraphQL and indexed surfaces | History and analytics | Higher | Investigations, reporting, trade history |
:::tip
Treat API and SDK reads as near-live, not as a strict same-block risk engine. Do not rely only on indexed or historical surfaces for latency-sensitive delegated trading controls.
:::
See \[Overview\](./overview.md) for the read contracts and \[Reader\](./reader.md) for position and order helpers.
## Security guidance
Delegated trading is a security-sensitive integration. Keep these constraints in mind:
### Limit scope aggressively
Always use the protocol's built-in controls — expiry, maximum allowed action count, and optional integration id. Do not treat delegated access as open-ended if your use case does not require it.
### Be explicit about key custody
If you use a browser-local signer, the browser becomes part of the trust boundary — compromised local storage or injected scripts can compromise the delegated signer. If you use a backend-managed signer, your backend becomes part of the custody boundary, and you should treat the delegated signer as a hot key with planned revocation, rotation, and auditability.
### Avoid unnecessary private-key transport
If your integration can avoid transporting raw delegated private keys between backend and browser, that is generally the safer design. Prefer architectures where the delegated signer is generated client-side, or the backend signs on behalf of the delegated session without exposing raw key material to the browser.
### Separate read architecture from write architecture
Do not tie delegated trade submission and risk monitoring to the same fragile polling path. In production integrations, treat authorization and write flow, state polling, and risk enforcement as separate responsibilities, even if they are implemented by the same service.
## What GMX provides vs what your integration must provide
| GMX provides | Your integration provides |
| --- | --- |
| Delegated trading primitives | Signer custody design |
| Gasless relay primitives | User authorization UX |
| Owner-controlled expiry and action limits | Session lifecycle management |
| Read contracts and APIs for account state | Monitoring and risk architecture |
| Protocol-level enforcement, not custody | Key-security controls appropriate for your trust model |
## Next steps
- \[Advanced entry points\](./advanced-entrypoints.md) for the raw delegated trading surfaces
- \[Reader\](./reader.md) for position and order reads
- \[Overview\](./overview.md) for read contracts and multicall guidance
- \[Trading overview\](../../trading/overview.md#express-trading-and-one-click-trading) for the user-facing one-click trading model
- \[SDK v1 integration guide\](../../sdk/v1/integration-guide.md) for SDK operational notes
- \[API integration guide\](../integration-guide.md) for freshness, consistency, and read-surface guidance
---
## Event monitoring
All protocol events are emitted through a single \`EventEmitter\` contract. Every event carries an \`eventName\` field, so you can monitor any protocol action by filtering on the \`EventEmitter\` address plus the \`eventName\` value — without needing to track individual logic contract addresses, which may be upgraded over time.
The \`EventEmitter\` address for each network is listed on \[Contract addresses\](./addresses.md). For the full generated deployment inventory, see the \[gmx-synthetics docs folder\](https://github.com/gmx-io/gmx-synthetics/tree/updates/docs).
## Event types
The \`EventEmitter\` contract defines three structured event signatures that differ by the number of indexed \`bytes32\` topics:
| Event | Indexed topics | Use case |
| --- | --- | --- |
| \`EventLog\` | \`eventNameHash\` only | General events with no additional indexed lookup |
| \`EventLog1\` | \`eventNameHash\`, \`topic1\` | Events indexed by one key (for example, an action key) |
| \`EventLog2\` | \`eventNameHash\`, \`topic1\`, \`topic2\` | Events indexed by two keys (for example, market address and account) |
All three variants include \`msgSender\`, \`eventName\` (as a plain string), \`eventNameHash\` (indexed for filtering), and \`eventData\` (a structured \`EventUtils.EventLogData\` payload containing typed arrays of addresses, uints, ints, bools, bytes32 values, bytes, and strings).
The \`EventEmitter\` also exposes raw log functions (\`emitDataLog1\` through \`emitDataLog4\`) that emit unstructured logs using assembly. These are used for general-purpose data emission and don't follow the \`EventLog\` schema.
Which variant a specific protocol event uses depends on how the emitting contract calls the \`EventEmitter\`. Check the relevant contract source to determine the correct variant before setting up a filter.
## Example: monitoring Timelock actions with OpenZeppelin Defender
The following steps configure an alert that fires whenever an action is signalled on the \`TimelockConfig\` contract. Timelock signal events use \`EventLog1\` with \`eventName == "SignalPendingAction"\` and the action key as \`topic1\`.
1. In \[OpenZeppelin Defender\](https://defender.openzeppelin.com), select the "Monitor" (Sentinel) option.
2. Click "Create Monitor."
3. Enter a name for the monitor.
4. Select the target network.
5. Enter the \`EventEmitter\` address for that network in the "Addresses" field.
6. Under "Contract conditions," select "Events" > "EventLog1."
7. In the filter field below "EventLog1," enter \`eventName == "SignalPendingAction"\`.
8. Click "Next" and configure a notification channel.
With this configuration, you receive a notification each time an action is signalled on the Timelock.
---
## ExchangeRouter
The \`ExchangeRouter\` contract exposes the main protocol functions for creating orders, deposits, and withdrawals.
For an overview of the contract architecture and execution model, see \[Architecture\](./architecture.md).
## Creating an order
To create a swap, increase-position, or decrease-position order, you must first transfer the required tokens to the \`OrderVault\`, then call \`ExchangeRouter.createOrder\` in the same transaction.
:::warning
The token transfer and the \`ExchangeRouter.createOrder\` call must occur in a single transaction. If they are separated, other users may withdraw the transferred tokens before your order is created.
:::
See the \[ExchangeRouter tests\](https://github.com/gmx-io/gmx-synthetics/blob/updates/test/router/ExchangeRouter.ts) for a complete example.
### ExchangeRouter.createOrder
\`\`\`solidity
function createOrder(IBaseOrderUtils.CreateOrderParams calldata params) returns (bytes32)
\`\`\`
Use this to create swap, increase, or decrease orders through the router. For increase and swap orders, transfer the execution fee and any input collateral to the \`OrderVault\` in the same transaction, usually via \`multicall\`.
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
await usdc.approve(router.address, collateralAmount);
await exchangeRouter.multicall(
\[\
exchangeRouter.interface.encodeFunctionData("sendWnt", \[orderVault.address, executionFee\]),\
exchangeRouter.interface.encodeFunctionData("sendTokens", \[usdc.address, orderVault.address, collateralAmount\]),\
exchangeRouter.interface.encodeFunctionData("createOrder", \[\
{\
addresses: {\
receiver: trader.address,\
cancellationReceiver: trader.address,\
callbackContract: ethers.constants.AddressZero,\
uiFeeReceiver: ethers.constants.AddressZero,\
market: marketToken,\
initialCollateralToken: usdc.address,\
swapPath: \[\],\
},\
numbers: {\
sizeDeltaUsd,\
initialCollateralDeltaAmount: collateralAmount,\
triggerPrice: 0,\
acceptablePrice,\
executionFee,\
callbackGasLimit: 0,\
minOutputAmount: 0,\
validFromTime: 0,\
},\
orderType: OrderType.MarketIncrease,\
decreasePositionSwapType: DecreasePositionSwapType.NoSwap,\
isLong: true,\
shouldUnwrapNativeToken: false,\
autoCancel: false,\
referralCode: ethers.constants.HashZero,\
dataList: \[\],\
},\
\]),\
\],
{ value: executionFee }
);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| --------- | ----------------------------------- | ------------------------------------- |
| \`params\` | \`IBaseOrderUtils.CreateOrderParams\` | Struct containing order configuration |
### CreateOrderParams
The order struct is split into address fields, numeric fields, and a small set of enums and flags.
| Field | Description |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| \`addresses\` | Group of address fields listed in \[CreateOrderParamsAddresses\](#createorderparamsaddresses). |
| \`numbers\` | Group of numeric fields listed in \[CreateOrderParamsNumbers\](#createorderparamsnumbers). |
| \`orderType\` | Order type enum listed in \[OrderType\](#ordertype). |
| \`decreasePositionSwapType\` | Swap behavior for decrease orders listed in \[DecreasePositionSwapType\](#decreasepositionswaptype). |
| \`isLong\` | \`true\` for a long position, \`false\` for a short position. |
| \`shouldUnwrapNativeToken\` | Whether to unwrap the native token on output. For example, if the output token is WETH and this is \`true\`, the contract converts WETH to ETH before sending. |
| \`autoCancel\` | For \`LimitDecrease\` and \`StopLossDecrease\` orders, whether the order is cancelled automatically when the position closes. Ignored for all other order types. |
| \`referralCode\` | Referral code to set for the trader alongside order creation. If the trader already has a referral code set, this parameter has no effect. |
| \`dataList\` | Array of additional \`bytes32\` data. Pass an empty array if no extra data is needed. |
### CreateOrderParamsAddresses
| Field | Description |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| \`receiver\` | Address that receives any output amounts. |
| \`cancellationReceiver\` | If the order is cancelled, collateral and the network fee gas are sent to this address if it is not the zero address. |
| \`callbackContract\` | Contract to call on order execution or cancellation. |
| \`uiFeeReceiver\` | Address that receives the UI fee. |
| \`market\` | Market to trade in. |
| \`initialCollateralToken\` | Initial collateral token transferred into the contract. |
| \`swapPath\` | Array of market addresses to swap \`initialCollateralToken\` through. For increase and swap orders, the token is swapped before entering the position. For decrease orders, the output is swapped through these markets. |
### CreateOrderParamsNumbers
| Field | Description |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| \`sizeDeltaUsd\` | Position size to increase or decrease. |
| \`initialCollateralDeltaAmount\` | Amount of input collateral sent to the \`OrderVault\` for swap and increase orders, or collateral amount to withdraw for decrease orders. |
| \`triggerPrice\` | Trigger price for \`LimitIncrease\`, \`LimitDecrease\`, and \`StopLossDecrease\` orders. The keeper attempts execution when price reaches this level. |
| \`acceptablePrice\` | Price at which the order can execute. For market orders, the order is cancelled if it cannot execute at this price. For limit and stop-loss orders, execution is skipped if the trigger price is reached but the acceptable price cannot be filled. |
| \`executionFee\` | Amount of native token (for example, ETH on Arbitrum) included as the execution fee. This is the maximum fee keepers can use to execute the order. Any excess is returned to the order account. See \[Execution Fee\](./fees.md#execution-fee) for details. |
| \`callbackGasLimit\` | Gas limit passed to the callback contract on order execution or cancellation. |
| \`minOutputAmount\` | For swap orders, the minimum token output amount. For increase orders, the minimum token amount after \`initialCollateralDeltaAmount\` is swapped through \`swapPath\`. For decrease orders, this is the minimum USD value, because decrease orders can produce two output tokens: the profit token and the withdrawn collateral token. |
| \`validFromTime\` | Timestamp from which the order becomes valid for execution. The keeper skips the order until \`block.timestamp\` reaches this value. Pass \`0\` for immediate validity. |
### OrderType
| Value | Description |
| ------------------ | ---------------------------------------------------------------------------------------------------------------- |
| \`MarketSwap\` | Execute a swap at the current market price. |
| \`LimitSwap\` | Execute a swap when \`minOutputAmount\` can be filled. |
| \`MarketIncrease\` | Open or increase a long or short position at market price. |
| \`LimitIncrease\` | Open or increase a position when the trigger price is reached. |
| \`MarketDecrease\` | Close or reduce a position at market price. |
| \`LimitDecrease\` | Close or reduce a position when the trigger price is reached. |
| \`StopLossDecrease\` | Close or reduce a position when price falls to the trigger level. |
| \`Liquidation\` | Forced position closure triggered by the protocol when margin requirements are no longer met. Not user-callable. |
| \`StopIncrease\` | Open or increase a position when the stop price is reached. |
### DecreasePositionSwapType
| Value | Description |
| ------------------------------- | --------------------------------------------------------------------- |
| \`NoSwap\` | No swap is performed. |
| \`SwapPnlTokenToCollateralToken\` | The profit token is swapped to the collateral token, if possible. |
| \`SwapCollateralTokenToPnlToken\` | The withdrawn collateral is swapped to the profit token, if possible. |
## Creating a deposit
To create a deposit, you must first transfer tokens to the \`DepositVault\`, then call \`ExchangeRouter.createDeposit\` in the same transaction.
:::warning
The token transfer and the \`ExchangeRouter.createDeposit\` call must occur in a single transaction. If they are separated, other users may withdraw the transferred tokens before your deposit is created.
:::
If this transaction reverts, the token transfer also reverts, so no funds remain in the \`DepositVault\`. If the deposit request is created successfully and is later cancelled, the initial deposit tokens are returned to the account that created the deposit, and any unused execution fee is refunded separately.
See the \[ExchangeRouter tests\](https://github.com/gmx-io/gmx-synthetics/blob/updates/test/router/ExchangeRouter.ts) for a complete example.
### ExchangeRouter.createDeposit
\`\`\`solidity
function createDeposit(IDepositUtils.CreateDepositParams calldata params) returns (bytes32)
\`\`\`
Use this to add liquidity to a GM market. Transfer the execution fee and any long / short input tokens to the \`DepositVault\` in the same transaction, usually via \`multicall\`.
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
await usdc.approve(router.address, shortTokenAmount);
await exchangeRouter.multicall(
\[\
exchangeRouter.interface.encodeFunctionData("sendWnt", \[depositVault.address, executionFee\]),\
exchangeRouter.interface.encodeFunctionData("sendTokens", \[usdc.address, depositVault.address, shortTokenAmount\]),\
exchangeRouter.interface.encodeFunctionData("createDeposit", \[\
{\
addresses: {\
receiver: liquidityProvider.address,\
callbackContract: ethers.constants.AddressZero,\
uiFeeReceiver: ethers.constants.AddressZero,\
market: marketToken,\
initialLongToken: longToken,\
initialShortToken: usdc.address,\
longTokenSwapPath: \[\],\
shortTokenSwapPath: \[\],\
},\
minMarketTokens,\
shouldUnwrapNativeToken: false,\
executionFee,\
callbackGasLimit: 0,\
dataList: \[\],\
},\
\]),\
\],
{ value: executionFee }
);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| --------- | ----------------------------------- | --------------------------------------- |
| \`params\` | \`IDepositUtils.CreateDepositParams\` | Struct containing deposit configuration |
### CreateDepositParams
| Field | Description |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| \`receiver\` | Address that receives the GM tokens. |
| \`callbackContract\` | Contract to call on deposit execution or cancellation. |
| \`uiFeeReceiver\` | Address that receives the UI fee. |
| \`market\` | Market to deposit into. |
| \`initialLongToken\` | Long token transferred into the contract. |
| \`initialShortToken\` | Short token transferred into the contract. |
| \`longTokenSwapPath\` | Array of market addresses to swap \`initialLongToken\` through before depositing. |
| \`shortTokenSwapPath\` | Array of market addresses to swap \`initialShortToken\` through before depositing. |
| \`minMarketTokens\` | Minimum acceptable amount of GM tokens to receive. |
| \`shouldUnwrapNativeToken\` | Whether to unwrap the native token if the deposit is cancelled. For example, if \`initialLongToken\` is WETH and this is \`true\`, the contract converts WETH to ETH before refunding. |
| \`executionFee\` | Amount of native token (for example, ETH on Arbitrum) included as the execution fee. This is the maximum fee keepers can use to execute the deposit. Any excess is returned to the deposit account. See \[Execution Fee\](./fees.md#execution-fee) for details. |
| \`callbackGasLimit\` | Gas limit passed to the callback contract on deposit execution or cancellation. |
| \`dataList\` | Array of additional \`bytes32\` data. Pass an empty array if no extra data is needed. |
## Creating a withdrawal
To create a withdrawal through \`ExchangeRouter\`, send the GM market tokens and execution fee to the \`WithdrawalVault\` and call \`ExchangeRouter.createWithdrawal\` in the same transaction, usually via \`multicall\`.
### ExchangeRouter.createWithdrawal
\`\`\`solidity
function createWithdrawal(IWithdrawalUtils.CreateWithdrawalParams calldata params) returns (bytes32)
\`\`\`
Use this to create an asynchronous withdrawal request. Transfer the GM market tokens and execution fee to the \`WithdrawalVault\` in the same transaction, usually via \`multicall\`. The withdrawal size is determined by the GM market token amount sent to \`WithdrawalVault\` with \`sendTokens\`.
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
await marketToken.approve(router.address, marketTokenAmount);
await exchangeRouter.multicall(
\[\
exchangeRouter.interface.encodeFunctionData("sendWnt", \[withdrawalVault.address, executionFee\]),\
exchangeRouter.interface.encodeFunctionData("sendTokens", \[\
marketToken.address,\
withdrawalVault.address,\
marketTokenAmount,\
\]),\
exchangeRouter.interface.encodeFunctionData("createWithdrawal", \[\
{\
addresses: {\
receiver: trader.address,\
callbackContract: ethers.constants.AddressZero,\
uiFeeReceiver: ethers.constants.AddressZero,\
market: marketToken.address,\
longTokenSwapPath: \[\],\
shortTokenSwapPath: \[\],\
},\
minLongTokenAmount,\
minShortTokenAmount,\
shouldUnwrapNativeToken: false,\
executionFee,\
callbackGasLimit: 0,\
dataList: \[\],\
},\
\]),\
\],
{ value: executionFee }
);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| --------- | ----------------------------------------- | ------------------------------------------ |
| \`params\` | \`IWithdrawalUtils.CreateWithdrawalParams\` | Struct containing withdrawal configuration |
### CreateWithdrawalParams
The GM market token amount to withdraw is not part of \`CreateWithdrawalParams\`. It is set by the amount sent to \`WithdrawalVault\` in the preceding \`sendTokens\` call.
| Field | Description |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| \`receiver\` | Address that receives the withdrawn tokens. |
| \`callbackContract\` | Contract to call on withdrawal execution or cancellation. |
| \`uiFeeReceiver\` | Address that receives the UI fee. |
| \`market\` | Market to withdraw from. |
| \`longTokenSwapPath\` | Array of market addresses to swap the withdrawn long token through. |
| \`shortTokenSwapPath\` | Array of market addresses to swap the withdrawn short token through. |
| \`minLongTokenAmount\` | Minimum output amount of long token after swapping through \`longTokenSwapPath\`. For example, if WETH is swapped to BTC, this specifies the minimum BTC amount. |
| \`minShortTokenAmount\` | Minimum output amount of short token after swapping through \`shortTokenSwapPath\`. |
| \`shouldUnwrapNativeToken\` | Whether to unwrap the native token on output. For example, if the output token is WETH and this is \`true\`, the contract converts WETH to ETH before sending. |
| \`executionFee\` | Amount of native token (for example, ETH on Arbitrum) included as the execution fee. This is the maximum fee keepers can use to execute the withdrawal. Any excess is returned to the withdrawal account. See \[Execution Fee\](./fees.md#execution-fee) for details. |
| \`callbackGasLimit\` | Gas limit passed to the callback contract on withdrawal execution or cancellation. |
| \`dataList\` | Array of additional \`bytes32\` data. Pass an empty array if no extra data is needed. |
## Creating an atomic withdrawal
An atomic withdrawal executes synchronously without waiting for a keeper. It uses on-chain Chainlink price feeds rather than off-chain oracle data, so only tokens with a registered \`ChainlinkPriceFeedProvider\` are supported.
### ExchangeRouter.executeAtomicWithdrawal
\`\`\`solidity
function executeAtomicWithdrawal(
IWithdrawalUtils.CreateWithdrawalParams calldata params,
OracleUtils.SetPricesParams calldata oracleParams
)
\`\`\`
Use this to withdraw synchronously using on-chain Chainlink prices instead of the normal keeper flow. Swaps are not supported, so both swap paths must be empty. As with standard withdrawals, the withdrawal size is determined by the GM market token amount sent to \`WithdrawalVault\`.
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
await marketToken.approve(router.address, marketTokenAmount);
await exchangeRouter.multicall(
\[\
exchangeRouter.interface.encodeFunctionData("sendWnt", \[withdrawalVault.address, executionFee\]),\
exchangeRouter.interface.encodeFunctionData("sendTokens", \[\
marketToken.address,\
withdrawalVault.address,\
marketTokenAmount,\
\]),\
exchangeRouter.interface.encodeFunctionData("executeAtomicWithdrawal", \[\
{\
addresses: {\
receiver: trader.address,\
callbackContract: ethers.constants.AddressZero,\
uiFeeReceiver: ethers.constants.AddressZero,\
market: marketToken.address,\
longTokenSwapPath: \[\],\
shortTokenSwapPath: \[\],\
},\
minLongTokenAmount,\
minShortTokenAmount,\
shouldUnwrapNativeToken: false,\
executionFee,\
callbackGasLimit: 0,\
dataList: \[\],\
},\
{\
tokens: \[indexToken.address, longToken.address, shortToken.address\],\
providers: \[\
chainlinkPriceFeedProvider.address,\
chainlinkPriceFeedProvider.address,\
chainlinkPriceFeedProvider.address,\
\],\
data: \["0x", "0x", "0x"\],\
},\
\]),\
\],
{ value: executionFee }
);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| -------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| \`params\` | \`IWithdrawalUtils.CreateWithdrawalParams\` | Withdrawal configuration, using the same fields as a standard withdrawal with the constraints listed in \[CreateWithdrawalParams for atomic withdrawal\](#createwithdrawalparams-for-atomic-withdrawal). |
| \`oracleParams\` | \`OracleUtils.SetPricesParams\` | Oracle price inputs required for atomic execution. |
### CreateWithdrawalParams for atomic withdrawal
| Field | Description |
| -------------------- | -------------------------------------------------------------- |
| \`longTokenSwapPath\` | Must be empty. Swaps are not supported for atomic withdrawals. |
| \`shortTokenSwapPath\` | Must be empty. Swaps are not supported for atomic withdrawals. |
| All other fields | Same as \[CreateWithdrawalParams\](#createwithdrawalparams). |
### OracleUtils.SetPricesParams
| Field | Description |
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| \`tokens\` | Array of token addresses: the index token, long token, and short token of the market. |
| \`providers\` | Array of price providers for each token. Use the \`ChainlinkPriceFeedProvider\` address found in the \`deployments\` folder. To check whether a token is supported, call \`dataStore.getAddress(Keys.priceFeedKey(token))\` and verify the result is not the zero address. |
| \`data\` | Array of provider data. Pass an array of \`0x\` empty bytes for Chainlink feeds. |
## Creating a shift
A shift moves liquidity from one GM market to another in a single request. Instead of withdrawing from the source market and depositing into the destination market separately, you can use \`createShift\` to do both atomically. Transfer the GM market tokens from the source market and the execution fee to the \`ShiftVault\` before calling \`ExchangeRouter.createShift\` in the same transaction.
:::warning
The token transfer and the \`ExchangeRouter.createShift\` call must occur in a single transaction. If they are separated, other users may withdraw the transferred tokens before your shift is created.
:::
### ExchangeRouter.createShift
\`\`\`solidity
function createShift(IShiftUtils.CreateShiftParams calldata params) returns (bytes32)
\`\`\`
Use this to move GM liquidity from one market to another. Transfer the source market's GM tokens and the execution fee to the \`ShiftVault\` in the same transaction, usually via \`multicall\`. The shift amount is determined by the GM token amount sent to \`ShiftVault\` with \`sendTokens\`.
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
await sourceMarketToken.approve(router.address, marketTokenAmount);
await exchangeRouter.multicall(
\[\
exchangeRouter.interface.encodeFunctionData("sendWnt", \[shiftVault.address, executionFee\]),\
exchangeRouter.interface.encodeFunctionData("sendTokens", \[\
sourceMarketToken.address,\
shiftVault.address,\
marketTokenAmount,\
\]),\
exchangeRouter.interface.encodeFunctionData("createShift", \[\
{\
addresses: {\
receiver: account.address,\
callbackContract: ethers.constants.AddressZero,\
uiFeeReceiver: ethers.constants.AddressZero,\
fromMarket: sourceMarketToken.address,\
toMarket: destinationMarketToken.address,\
},\
minMarketTokens,\
executionFee,\
callbackGasLimit: 0,\
dataList: \[\],\
},\
\]),\
\],
{ value: executionFee }
);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| --------- | --------------------------------- | ------------------------------------- |
| \`params\` | \`IShiftUtils.CreateShiftParams\` | Struct containing shift configuration |
\*\*Returns:\*\* \`bytes32\` -- the unique key identifying the shift request.
### CreateShiftParams
The GM market token amount to shift is not part of \`CreateShiftParams\`. It is set by the amount sent to \`ShiftVault\` in the preceding \`sendTokens\` call.
| Field | Description |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| \`receiver\` | Address that receives the destination market's GM tokens. |
| \`callbackContract\` | Contract to call on shift execution or cancellation. |
| \`uiFeeReceiver\` | Address that receives the UI fee. |
| \`fromMarket\` | Source GM market to withdraw liquidity from. |
| \`toMarket\` | Destination GM market to deposit liquidity into. |
| \`minMarketTokens\` | Minimum acceptable amount of destination GM tokens to receive. |
| \`executionFee\` | Amount of native token (for example, ETH on Arbitrum) included as the execution fee. This is the maximum fee keepers can use to execute the shift. Any excess is returned to the shift account. See \[Execution Fee\](./fees.md#execution-fee) for details. |
| \`callbackGasLimit\` | Gas limit passed to the callback contract on shift execution or cancellation. |
| \`dataList\` | Array of additional \`bytes32\` data. Pass an empty array if no extra data is needed. |
## Updating an order
You can modify the parameters of an existing pending order by calling \`updateOrder\`. Only the order's creator can update it, and market orders can't be updated. Any additional WNT transferred to the contract during the update is added to the order's execution fee.
### ExchangeRouter.updateOrder
\`\`\`solidity
function updateOrder(
bytes32 key,
uint256 sizeDeltaUsd,
uint256 acceptablePrice,
uint256 triggerPrice,
uint256 minOutputAmount,
uint256 validFromTime,
bool autoCancel
)
\`\`\`
Use this to change the parameters of a pending limit or trigger order. The order is also unfrozen if it was previously frozen due to an execution error.
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ---------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| \`key\` | \`bytes32\` | Unique key of the order to update, returned by \`createOrder\`. |
| \`sizeDeltaUsd\` | \`uint256\` | New position size delta in USD. |
| \`acceptablePrice\`| \`uint256\` | New acceptable execution price. For long increase orders, the order is cancelled if the execution price is greater than \`acceptablePrice\`. For short increase orders, the order is cancelled if the execution price is less than \`acceptablePrice\`. |
| \`triggerPrice\` | \`uint256\` | New trigger price for limit and stop-loss orders. |
| \`minOutputAmount\`| \`uint256\` | New minimum output amount for swap orders or minimum USD value for decrease orders. |
| \`validFromTime\` | \`uint256\` | New timestamp from which the order becomes valid. Pass \`0\` for immediate validity. |
| \`autoCancel\` | \`bool\` | Whether to automatically cancel the order when the associated position closes. Only applies to \`LimitDecrease\` and \`StopLossDecrease\` orders. |
## Cancelling requests
You can cancel pending orders, deposits, withdrawals, and shifts that you created. When a request is cancelled, the deposited funds and any unused execution fee are returned to the creator. Cancellation is subject to a delay period -- the request must have been pending for at least the configured \`requestExpirationTime\` before it can be cancelled. If you attempt to cancel too early, the transaction reverts with \`RequestNotYetCancellable\`.
### ExchangeRouter.cancelOrder
\`\`\`solidity
function cancelOrder(bytes32 key)
\`\`\`
Cancels a pending order. Only the order's creator can cancel it.
\*\*Parameters:\*\*
| Parameter | Type | Description |
| --------- | --------- | ------------------------------------------------------------ |
| \`key\` | \`bytes32\` | Unique key of the order to cancel, returned by \`createOrder\`.|
### ExchangeRouter.cancelDeposit
\`\`\`solidity
function cancelDeposit(bytes32 key)
\`\`\`
Cancels a pending deposit. Only the deposit's creator can cancel it. The initial deposit tokens are returned to the creator's account.
\*\*Parameters:\*\*
| Parameter | Type | Description |
| --------- | --------- | ---------------------------------------------------------------- |
| \`key\` | \`bytes32\` | Unique key of the deposit to cancel, returned by \`createDeposit\`.|
### ExchangeRouter.cancelWithdrawal
\`\`\`solidity
function cancelWithdrawal(bytes32 key)
\`\`\`
Cancels a pending withdrawal. Only the withdrawal's creator can cancel it. The GM market tokens are returned to the creator's account.
\*\*Parameters:\*\*
| Parameter | Type | Description |
| --------- | --------- | ------------------------------------------------------------------------ |
| \`key\` | \`bytes32\` | Unique key of the withdrawal to cancel, returned by \`createWithdrawal\`. |
### ExchangeRouter.cancelShift
\`\`\`solidity
function cancelShift(bytes32 key)
\`\`\`
Cancels a pending shift. Only the shift's creator can cancel it. The source market's GM tokens are returned to the creator's account.
\*\*Parameters:\*\*
| Parameter | Type | Description |
| --------- | --------- | ------------------------------------------------------------------ |
| \`key\` | \`bytes32\` | Unique key of the shift to cancel, returned by \`createShift\`. |
## Setting a callback contract
You can set a persistent callback contract for a specific market. The protocol uses this saved callback contract for liquidations and auto-deleveraging (ADL), where no user-initiated order exists to specify a callback. This lets your contract receive notifications when your position is liquidated or reduced by ADL.
### ExchangeRouter.setSavedCallbackContract
\`\`\`solidity
function setSavedCallbackContract(address market, address callbackContract)
\`\`\`
Saves a callback contract for the caller's account in the given market. The protocol calls this contract during liquidation and ADL events for that account and market.
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ------------------ | --------- | ---------------------------------------------------------------------------------- |
| \`market\` | \`address\` | Market address to associate the callback contract with. |
| \`callbackContract\` | \`address\` | Contract address to call on liquidation or ADL. Pass the zero address to remove it.|
## Claiming fees and rewards
These functions let you claim accumulated fees and rewards across multiple markets in a single transaction. The \`markets\` and \`tokens\` arrays must have the same length -- each index pairs a market with the token to claim.
### ExchangeRouter.claimFundingFees
\`\`\`solidity
function claimFundingFees(
address\[\] memory markets,
address\[\] memory tokens,
address receiver
) returns (uint256\[\] memory)
\`\`\`
Claims accumulated positive funding fees for the caller across the specified market-token pairs. Funding fees accrue when you hold a position on the less-crowded side of a market.
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ---------- | ----------- | ----------------------------------------------------------------------------- |
| \`markets\` | \`address\[\]\` | Array of market addresses to claim funding fees from. |
| \`tokens\` | \`address\[\]\` | Array of token addresses, one per market, specifying which token to claim. |
| \`receiver\` | \`address\` | Address that receives the claimed funding fees. |
\*\*Returns:\*\* \`uint256\[\]\` -- the amount claimed for each market-token pair.
### ExchangeRouter.claimCollateral
\`\`\`solidity
function claimCollateral(
address\[\] memory markets,
address\[\] memory tokens,
uint256\[\] memory timeKeys,
address receiver
) returns (uint256\[\] memory)
\`\`\`
Claims collateral that was capped due to negative price impact. When a position's price impact is capped, the excess amount is stored and becomes claimable over time as the price impact factor recovers. Each claim is keyed by the timestamp when the capped amount was recorded.
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ---------- | ----------- | ---------------------------------------------------------------------------------------- |
| \`markets\` | \`address\[\]\` | Array of market addresses to claim collateral from. |
| \`tokens\` | \`address\[\]\` | Array of token addresses, one per market, specifying which token to claim. |
| \`timeKeys\` | \`uint256\[\]\` | Array of timestamps identifying the specific capped collateral entries to claim. |
| \`receiver\` | \`address\` | Address that receives the claimed collateral. |
\*\*Returns:\*\* \`uint256\[\]\` -- the amount claimed for each entry.
### ExchangeRouter.claimAffiliateRewards
\`\`\`solidity
function claimAffiliateRewards(
address\[\] memory markets,
address\[\] memory tokens,
address receiver
) returns (uint256\[\] memory)
\`\`\`
Claims accumulated affiliate (referral) rewards for the caller across the specified market-token pairs. Rewards accrue when traders you referred generate trading fees.
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ---------- | ----------- | -------------------------------------------------------------------------------- |
| \`markets\` | \`address\[\]\` | Array of market addresses to claim affiliate rewards from. |
| \`tokens\` | \`address\[\]\` | Array of token addresses, one per market, specifying which token to claim. |
| \`receiver\` | \`address\` | Address that receives the claimed affiliate rewards. |
\*\*Returns:\*\* \`uint256\[\]\` -- the amount claimed for each market-token pair.
## UI fee configuration
These functions let an integration configure its UI fee factor and claim accumulated UI fees.
### ExchangeRouter.setUiFeeFactor
\`\`\`solidity
function setUiFeeFactor(uint256 uiFeeFactor)
\`\`\`
Sets the UI fee factor for the caller's account. The factor is stored in the protocol configuration and is applied when users submit actions with your address as \`uiFeeReceiver\`.
\*\*Parameters:\*\*
| Parameter | Type | Description |
| -------------- | --------- | --------------------------------------------------------------------------- |
| \`uiFeeFactor\` | \`uint256\` | UI fee percentage in 30-decimal precision. The value must not exceed \`MAX\_UI\_FEE\_FACTOR\`. |
### ExchangeRouter.claimUiFees
\`\`\`solidity
function claimUiFees(
address\[\] memory markets,
address\[\] memory tokens,
address receiver
) returns (uint256\[\] memory)
\`\`\`
Claims accumulated UI fees for the caller across the specified market-token pairs. The caller address (\`msg.sender\`) is treated as the \`uiFeeReceiver\` whose balance is being claimed.
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ---------- | ----------- | ------------------------------------------------------------------------- |
| \`markets\` | \`address\[\]\` | Array of market addresses to claim UI fees from. |
| \`tokens\` | \`address\[\]\` | Array of token addresses, one per market, specifying which token to claim. |
| \`receiver\` | \`address\` | Address that receives the claimed UI fees. |
\*\*Returns:\*\* \`uint256\[\]\` -- the amount claimed for each market-token pair.
---
## Fees(Contracts)
This page documents fee types, execution fee calculation, and how to retrieve fee parameters from the DataStore.
## UI fee
UI fees are charged on top of the base protocol fee. The percentage is based on the \`uiFeeFactor\` configured for the \`uiFeeReceiver\` address you pass when creating an action. For more information, see \[Running a frontend\](../frontend-integration.md#running-a-frontend).
Configure the UI fee percentage for your address by calling \`ExchangeRouter.setUiFeeFactor\`. The \`uiFeeFactor\` is a percentage value over \`10^30\`. For example, if the \`uiFeeFactor\` is \`2 \* 10^25\`, the percentage charged is \`(2 \* 10^25) / (10^30) = 0.00002 = 0.002%\`. The call reverts with \`InvalidUiFeeFactor\` if the value exceeds the maximum.
The maximum \`uiFeeFactor\` is capped by \`dataStore.getUint(Keys.MAX\_UI\_FEE\_FACTOR)\`.
You can pass the \`uiFeeReceiver\` value for the following actions:
- Deposits
- Withdrawals
- Swap orders
- Increase and decrease position orders (Market Increase, Limit Increase, Market Decrease, Limit Decrease, Stop-Loss, Take-Profit)
- GLV deposits
- GLV withdrawals
- Shifts
For deposits, withdrawals, and swaps, the fee is a percentage of the input amount. For increase and decrease position orders, the fee is a percentage of the position size change.
UI fees are credited when deposits, withdrawals, and orders execute. Call \`ExchangeRouter.claimUiFees\` to claim accumulated fees at any time. The caller's address (\`msg.sender\`) is used as the \`uiFeeReceiver\` for the claim.
## Execution fee
Creating a deposit, order, withdrawal, shift, GLV deposit, or GLV withdrawal request requires sending an \`executionFee\` as the transaction value.
During creation, the contracts verify that the provided \`executionFee\` is at least the minimum, calculated as:
\`\`\`
tx.gasprice \* GasUtils.adjustGasLimitForEstimate(dataStore, estimatedGasLimit, oraclePriceCount)
\`\`\`
To calculate the \`estimatedGasLimit\`, use the appropriate function:
- For deposits: \`GasUtils.estimateExecuteDepositGasLimit\`
- For withdrawals: \`GasUtils.estimateExecuteWithdrawalGasLimit\`
- For orders: \`GasUtils.estimateExecuteOrderGasLimit\`
- For shifts: \`GasUtils.estimateExecuteShiftGasLimit\`
- For GLV deposits: \`GasUtils.estimateExecuteGlvDepositGasLimit\`
- For GLV withdrawals: \`GasUtils.estimateExecuteGlvWithdrawalGasLimit\`
Because \`tx.gasprice\` fluctuates based on network usage, add a buffer to reduce the risk of the creation transaction reverting. If the provided \`executionFee\` is below the minimum, the transaction reverts with \`InsufficientExecutionFee\`. Upon execution, any excess execution fee is refunded to the request's \`account\` address.
## Funding
For an overview of how funding fees work, see \[adaptive funding\](../../trading/fees.md#adaptive-funding).
Retrieve funding fee parameters from the \[DataStore\](./overview.md#reading-values) using these keys. All keys are per-market.
| Key | Description |
| --- | --- |
| \`FUNDING\_FACTOR\` | Base funding factor per second |
| \`FUNDING\_EXPONENT\_FACTOR\` | Exponent applied to the open interest imbalance ratio |
| \`FUNDING\_INCREASE\_FACTOR\_PER\_SECOND\` | Rate at which the funding factor increases per second |
| \`FUNDING\_DECREASE\_FACTOR\_PER\_SECOND\` | Rate at which the funding factor decreases per second |
| \`MIN\_FUNDING\_FACTOR\_PER\_SECOND\` | Minimum funding factor per second |
| \`MAX\_FUNDING\_FACTOR\_PER\_SECOND\` | Maximum funding factor per second |
| \`THRESHOLD\_FOR\_STABLE\_FUNDING\` | Imbalance threshold below which funding stays stable |
| \`THRESHOLD\_FOR\_DECREASE\_FUNDING\` | Imbalance threshold below which the funding factor decreases |
## Borrowing
For an overview of how borrow fees work, see \[borrow fees\](../../trading/fees.md#borrow-fees).
Retrieve borrow fee parameters from the \[DataStore\](./overview.md#reading-values) using these keys. Each market uses one of the two models below.
### Kink model
| Key | Description |
| --- | --- |
| \`OPTIMAL\_USAGE\_FACTOR\` | Utilization threshold where the rate slope increases |
| \`BASE\_BORROWING\_FACTOR\` | Base rate factor below optimal utilization |
| \`ABOVE\_OPTIMAL\_USAGE\_BORROWING\_FACTOR\` | Rate factor applied above optimal utilization |
### Curve (power) model
| Key | Description |
| --- | --- |
| \`BORROWING\_FACTOR\` | Per-market borrowing factor for longs and shorts |
| \`BORROWING\_EXPONENT\_FACTOR\` | Per-market exponent for longs and shorts |
| \`SKIP\_BORROWING\_FEE\_FOR\_SMALLER\_SIDE\` | If true, the side with smaller open interest pays zero borrow fees |
## Position and swap fees
Retrieve position and swap fee parameters from the \[DataStore\](./overview.md#reading-values) using these keys. Fee factors are percentage values over \`10^30\`.
### Position fees
| Key | Description |
| --- | --- |
| \`POSITION\_FEE\_FACTOR\` | Percentage fee deducted on position increase and decrease, based on position size change |
| \`POSITION\_IMPACT\_FACTOR\` | Price impact factor for position actions |
| \`MAX\_POSITION\_IMPACT\_FACTOR\` | Cap on negative price impact for positions |
| \`MAX\_POSITION\_IMPACT\_FACTOR\_FOR\_LIQUIDATIONS\` | Cap on negative price impact applied during liquidations |
| \`POSITION\_IMPACT\_EXPONENT\_FACTOR\` | Exponent for position price impact calculation |
| \`POSITION\_IMPACT\_POOL\_DISTRIBUTION\_RATE\` | Rate at which the position impact pool is distributed to the market pool |
| \`PRO\_DISCOUNT\_FACTOR\` | Fee discount factor applied to pro-tier traders |
### Swap fees
| Key | Description |
| --- | --- |
| \`SWAP\_FEE\_FACTOR\` | Percentage fee deducted on swaps, based on swap amount |
| \`ATOMIC\_SWAP\_FEE\_FACTOR\` | Percentage fee deducted on atomic swaps using on-chain price feeds |
| \`SWAP\_IMPACT\_FACTOR\` | Price impact factor for swaps |
| \`SWAP\_IMPACT\_EXPONENT\_FACTOR\` | Exponent for swap price impact calculation |
| \`ATOMIC\_SWAP\_FEE\_TYPE\` | Type flag that determines the atomic swap fee behavior |
### Deposit and withdrawal fees
| Key | Description |
| --- | --- |
| \`DEPOSIT\_FEE\_FACTOR\` | Percentage fee deducted on deposits, based on deposit amount |
| \`WITHDRAWAL\_FEE\_FACTOR\` | Percentage fee deducted on withdrawals, based on withdrawal amount |
| \`ATOMIC\_WITHDRAWAL\_FEE\_FACTOR\` | Percentage fee deducted on atomic withdrawals using on-chain price feeds |
### Liquidation fees
| Key | Description |
| --- | --- |
| \`LIQUIDATION\_FEE\_FACTOR\` | Percentage fee deducted when a position is liquidated |
### Fee receiver factors
These parameters control the share of collected fees allocated to the fee receiver. Each is a percentage value over \`10^30\`.
| Key | Description |
| --- | --- |
| \`POSITION\_FEE\_RECEIVER\_FACTOR\` | Share of position fees allocated to the fee receiver |
| \`SWAP\_FEE\_RECEIVER\_FACTOR\` | Share of swap fees allocated to the fee receiver |
| \`BORROWING\_FEE\_RECEIVER\_FACTOR\` | Share of borrow fees allocated to the fee receiver |
| \`LIQUIDATION\_FEE\_RECEIVER\_FACTOR\` | Share of liquidation fees allocated to the fee receiver |
## Relay fees
These parameters control fee calculation for Gelato relay (gasless) transactions.
| Key | Description |
| --- | --- |
| \`GELATO\_RELAY\_FEE\_MULTIPLIER\_FACTOR\` | Multiplier applied to the relay fee calculation |
| \`GELATO\_RELAY\_FEE\_BASE\_AMOUNT\` | Base fee amount for relay transactions |
## Atomic operation parameters
These parameters control behavior for atomic (synchronous) operations that use on-chain price feeds.
| Key | Description |
| --- | --- |
| \`MAX\_ATOMIC\_ORACLE\_PRICE\_AGE\` | Maximum acceptable age for oracle prices in atomic operations |
## Advanced parameters
These parameters control specialized protocol behavior.
| Key | Description |
| --- | --- |
| \`DATA\_STREAM\_SPREAD\_REDUCTION\_FACTOR\` | Factor applied to reduce the bid-ask spread from data stream oracle prices |
| \`GLV\_SHIFT\_MAX\_LOSS\_FACTOR\` | Maximum acceptable loss factor when executing GLV shifts |
| \`BUYBACK\_GMX\_FACTOR\` | Factor controlling GMX token buyback from protocol fees |
| \`BUYBACK\_MAX\_PRICE\_IMPACT\_FACTOR\` | Maximum price impact allowed for buyback operations |
---
## GlvReader
The \`GlvReader\` contract provides read-only functions for querying GMX Liquidity Vault (GLV) data from on-chain storage.
For GM market reader functions, see \[Reader\](./reader.md).
This page focuses on the most commonly used GLV read helpers. For the full public surface, see \[\`GlvReader.sol\`\](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/reader/GlvReader.sol).
Examples below assume you already have contract instances such as \`glvReader\` and \`dataStore\`, plus any required price structs.
## Getting a list of GLVs
Use \`getGlvs\` to retrieve all registered GLV vaults.
### GlvReader.getGlvs
\`\`\`solidity
function getGlvs(DataStore dataStore, uint256 start, uint256 end)
external view returns (Glv.Props\[\] memory)
\`\`\`
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
const glvs = await glvReader.getGlvs(dataStore.address, 0, 20);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`start\` | \`uint256\` | Start index for pagination |
| \`end\` | \`uint256\` | End index for pagination |
\*\*Returns:\*\* Array of \`Glv.Props\`.
### Glv.Props
| Field | Type | Description |
| ------------ | --------- | -------------------------- |
| \`glvToken\` | \`address\` | Address of the GLV token |
| \`longToken\` | \`address\` | Address of the long token |
| \`shortToken\` | \`address\` | Address of the short token |
## Getting GLV info with market list
Use \`getGlvInfoList\` to retrieve GLV vaults together with the markets each vault is exposed to.
### GlvReader.getGlvInfoList
\`\`\`solidity
function getGlvInfoList(DataStore dataStore, uint256 start, uint256 end)
external view returns (GlvInfo\[\] memory)
\`\`\`
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
const glvInfoList = await glvReader.getGlvInfoList(dataStore.address, 0, 20);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`start\` | \`uint256\` | Start index for pagination |
| \`end\` | \`uint256\` | End index for pagination |
\*\*Returns:\*\* Array of \`GlvInfo\` elements, each containing a \`Glv.Props\` and a list of market addresses.
## Getting GLV value
Use \`getGlvValue\` to retrieve the total GLV vault value before converting it into a token price.
### GlvReader.getGlvValue
\`\`\`solidity
function getGlvValue(
DataStore dataStore,
address\[\] memory marketAddresses,
Price.Props\[\] memory indexTokenPrices,
Price.Props memory longTokenPrice,
Price.Props memory shortTokenPrice,
address glv,
bool maximize
) external view returns (uint256)
\`\`\`
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
const glvValue = await glvReader.getGlvValue(
dataStore.address,
marketAddresses,
indexTokenPrices,
longTokenPrice,
shortTokenPrice,
glvAddress,
true
);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ------------------ | --------------- | --------------------------------------------------------------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`marketAddresses\` | \`address\[\]\` | Addresses of the markets inside the GLV |
| \`indexTokenPrices\` | \`Price.Props\[\]\` | Prices for the index tokens of each GLV market. The order must match \`marketAddresses\`. |
| \`longTokenPrice\` | \`Price.Props\` | Price of the long token |
| \`shortTokenPrice\` | \`Price.Props\` | Price of the short token |
| \`glv\` | \`address\` | Address of the GLV vault |
| \`maximize\` | \`bool\` | When \`true\`, uses maximum token prices. When \`false\`, uses minimum prices. |
\*\*Returns:\*\* Total GLV vault value in 30-decimal USD precision.
## Getting GLV token price
Use \`getGlvTokenPrice\` to retrieve the GLV token price, total vault value, and total supply.
### GlvReader.getGlvTokenPrice
\`\`\`solidity
function getGlvTokenPrice(
DataStore dataStore,
address\[\] memory marketAddresses,
Price.Props\[\] memory indexTokenPrices,
Price.Props memory longTokenPrice,
Price.Props memory shortTokenPrice,
address glv,
bool maximize
) external view returns (uint256, uint256, uint256)
\`\`\`
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
const \[glvPrice, glvValue, totalSupply\] = await glvReader.getGlvTokenPrice(
dataStore.address,
marketAddresses,
indexTokenPrices,
longTokenPrice,
shortTokenPrice,
glvAddress,
true
);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ------------------ | --------------- | --------------------------------------------------------------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`marketAddresses\` | \`address\[\]\` | Addresses of the markets inside the GLV |
| \`indexTokenPrices\` | \`Price.Props\[\]\` | Prices for the index tokens of each GLV market. The order must match \`marketAddresses\`. |
| \`longTokenPrice\` | \`Price.Props\` | Price of the long token |
| \`shortTokenPrice\` | \`Price.Props\` | Price of the short token |
| \`glv\` | \`address\` | Address of the GLV vault |
| \`maximize\` | \`bool\` | When \`true\`, uses maximum token prices. When \`false\`, uses minimum prices. |
\*\*Returns:\*\* A tuple of \`(uint256 price, uint256 glvValue, uint256 totalSupply)\`.
## Direct GLV lookups
Use these methods when you already have a GLV address or deployment salt and want the raw stored object.
### GlvReader.getGlv
\`\`\`solidity
function getGlv(DataStore dataStore, address glv)
external view returns (Glv.Props memory)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`glv\` | \`address\` | GLV token address |
\*\*Returns:\*\* \`Glv.Props\` for the requested GLV.
### GlvReader.getGlvInfo
\`\`\`solidity
function getGlvInfo(DataStore dataStore, address glv)
public view returns (GlvInfo memory)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`glv\` | \`address\` | GLV token address |
\*\*Returns:\*\* \`GlvInfo\`, containing the GLV props plus its supported market list.
### GlvReader.getGlvBySalt
\`\`\`solidity
function getGlvBySalt(DataStore dataStore, bytes32 salt)
external view returns (Glv.Props memory)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`salt\` | \`bytes32\` | Deterministic GLV deployment salt |
\*\*Returns:\*\* \`Glv.Props\` for the requested GLV.
## GLV deposit requests
Use these methods to inspect GLV deposit requests by key, globally, or for one account.
### GlvReader.getGlvDeposit
\`\`\`solidity
function getGlvDeposit(DataStore dataStore, bytes32 key)
external view returns (GlvDeposit.Props memory)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`key\` | \`bytes32\` | GLV deposit request key |
\*\*Returns:\*\* Raw \`GlvDeposit.Props\` for the request.
### GlvReader.getGlvDeposits
\`\`\`solidity
function getGlvDeposits(
DataStore dataStore,
uint256 start,
uint256 end
) external view returns (GlvDeposit.Props\[\] memory)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`start\` | \`uint256\` | Start index for pagination |
| \`end\` | \`uint256\` | End index for pagination |
\*\*Returns:\*\* Array of \`GlvDeposit.Props\` values.
### GlvReader.getAccountGlvDeposits
\`\`\`solidity
function getAccountGlvDeposits(
DataStore dataStore,
address account,
uint256 start,
uint256 end
) external view returns (GlvDeposit.Props\[\] memory)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | ------------------------------------ |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`account\` | \`address\` | Account to retrieve GLV deposits for |
| \`start\` | \`uint256\` | Start index for pagination |
| \`end\` | \`uint256\` | End index for pagination |
\*\*Returns:\*\* Array of \`GlvDeposit.Props\` values for the account.
## GLV withdrawal requests
Use these methods to inspect GLV withdrawal requests by key, globally, or for one account.
### GlvReader.getGlvWithdrawal
\`\`\`solidity
function getGlvWithdrawal(DataStore dataStore, bytes32 key)
external view returns (GlvWithdrawal.Props memory)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`key\` | \`bytes32\` | GLV withdrawal request key |
\*\*Returns:\*\* Raw \`GlvWithdrawal.Props\` for the request.
### GlvReader.getGlvWithdrawals
\`\`\`solidity
function getGlvWithdrawals(
DataStore dataStore,
uint256 start,
uint256 end
) external view returns (GlvWithdrawal.Props\[\] memory)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`start\` | \`uint256\` | Start index for pagination |
| \`end\` | \`uint256\` | End index for pagination |
\*\*Returns:\*\* Array of \`GlvWithdrawal.Props\` values.
### GlvReader.getAccountGlvWithdrawals
\`\`\`solidity
function getAccountGlvWithdrawals(
DataStore dataStore,
address account,
uint256 start,
uint256 end
) external view returns (GlvWithdrawal.Props\[\] memory)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | --------------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`account\` | \`address\` | Account to retrieve GLV withdrawals for |
| \`start\` | \`uint256\` | Start index for pagination |
| \`end\` | \`uint256\` | End index for pagination |
\*\*Returns:\*\* Array of \`GlvWithdrawal.Props\` values for the account.
## GLV shift requests
Use these methods to inspect GLV shift requests by key or through paginated lists.
### GlvReader.getGlvShift
\`\`\`solidity
function getGlvShift(DataStore dataStore, bytes32 key)
external view returns (GlvShift.Props memory)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`key\` | \`bytes32\` | GLV shift request key |
\*\*Returns:\*\* Raw \`GlvShift.Props\` for the request.
### GlvReader.getGlvShifts
\`\`\`solidity
function getGlvShifts(
DataStore dataStore,
uint256 start,
uint256 end
) external view returns (GlvShift.Props\[\] memory)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`start\` | \`uint256\` | Start index for pagination |
| \`end\` | \`uint256\` | End index for pagination |
\*\*Returns:\*\* Array of \`GlvShift.Props\` values.
---
## GlvRouter
The \`GlvRouter\` contract is the main entry point for creating and cancelling GLV (GMX Liquidity Vault) deposits and withdrawals. It works similarly to the \[ExchangeRouter\](./exchange-router.md) but targets GLV vaults instead of individual GM markets.
For an overview of the contract architecture and execution model, see \[Architecture\](./architecture.md).
## Creating a GLV deposit
To create a GLV deposit, you must first transfer the required tokens to the \`GlvVault\`, then call \`GlvRouter.createGlvDeposit\` in the same transaction.
:::warning
The token transfer and the \`GlvRouter.createGlvDeposit\` call must occur in a single transaction. If they are separated, other users may withdraw the transferred tokens before your deposit is created.
:::
You can deposit in two ways:
- \*\*Underlying tokens\*\* -- Transfer long and short tokens to the \`GlvVault\`. The protocol mints GM tokens internally, then mints GLV tokens to the receiver.
- \*\*GM market tokens\*\* -- Transfer GM tokens directly to the \`GlvVault\` by setting \`isMarketTokenDeposit\` to \`true\`. The protocol skips the GM minting step and mints GLV tokens to the receiver.
If this transaction reverts, the token transfer also reverts, so no funds remain in the \`GlvVault\`. If the deposit request is created successfully and is later cancelled, the initial deposit tokens are returned to the account that created the deposit, and any unused execution fee is refunded separately.
### GlvRouter.createGlvDeposit
\`\`\`solidity
function createGlvDeposit(
IGlvDepositUtils.CreateGlvDepositParams calldata params
) external payable returns (bytes32)
\`\`\`
Use this to add liquidity to a GLV vault. Transfer the execution fee and any long / short input tokens (or GM tokens) to the \`GlvVault\` in the same transaction, usually via \`multicall\`.
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
await usdc.approve(router.address, shortTokenAmount);
await glvRouter.multicall(
\[\
glvRouter.interface.encodeFunctionData("sendWnt", \[glvVault.address, executionFee\]),\
glvRouter.interface.encodeFunctionData("sendTokens", \[usdc.address, glvVault.address, shortTokenAmount\]),\
glvRouter.interface.encodeFunctionData("createGlvDeposit", \[\
{\
addresses: {\
glv: glvToken.address,\
market: marketToken,\
receiver: liquidityProvider.address,\
callbackContract: ethers.constants.AddressZero,\
uiFeeReceiver: ethers.constants.AddressZero,\
initialLongToken: longToken,\
initialShortToken: usdc.address,\
longTokenSwapPath: \[\],\
shortTokenSwapPath: \[\],\
},\
minGlvTokens,\
executionFee,\
callbackGasLimit: 0,\
shouldUnwrapNativeToken: false,\
isMarketTokenDeposit: false,\
dataList: \[\],\
},\
\]),\
\],
{ value: executionFee }
);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| --------- | --------------------------------------------- | ------------------------------------------- |
| \`params\` | \`IGlvDepositUtils.CreateGlvDepositParams\` | Struct containing GLV deposit configuration |
\*\*Returns:\*\* \`bytes32\` -- the key that identifies this GLV deposit request.
### CreateGlvDepositParams
The deposit struct is split into address fields and a set of numeric fields and flags.
| Field | Description |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| \`addresses\` | Group of address fields listed in \[CreateGlvDepositParamsAddresses\](#createglvdepositparamsaddresses). |
| \`minGlvTokens\` | Minimum acceptable amount of GLV tokens to receive. |
| \`executionFee\` | Amount of native token (for example, ETH on Arbitrum) included as the execution fee. This is the maximum fee keepers can use to execute the deposit. Any excess is returned to the deposit account. See \[Execution Fee\](./fees.md#execution-fee) for details. |
| \`callbackGasLimit\` | Gas limit passed to the callback contract on deposit execution or cancellation. |
| \`shouldUnwrapNativeToken\` | Whether to unwrap the native token if the deposit is cancelled. For example, if \`initialLongToken\` is WETH and this is \`true\`, the contract converts WETH to ETH before refunding. |
| \`isMarketTokenDeposit\` | Set to \`true\` when depositing GM market tokens directly instead of underlying long/short tokens. When \`true\`, \`initialLongToken\` and \`initialShortToken\` must be the zero address, and both swap paths must be empty. |
| \`dataList\` | Array of additional \`bytes32\` data. Pass an empty array if no extra data is needed. |
### CreateGlvDepositParamsAddresses
| Field | Description |
| -------------------- | --------------------------------------------------------------------------------------- |
| \`glv\` | Address of the GLV vault to deposit into. |
| \`market\` | GM market to deposit into. Must be a market that the GLV vault supports. |
| \`receiver\` | Address that receives the GLV tokens. |
| \`callbackContract\` | Contract to call on deposit execution or cancellation. |
| \`uiFeeReceiver\` | Address that receives the UI fee. |
| \`initialLongToken\` | Long token transferred into the contract. Set to the zero address for GM token deposits.|
| \`initialShortToken\` | Short token transferred into the contract. Set to the zero address for GM token deposits.|
| \`longTokenSwapPath\` | Array of market addresses to swap \`initialLongToken\` through before depositing. |
| \`shortTokenSwapPath\` | Array of market addresses to swap \`initialShortToken\` through before depositing. |
## Creating a GLV withdrawal
To create a GLV withdrawal, send the GLV tokens and execution fee to the \`GlvVault\` and call \`GlvRouter.createGlvWithdrawal\` in the same transaction, usually via \`multicall\`.
:::warning
The token transfer and the \`GlvRouter.createGlvWithdrawal\` call must occur in a single transaction. If they are separated, other users may withdraw the transferred tokens before your withdrawal is created.
:::
### GlvRouter.createGlvWithdrawal
\`\`\`solidity
function createGlvWithdrawal(
IGlvWithdrawalUtils.CreateGlvWithdrawalParams calldata params
) external payable returns (bytes32)
\`\`\`
Use this to create an asynchronous GLV withdrawal request. Transfer the GLV tokens and execution fee to the \`GlvVault\` in the same transaction, usually via \`multicall\`. The withdrawal size is determined by the GLV token amount sent to the \`GlvVault\` with \`sendTokens\`.
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
await glvToken.approve(router.address, glvTokenAmount);
await glvRouter.multicall(
\[\
glvRouter.interface.encodeFunctionData("sendWnt", \[glvVault.address, executionFee\]),\
glvRouter.interface.encodeFunctionData("sendTokens", \[\
glvToken.address,\
glvVault.address,\
glvTokenAmount,\
\]),\
glvRouter.interface.encodeFunctionData("createGlvWithdrawal", \[\
{\
addresses: {\
receiver: trader.address,\
callbackContract: ethers.constants.AddressZero,\
uiFeeReceiver: ethers.constants.AddressZero,\
market: marketToken.address,\
glv: glvToken.address,\
longTokenSwapPath: \[\],\
shortTokenSwapPath: \[\],\
},\
minLongTokenAmount,\
minShortTokenAmount,\
shouldUnwrapNativeToken: false,\
executionFee,\
callbackGasLimit: 0,\
dataList: \[\],\
},\
\]),\
\],
{ value: executionFee }
);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| --------- | --------------------------------------------------- | ---------------------------------------------- |
| \`params\` | \`IGlvWithdrawalUtils.CreateGlvWithdrawalParams\` | Struct containing GLV withdrawal configuration |
\*\*Returns:\*\* \`bytes32\` -- the key that identifies this GLV withdrawal request.
### CreateGlvWithdrawalParams
The GLV token amount to withdraw is not part of \`CreateGlvWithdrawalParams\`. It is set by the amount sent to the \`GlvVault\` in the preceding \`sendTokens\` call.
| Field | Description |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| \`addresses\` | Group of address fields listed in \[CreateGlvWithdrawalParamsAddresses\](#createglvwithdrawalparamsaddresses). |
| \`minLongTokenAmount\` | Minimum output amount of long token after swapping through \`longTokenSwapPath\`. For example, if WETH is swapped to BTC, this specifies the minimum BTC amount. |
| \`minShortTokenAmount\` | Minimum output amount of short token after swapping through \`shortTokenSwapPath\`. |
| \`shouldUnwrapNativeToken\` | Whether to unwrap the native token on output. For example, if the output token is WETH and this is \`true\`, the contract converts WETH to ETH before sending. |
| \`executionFee\` | Amount of native token (for example, ETH on Arbitrum) included as the execution fee. This is the maximum fee keepers can use to execute the withdrawal. Any excess is returned to the withdrawal account. See \[Execution Fee\](./fees.md#execution-fee) for details. |
| \`callbackGasLimit\` | Gas limit passed to the callback contract on withdrawal execution or cancellation. |
| \`dataList\` | Array of additional \`bytes32\` data. Pass an empty array if no extra data is needed. |
### CreateGlvWithdrawalParamsAddresses
| Field | Description |
| -------------------- | ------------------------------------------------------------------------ |
| \`receiver\` | Address that receives the withdrawn tokens. |
| \`callbackContract\` | Contract to call on withdrawal execution or cancellation. |
| \`uiFeeReceiver\` | Address that receives the UI fee. |
| \`market\` | GM market to withdraw from. Must be a market that the GLV vault supports.|
| \`glv\` | Address of the GLV vault to withdraw from. |
| \`longTokenSwapPath\` | Array of market addresses to swap the withdrawn long token through. |
| \`shortTokenSwapPath\` | Array of market addresses to swap the withdrawn short token through. |
## Cancelling GLV requests
You can cancel a pending GLV deposit or withdrawal if it hasn't been executed yet. Only the account that created the request can cancel it.
### GlvRouter.cancelGlvDeposit
\`\`\`solidity
function cancelGlvDeposit(bytes32 key) external
\`\`\`
Cancels a pending GLV deposit. The deposited tokens and any unused execution fee are returned to the original account.
\*\*Parameters:\*\*
| Parameter | Type | Description |
| --------- | --------- | -------------------------------------------- |
| \`key\` | \`bytes32\` | Key of the GLV deposit request to cancel |
### GlvRouter.cancelGlvWithdrawal
\`\`\`solidity
function cancelGlvWithdrawal(bytes32 key) external
\`\`\`
Cancels a pending GLV withdrawal. The GLV tokens and any unused execution fee are returned to the original account.
\*\*Parameters:\*\*
| Parameter | Type | Description |
| --------- | --------- | ---------------------------------------------- |
| \`key\` | \`bytes32\` | Key of the GLV withdrawal request to cancel |
## Simulating GLV execution
You can dry-run GLV deposits and withdrawals before keeper execution. These simulation helpers are publicly callable on \`GlvRouter\`, but the real execution path remains keeper-only on \`GlvDepositHandler.executeGlvDeposit\` and \`GlvWithdrawalHandler.executeGlvWithdrawal\`. Like the simulation helpers on \`ExchangeRouter\`, these calls execute with supplied oracle prices and revert with \`EndOfOracleSimulation\` on success, so they are typically used through \`eth\_call\` or \`callStatic\`-style preflight checks rather than as standalone state-changing transactions.
### GlvRouter.simulateExecuteGlvDeposit
\`\`\`solidity
function simulateExecuteGlvDeposit(
bytes32 key,
OracleUtils.SimulatePricesParams memory simulatedOracleParams
)
\`\`\`
Simulates execution for a specific GLV deposit request key.
### GlvRouter.simulateExecuteLatestGlvDeposit
\`\`\`solidity
function simulateExecuteLatestGlvDeposit(
OracleUtils.SimulatePricesParams memory simulatedOracleParams
)
\`\`\`
Simulates execution for the latest created GLV deposit request.
### GlvRouter.simulateExecuteGlvWithdrawal
\`\`\`solidity
function simulateExecuteGlvWithdrawal(
bytes32 key,
OracleUtils.SimulatePricesParams memory simulatedOracleParams
)
\`\`\`
Simulates execution for a specific GLV withdrawal request key.
### GlvRouter.simulateExecuteLatestGlvWithdrawal
\`\`\`solidity
function simulateExecuteLatestGlvWithdrawal(
OracleUtils.SimulatePricesParams memory simulatedOracleParams
)
\`\`\`
Simulates execution for the latest created GLV withdrawal request.
## External swaps before GLV actions
\`GlvRouter\` also exposes \`makeExternalCalls(...)\` through its \`ExternalHandler\` integration. Use this when you need to perform an external swap or aggregator call before creating the GLV request, then refund any residual tokens back to the intended receivers.
## Next steps
- \[GLV Reader\](./glv-reader.md) -- Query GLV vault data and pricing
- \[Simulations\](./simulations.md) -- Dry-run GLV actions
- \[Contract addresses\](./addresses.md) -- GlvRouter and GlvVault addresses per chain
- \[ExchangeRouter\](./exchange-router.md) -- GM market operations
---
## Known issues
This page is based on the known issues section of the \[gmx-synthetics repository\](https://github.com/gmx-io/gmx-synthetics/blob/updates/README.md#known-issues), with corrections and additions. It is intended for integrators, auditors, and developers building on top of the GMX contracts.
## Tokens
These constraints apply to tokens used with the protocol.
- Collateral tokens must be whitelisted with a configured \`TOKEN\_TRANSFER\_GAS\_LIMIT\`.
- Rebasing tokens, tokens that change balance on transfer, tokens with burns, tokens with callbacks (for example, ERC-777 tokens), and similar non-standard tokens are not compatible with the system and must not be whitelisted.
## Keepers
These items describe known keeper behavior and limitations.
- Order keepers can use prices from different timestamps for limit orders with a swap, which leads to different output amounts.
- Order keepers are expected to validate whether a transaction will revert before sending it, to minimize gas wastage.
- Order keepers may cause requests to be cancelled instead of executed by executing the request with insufficient gas.
- If an execution transaction requires a large amount of gas close to the maximum block gas limit, it may be possible to stuff blocks to prevent the transaction from being included.
- On certain blockchains, the keeper can control the \`tx.gasprice\` used to execute a transaction, which affects the execution fee paid to the keeper.
- A malicious user can intentionally unbalance a market to create high price impact, preventing order execution. This is expected to be costly and difficult to benefit from.
## Price impact
These items describe known limitations of the price impact mechanism.
- Price impact can be reduced by using positions and swaps across markets, chains, forks, and other protocols. Virtual inventory tracking partially mitigates this.
- A user can reduce price impact by using high-leverage positions. The \`MIN\_COLLATERAL\_FACTOR\_FOR\_OPEN\_INTEREST\_MULTIPLIER\` value partially mitigates this.
- Price impact calculations don't account for fees or the effects of the price impact itself. In most cases, the effect on the calculation is expected to be small.
## Market token price
These items describe edge cases in market token pricing.
- It is rare but possible for a pool's value to become negative. This can happen because the \`impactPoolAmount\` and pending PnL are subtracted from the worth of the tokens in the pool.
- Due to the difference in positive and negative position price impact, virtual token amounts can build up in the position impact pool, which affects the pricing of market tokens. The position impact pool must be gradually distributed if needed.
## Virtual inventory
Virtual inventory tracking has the following constraints.
- Virtual inventory tracks the amount of tokens in pools. Tokens in each grouping must be the same type and have the same decimals — the long tokens across pools in the group must have the same decimals, and the short tokens across pools in the group must have the same decimals. For example, because USDC has 6 decimals and DAI has 18 decimals, markets like ETH-USDC and ETH-DAI must not be grouped.
- Virtual IDs must be set before market creation or token whitelisting. If set after trading for the token or market has occurred, the tracking won't be accurate and may need to be adjusted.
## Blockchain
These items cover blockchain-level risks and mitigations.
- For L2s with sequencers, there is no contract validation to check if the L2 sequencer is active. Oracle keepers must stop signing prices if the sequencer stops producing blocks. When the sequencer resumes, oracle keepers must sign prices for the latest blocks using the latest fetched prices.
- If an L2 sequencer is down, it may prevent deposits into positions to prevent liquidations.
- For transactions that can be executed entirely using on-chain price feeds, it may be possible to take advantage of stale pricing due to price latency or the chain being down. On-chain price feeds must be temporary, and low-latency feeds must be used instead once all tokens are supported.
- Block re-orgs could allow a user to retroactively cancel an order after it has been executed if price didn't move favorably for the user. Handle this case if using the contracts on chains where long re-orgs are possible.
- Updating and cancellation of orders could be front-run to prevent order execution. This is not expected to be an issue if the probability of successful front-running is \`<= 50%\`. If the probability is higher than 50%, fees and price impact must be adjusted to ensure the strategy is not net profitable. Adjusting the UI fee or referral discount could similarly be used to cause order cancellations.
- During downtime of the blockchain or oracle, orders may be executed at significantly different prices or may not execute if the order's acceptable price can't be fulfilled.
- There is a dependency on the accuracy of the block timestamp because oracle prices are validated against this value. For blockchains where nodes have some control over the timestamp, set the \`oracleTimestampAdjustment\` to a value that makes manipulation of the timestamp unprofitable.
## GLV
These items describe known risks specific to GLV vaults.
- The GLV shift feature can be exploited by temporarily increasing the utilization in a market that typically has low utilization. Once the keeper executes the shift, the attacker can lower the utilization back to normal levels. Position fees and price impact must be configured to make this attack expensive enough to cover the GLV loss.
- A GLV may contain GM markets that are above their maximum \`pnlToPoolFactorForTraders\`. If a GM market's \`maxPnlFactorForDeposits\` is higher than \`maxPnlFactorForTraders\`, the GM market is valued lower during deposits than it will be once traders have realized their capped profits. A malicious user may observe a GM market in this condition and deposit into the GLV to gain from the ADLs that follow. To avoid this, \`maxPnlFactorForDeposits\` must be less than or equal to \`maxPnlFactorForTraders\`.
- It is technically possible for market value to become negative. In this case, the GLV is unusable until the market value becomes positive.
- GM tokens could become illiquid due to high PnL factor or high reserved USD. Users can deposit illiquid GM tokens into a GLV and withdraw liquidity from a different market, leaving the GLV with illiquid tokens. The \`glvMaxMarketTokenBalanceUsd\` and \`glvMaxMarketTokenBalanceAmount\` parameters must account for the riskiness of a market to avoid accumulating too many GM tokens from a risky market.
## Factories
This item describes a known behavior in market and GLV factory contracts.
- When adding a market with the \`MarketStoreUtils.set\` function, the market receives a lookup where the market address can be obtained with the market salt. This lookup is not cleared on market deletion. The same applies to GLV.
## Notes
These notes cover deployment, configuration, and upgrade procedures.
### Deployment
These items cover the initial deployment verification process.
- Use \`scripts/verifyFallback.ts\` to verify contracts.
- One MarketToken contract needs to be verified using \`npx hardhat verify\`. After that, all MarketToken contracts are verified because the source code is the same.
### Configuration
This item covers a key configuration parameter.
- \`MAX\_ORACLE\_REF\_PRICE\_DEVIATION\_FACTOR\` is a sanity check that helps guard against incorrect oracle decimal configuration or incorrect price feed configuration. Set this to a sufficiently high value to prevent reverts during times of high volatility.
### Upgrades
These items describe considerations when upgrading contracts.
- If new contracts lead to a difference in pricing (for example, of market tokens) between old and new contracts, disable the old contracts before enabling the new ones.
- Notify external protocols that use the Reader contract or potentially outdated pricing calculations to use the latest contracts and calculations (for example, Chainlink price feeds for GM tokens).
- Publish a best-effort changelog documenting important changes that integrations must be aware of (for example, if a field is added to a struct passed into a callback function). These changes may not be obvious to integrations.
- If the contracts support equity synthetic markets, ensure that stock splits and similar changes can be handled.
- Contracts with the \`CONTROLLER\` role have access to important functions such as setting DataStore values. Ensure that such contracts don't have generic functions that can be used to change important values.
- Add tests for the different market types (for example, spot-only markets, single-token markets).
- Don't modify the ordering of values in the \`eventData\` for callbacks unless strictly necessary, because callback contracts may reference values by a fixed index.
- If a struct passed into callbacks is changed (for example, Deposit, Withdrawal, Order structs), callback contracts expecting the previous struct stop working. Highlight struct changes to integrations.
- If the referral system is in use, the OrderHandler must be given access to update the referral code for traders.
## Integrations
These items describe integration considerations for protocols building on the GMX contracts.
### General
These general considerations apply to all integrations.
- Deposits, withdrawals, and orders may be cancelled if the requirements specified in the request can't be fulfilled (for example, minimum output amount). Check where funds and gas refunds are sent on cancellation to ensure it matches expectations.
- Decrease position orders can output two tokens instead of one if the decrease position swap fails. The output amount and collateral may also not be sufficient to cover fees, causing the order not to be executed.
- If there is a large spread, opening or closing a position can significantly change the min and max price of the market token. This must not be manipulatable in a profitable way.
- Changes in config values such as \`FUNDING\_FACTOR\`, \`THRESHOLD\_FOR\_STABLE\_FUNDING\`, \`BORROWING\_FACTOR\`, \`SKIP\_BORROWING\_FEE\_FOR\_SMALLER\_SIDE\`, and \`BORROWING\_FEE\_RECEIVER\_FACTOR\` could lead to additional charges for users and changes in market token price.
- If trader PnL is capped due to \`MAX\_PNL\_FACTOR\_FOR\_TRADERS\`, the percentage of profit paid out to traders may differ depending on the order in which positions are decreased or closed, because the cap is recalculated based on the current state of the pool.
- Event data may be passed to callback contracts. The ordering of params in the \`eventData\` is kept unchanged where possible, so params can be accessed by index. For safety, validate the key of each param before use to confirm it matches the expected value.
- Some parameters such as \`order.sizeDelta\` and \`order.initialCollateralDeltaAmount\` may be updated during execution. The updated values may not be passed to the callback contract.
- Callback contracts may need to whitelist the DepositHandler, OrderHandler, or WithdrawalHandler. New versions of these handlers may be deployed as new code is added, and two handlers can temporarily exist at the same time (for example, OrderHandler(1), OrderHandler(2)). The callback contract must be able to whitelist and simultaneously accept callbacks from multiple handlers.
- Instead of maintaining a separate whitelist for each handler type, validate the role of \`msg.sender\` in the RoleStore — for example, \`RoleStore.hasRole(msg.sender, Role.CONTROLLER)\`. This checks that \`msg.sender\` is a valid handler.
- If the user can choose which ExchangeRouter to interact with, don't assume the callback params are a fixed format. During transitions between old and new contracts, callbacks for functions such as \`afterOrderCancellation\` could be in either format. If only a specific ExchangeRouter can trigger the callback, this is not an issue.
- Addresses of contracts such as the ExchangeRouter, Oracle, or Reader change as new logic is added.
- When contracts such as the ExchangeRouter, Oracle, or Reader are updated, effort is made to keep function parameters the same. However, this may not always be possible (for example, if a new order property requires changing the \`ExchangeRouter.createOrder\` params).
- The RoleStore and DataStore for deployments must not change. If they are changed, a migration of funds from the previous contracts to the new contracts is likely needed.
- While the code is structured to minimize the risk of \[read-only reentrancy\](https://officercia.mirror.xyz/DBzFiDuxmDOTQEbfXhvLdK0DXVpKu1Nkurk0Cqk3QKc), guard against this possibility.
- Token airdrops may occur to accounts of GM token holders. Integrating contracts holding GM tokens must be able to claim these tokens, otherwise the tokens are locked. One approach is to allow claiming of tokens that aren't market tokens — check using the \`Keys.MARKET\_LIST\` value.
- ETH transfers are sent with \`NATIVE\_TOKEN\_TRANSFER\_GAS\_LIMIT\` for the gas limit. If the transfer fails due to insufficient gas or other errors, ETH is sent as WETH instead.
- Accounts may receive ETH for ADLs or liquidations. If the account can't receive ETH, WETH is sent instead.
- Positive price impact is capped by the amount of tokens in the impact pools and by configured values.
- Negative price impact may be capped by configured values.
- If negative price impact is capped, the additional amount is kept in the claimable collateral pool. Claim it manually using \`ExchangeRouter.claimCollateral\`.
- Positive funding fees must be manually claimed using \`ExchangeRouter.claimFundingFees\`.
- Affiliate rewards must be manually claimed using \`ExchangeRouter.claimAffiliateRewards\`.
- Markets or features may be disabled.
- Execution continues even if a callback reverts.
- Ensure callbacks have sufficient gas.
- Subaccounts can create, update, and cancel any order for an account.
- Subaccounts can spend WNT and collateral from the account.
- UI fees can be changed.
- Referral discounts can be changed.
- Funds for blacklisted addresses are kept within the protocol.
- The index token is not always the long token.
- Fee rates change depending on whether there is a positive or negative impact.
### Deposits
These items apply to deposit integrations.
- Consider PnL factor when estimating GM price.
- Handle deposit cancellations.
- Ensure only handlers with the \`CONTROLLER\` role can call the \`afterDepositExecution\` and \`afterDepositCancellation\` callback functions.
- Ensure only the correct deposit execution can call callback functions.
- Consider markets with the same long and short token — swaps aren't supported for these markets.
- Consider positive and negative price impact.
- There is a request cancellation period for a configured delay during which deposit requests can't be cancelled.
- Output amounts are subject to price impact and fees.
- Deposits aren't allowed above the \`MAX\_PNL\_FACTOR\_FOR\_DEPOSITS\`.
- The first deposit in any market must go to the \`RECEIVER\_FOR\_FIRST\_DEPOSIT\`.
### Withdrawals
These items apply to withdrawal integrations.
- Two minimum outputs must be used for withdrawals.
- Handle withdrawal cancellations.
- Ensure only handlers with the \`CONTROLLER\` role can call the \`afterWithdrawalExecution\` and \`afterWithdrawalCancellation\` callback functions.
- Ensure only the correct withdrawal execution can call callback functions.
- Consider markets with the same long and short token — swaps aren't supported for these markets.
- Consider positive and negative price impact.
- There is a request cancellation period for a configured delay during which withdrawal requests can't be cancelled.
- Output amounts are subject to price impact and fees.
- Withdrawals aren't allowed above the \`MAX\_PNL\_FACTOR\_FOR\_WITHDRAWALS\`.
### Orders
These items apply to order integrations.
- Handle order cancellations.
- Liquidations and ADLs can trigger the saved callback contract.
- Orders can become frozen.
- Ensure only handlers with the \`CONTROLLER\` role can call the \`afterOrderExecution\`, \`afterOrderCancellation\`, and \`afterOrderFrozen\` callback functions.
- Ensure only the correct order execution can call callback functions.
- Consider markets with the same long and short token — swaps aren't supported for these markets.
- Consider positive and negative price impact.
- Saved callback contracts can be changed.
- There is a request cancellation period for a configured delay during which order requests can't be cancelled.
- Output amounts are subject to price impact and fees.
- The position impact pool is distributed to liquidity providers over time.
- If computing price impact, consult the virtual inventory.
- Trader PnL is capped above the \`MAX\_PNL\_FACTOR\_FOR\_TRADERS\`.
- Negative price impact can be capped on position decreases.
- Decrease order \`sizeDelta\` and \`collateralDelta\` are auto-updated if they exceed what the position can handle.
- Consider \`willPositionCollateralBeSufficient\` validation.
- Consider \`decreasePositionSwapTypes\`.
- Consider the minimum collateral amount.
- Referrals are still paid out during liquidation.
- It is possible for positions to have zero collateral.
- Positions with zero size can't exist.
---
## Overview
Docs for the GMX contracts. This section focuses on the contracts most integrations interact with directly, not an exhaustive page for every deployed contract.
## Important notes
Review these points before integrating with the contracts.
:::warning
See the \[Known issues\](./known-issues.md) page for the full list of known issues and integration considerations.
These docs provide an overview. Check the actual contract code for the exact implementation and for any edge cases when building an application or integration.
Contracts such as readers and events may not be audited. Check the scopes of the audits for more information, and take extra caution when using or depending on these contracts.
Subscribe to the channels on the \[Updates and Support\](../updates-support.md) page for important contract update notifications.
:::
## How it works
The protocol separates concerns across four contract categories (bank, data storage, logic, and event contracts) to enable upgrades without fund migration. Most user actions follow a two-phase execution model where the user submits a request and a keeper executes it with oracle prices. For a detailed explanation of the architecture and keeper network, see \[Architecture\](./architecture.md).
The \[contracts repo\](https://github.com/gmx-io/gmx-synthetics/tree/updates) provides the production-branch source code. The \[test\](https://github.com/gmx-io/gmx-synthetics/tree/updates/test) folder contains examples for interacting with the contracts.
## Deployments
Key contract addresses for all supported chains (Arbitrum, Avalanche, Botanix, MegaETH) and testnets are listed on the \[Contract addresses\](./addresses.md) page.
The full deployment list with all 130+ contracts per chain is in the \[gmx-synthetics docs folder\](https://github.com/gmx-io/gmx-synthetics/tree/updates/docs). The machine-readable \`contracts.json\` currently covers mainnet deployments, while testnet deployments are published in the per-network markdown files in that folder.
### Testnet
The Arbitrum Sepolia deployment is typically the most current testnet. See \[Contract addresses — Testnet\](./addresses.md#testnet) for key testnet addresses.
For a frontend that connects to testnet, see the \[Testnet frontend\](../frontend-integration.md#testnet-frontend) section.
## Reading values
You can read on-chain values using three contracts:
- \[Reader\](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/reader/Reader.sol)
- \[GlvReader\](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/reader/GlvReader.sol)
- \[DataStore\](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/data/DataStore.sol)
The \`Reader\` contract provides convenience functions for retrieving information such as markets and positions lists.
Most integrations only need a small set of entry points:
- \`ExchangeRouter\` for creating orders, deposits, withdrawals, and shifts
- \`GlvRouter\` for GLV-specific deposits and withdrawals
- \`Reader\` for GM markets, positions, and pricing data
- \`GlvReader\` for GLV-specific reads
The wider protocol architecture includes many additional handlers, vaults, storage contracts, and utility contracts. See \[Architecture\](./architecture.md) for how those pieces fit together.
For delegated trading, gasless relay flows, and GMX Account cross-chain routers, see \[Advanced entry points\](./advanced-entrypoints.md).
You can also retrieve additional information using the \`DataStore\` and \`Keys\` contracts. The \[test\](https://github.com/gmx-io/gmx-synthetics/tree/updates/test) folder contains \`DataStore\` usage examples, and the \[keys\](https://github.com/gmx-io/gmx-synthetics/blob/updates/utils/keys.ts) file shows how to construct keys for \`DataStore\` reads.
To retrieve multiple values in a single query, use a \[Multicall contract\](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/mock/Multicall3.sol). See \[Contract addresses\](./addresses.md) for the \`Multicall3\` address on each chain.
For detailed function references, see the \[Reader\](./reader.md) and \[GLV Reader\](./glv-reader.md) pages.
For retrieving prices, see the \[REST API\](../rest-api/oracle-prices.mdx) docs.
For token compatibility, known limitations, and integration considerations, see the \[Known issues\](./known-issues.md) page.
---
## Reader
The Reader contract provides convenience functions for retrieving information such as markets, positions, and pricing data.
This page focuses on the most commonly used read helpers. For the full public surface, see \[\`Reader.sol\`\](https://github.com/gmx-io/gmx-synthetics/blob/updates/contracts/reader/Reader.sol).
Examples below assume you already have contract instances such as \`reader\`, \`dataStore\`, and \`referralStorage\`, plus any required market or price structs.
## Market list
Use \`Reader.getMarkets\` to retrieve a paginated list of all markets. Each market is represented by a \`Market.Props\` struct.
### Reader.getMarkets
\`\`\`solidity
function getMarkets(DataStore dataStore, uint256 start, uint256 end)
external view returns (Market.Props\[\] memory)
\`\`\`
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
const markets = await reader.getMarkets(dataStore.address, 0, 20);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`start\` | \`uint256\` | Start index for pagination |
| \`end\` | \`uint256\` | End index for pagination |
\*\*Returns:\*\* Array of \`Market.Props\`.
### Market.Props
| Field | Type | Description |
| ------------- | --------- | -------------------------------------------------------------------- |
| \`marketToken\` | \`address\` | Address of the GM token for this market |
| \`indexToken\` | \`address\` | Address of the index token (for example, ETH for the ETH/USD market) |
| \`longToken\` | \`address\` | Address of the long collateral token |
| \`shortToken\` | \`address\` | Address of the short collateral token |
## Detailed market list
Use \`Reader.getMarketInfoList\` to retrieve markets with additional runtime data including borrowing rates, funding rates, and whether the market is disabled.
### Reader.getMarketInfoList
\`\`\`solidity
function getMarketInfoList(
DataStore dataStore,
MarketUtils.MarketPrices\[\] memory marketPricesList,
uint256 start,
uint256 end
) external view returns (ReaderUtils.MarketInfo\[\] memory)
\`\`\`
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
const marketInfoList = await reader.getMarketInfoList(dataStore.address, marketPricesList, 0, 20);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ------------------ | ---------------------------- | ------------------------------------------------------------------------------ |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`marketPricesList\` | \`MarketUtils.MarketPrices\[\]\` | Current prices for each market, in the same order as the markets being queried |
| \`start\` | \`uint256\` | Start index for pagination |
| \`end\` | \`uint256\` | End index for pagination |
\*\*Returns:\*\* Array of \`ReaderUtils.MarketInfo\`, which includes the market props, borrowing rates, funding rates, and a flag indicating whether the market is disabled.
### MarketUtils.MarketPrices
| Field | Type | Description |
| ----------------- | ------------- | --------------------------------------- |
| \`indexTokenPrice\` | \`Price.Props\` | Current price range for the index token |
| \`longTokenPrice\` | \`Price.Props\` | Current price range for the long token |
| \`shortTokenPrice\` | \`Price.Props\` | Current price range for the short token |
### Price.Props
| Field | Type | Description |
| ----- | --------- | ------------------- |
| \`min\` | \`uint256\` | Minimum (bid) price |
| \`max\` | \`uint256\` | Maximum (ask) price |
## Getting GM token price
Use \`Reader.getMarketTokenPrice\` to retrieve the current GM token price along with detailed pool information: pool value, PnL, token amounts, borrowing fees, and the impact pool.
### Reader.getMarketTokenPrice
\`\`\`solidity
function getMarketTokenPrice(
DataStore dataStore,
Market.Props memory market,
Price.Props memory indexTokenPrice,
Price.Props memory longTokenPrice,
Price.Props memory shortTokenPrice,
bytes32 pnlFactorType,
bool maximize
) external view returns (int256, MarketPoolValueInfo.Props memory)
\`\`\`
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
const \[gmPrice, poolInfo\] = await reader.getMarketTokenPrice(
dataStore.address,
market,
indexTokenPrice,
longTokenPrice,
shortTokenPrice,
pnlFactorType,
true
);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`market\` | \`Market.Props\` | Market data struct (see \[Market list\](#market-list)) |
| \`indexTokenPrice\` | \`Price.Props\` | Current price range for the index token |
| \`longTokenPrice\` | \`Price.Props\` | Current price range for the long token |
| \`shortTokenPrice\` | \`Price.Props\` | Current price range for the short token |
| \`pnlFactorType\` | \`bytes32\` | Which PnL factor cap to apply. Use \`Keys.MAX\_PNL\_FACTOR\_FOR\_TRADERS\` for trading contexts, \`Keys.MAX\_PNL\_FACTOR\_FOR\_DEPOSITS\` for deposit simulation, or \`Keys.MAX\_PNL\_FACTOR\_FOR\_WITHDRAWALS\` for withdrawal simulation. |
| \`maximize\` | \`bool\` | Pass \`true\` to use maximum prices (gives the higher GM token price), \`false\` to use minimum prices |
\*\*Returns:\*\* A tuple of \`(int256 price, MarketPoolValueInfo.Props poolInfo)\` where \`price\` is the GM token price and \`poolInfo\` contains pool value, PnL, token amounts, borrowing fees, and the impact pool balance.
## Position list
Use \`Reader.getAccountPositions\` to retrieve all open positions for a given account. The function returns raw position data without fee or pricing calculations.
### Reader.getAccountPositions
\`\`\`solidity
function getAccountPositions(
DataStore dataStore,
address account,
uint256 start,
uint256 end
) external view returns (Position.Props\[\] memory)
\`\`\`
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
const positions = await reader.getAccountPositions(dataStore.address, account.address, 0, 20);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | --------------------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`account\` | \`address\` | The account address to retrieve positions for |
| \`start\` | \`uint256\` | Start index for pagination |
| \`end\` | \`uint256\` | End index for pagination |
\*\*Returns:\*\* Array of \`Position.Props\`, each containing the raw position state (size, collateral, entry price, and so on).
## Detailed position list
Use \`Reader.getAccountPositionInfoList\` to retrieve all open positions for a given account with full fee and pricing context. This function uses the account address and market list directly rather than position keys.
:::note
\`Reader.getAccountPositionInfoList\` uses an account plus market list rather than explicit \`positionKeys\`. If you need to query specific keys directly, use \`Reader.getPositionInfoList\`.
:::
### Reader.getAccountPositionInfoList
\`\`\`solidity
function getAccountPositionInfoList(
DataStore dataStore,
IReferralStorage referralStorage,
address account,
address\[\] memory markets,
MarketUtils.MarketPrices\[\] memory marketPrices,
address uiFeeReceiver,
uint256 start,
uint256 end
) external view returns (ReaderPositionUtils.PositionInfo\[\] memory)
\`\`\`
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
const positionInfoList = await reader.getAccountPositionInfoList(
dataStore.address,
referralStorage.address,
account.address,
markets,
marketPrices,
ethers.constants.AddressZero,
0,
20
);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`referralStorage\` | \`address\` | Address of the ReferralStorage contract |
| \`account\` | \`address\` | The account address to retrieve positions for |
| \`markets\` | \`address\[\]\` | Array of perp market addresses covering every position you expect to retrieve. Must contain only perpetual markets (not swap-only markets). |
| \`marketPrices\` | \`MarketUtils.MarketPrices\[\]\` | Current prices for each market in the same order as \`markets\`. If a returned position's market is missing from this list, the call reverts. |
| \`uiFeeReceiver\` | \`address\` | Address of the UI fee receiver used in fee calculations. Pass the zero address if not applicable. |
| \`start\` | \`uint256\` | Start index for pagination |
| \`end\` | \`uint256\` | End index for pagination |
\*\*Returns:\*\* Array of \`ReaderPositionUtils.PositionInfo\`, each including the position, fees, execution price, and PnL.
## Position information
Use \`Reader.getPositionInfo\` to retrieve full details for a single position, including fees, execution price, and PnL.
### Reader.getPositionInfo
\`\`\`solidity
function getPositionInfo(
DataStore dataStore,
IReferralStorage referralStorage,
bytes32 positionKey,
MarketUtils.MarketPrices memory prices,
uint256 sizeDeltaUsd,
address uiFeeReceiver,
bool usePositionSizeAsSizeDeltaUsd
) public view returns (ReaderPositionUtils.PositionInfo memory)
\`\`\`
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
const positionInfo = await reader.getPositionInfo(
dataStore.address,
referralStorage.address,
positionKey,
prices,
0,
ethers.constants.AddressZero,
false
);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`referralStorage\` | \`address\` | Address of the ReferralStorage contract |
| \`positionKey\` | \`bytes32\` | Key identifying the position |
| \`prices\` | \`MarketUtils.MarketPrices\` | Current prices for the index, long, and short tokens |
| \`sizeDeltaUsd\` | \`uint256\` | Used to calculate fees and execution price when simulating a position decrease. Pass \`0\` if not simulating a size change. |
| \`uiFeeReceiver\` | \`address\` | Address of the UI fee receiver for fee calculations. Pass the zero address if not applicable. |
| \`usePositionSizeAsSizeDeltaUsd\` | \`bool\` | Pass \`true\` to use the full position size as \`sizeDeltaUsd\` (for example, when simulating a full close) |
\*\*Returns:\*\* \`ReaderPositionUtils.PositionInfo\` containing the position data, fees, execution price, and PnL.
## Detailed position list by key
Use \`Reader.getPositionInfoList\` to retrieve detailed position data when you already have an array of position keys.
### Reader.getPositionInfoList
\`\`\`solidity
function getPositionInfoList(
DataStore dataStore,
IReferralStorage referralStorage,
bytes32\[\] memory positionKeys,
MarketUtils.MarketPrices\[\] memory prices,
address uiFeeReceiver
) external view returns (ReaderPositionUtils.PositionInfo\[\] memory)
\`\`\`
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
const positionInfoList = await reader.getPositionInfoList(
dataStore.address,
referralStorage.address,
positionKeys,
prices,
ethers.constants.AddressZero
);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------------- | ---------------------------- | ------------------------------------------------------------------------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`referralStorage\` | \`address\` | Address of the ReferralStorage contract |
| \`positionKeys\` | \`bytes32\[\]\` | Position keys to query |
| \`prices\` | \`MarketUtils.MarketPrices\[\]\` | Current prices for the markets of the requested positions, in the same order as \`positionKeys\` |
| \`uiFeeReceiver\` | \`address\` | Address of the UI fee receiver used in fee calculations. Pass the zero address if not applicable. |
\*\*Returns:\*\* Array of \`ReaderPositionUtils.PositionInfo\` values in the same order as \`positionKeys\`.
## Execution price for increasing or decreasing a position
Use \`Reader.getExecutionPrice\` to estimate the execution price for increasing or decreasing a position, accounting for price impact.
### Reader.getExecutionPrice
\`\`\`solidity
function getExecutionPrice(
DataStore dataStore,
address marketKey,
MarketUtils.MarketPrices memory prices,
uint256 positionSizeInUsd,
uint256 positionSizeInTokens,
int256 sizeDeltaUsd,
int256 pendingImpactAmount,
bool isLong
) external view returns (ReaderPricingUtils.ExecutionPriceResult memory)
\`\`\`
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
const executionPriceResult = await reader.getExecutionPrice(
dataStore.address,
marketKey,
prices,
positionSizeInUsd,
positionSizeInTokens,
sizeDeltaUsd,
pendingImpactAmount,
true
);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ---------------------- | -------------------------- | --------------------------------------------------------------------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`marketKey\` | \`address\` | Address of the market |
| \`prices\` | \`MarketUtils.MarketPrices\` | Current prices for the index, long, and short tokens |
| \`positionSizeInUsd\` | \`uint256\` | Current size of the open position in USD. Pass \`0\` if there is no existing position. |
| \`positionSizeInTokens\` | \`uint256\` | Current size of the open position in index tokens. Pass \`0\` if there is no existing position. |
| \`sizeDeltaUsd\` | \`int256\` | Size change in USD. Positive to increase, negative to decrease. |
| \`pendingImpactAmount\` | \`int256\` | Pending price impact amount already accumulated for this position |
| \`isLong\` | \`bool\` | Pass \`true\` for a long position, \`false\` for short |
\*\*Returns:\*\* \`ReaderPricingUtils.ExecutionPriceResult\` containing the execution price and price impact amounts.
## Output amount for swaps
Use \`Reader.getSwapAmountOut\` to estimate how many tokens you receive for a swap, along with the price impact and swap fees.
### Reader.getSwapAmountOut
\`\`\`solidity
function getSwapAmountOut(
DataStore dataStore,
Market.Props memory market,
MarketUtils.MarketPrices memory prices,
address tokenIn,
uint256 amountIn,
address uiFeeReceiver
) external view returns (uint256, int256, SwapPricingUtils.SwapFees memory fees)
\`\`\`
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
const \[amountOut, impactAmount, fees\] = await reader.getSwapAmountOut(
dataStore.address,
market,
prices,
tokenIn,
amountIn,
ethers.constants.AddressZero
);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| --------------- | -------------------------- | ------------------------------------------------------------------------ |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`market\` | \`Market.Props\` | Market to route the swap through |
| \`prices\` | \`MarketUtils.MarketPrices\` | Current prices for the index, long, and short tokens |
| \`tokenIn\` | \`address\` | Address of the input token |
| \`amountIn\` | \`uint256\` | Amount of the input token |
| \`uiFeeReceiver\` | \`address\` | Address of the UI fee receiver. Pass the zero address if not applicable. |
\*\*Returns:\*\* A tuple of \`(uint256 amountOut, int256 impactAmount, SwapPricingUtils.SwapFees fees)\` — the output token amount, price impact amount, and fee breakdown.
## Output amount for deposits
Use \`Reader.getDepositAmountOut\` to estimate how many GM tokens you receive for a deposit.
### Reader.getDepositAmountOut
\`\`\`solidity
function getDepositAmountOut(
DataStore dataStore,
Market.Props memory market,
MarketUtils.MarketPrices memory prices,
uint256 longTokenAmount,
uint256 shortTokenAmount,
address uiFeeReceiver,
ISwapPricingUtils.SwapPricingType swapPricingType,
bool includeVirtualInventoryImpact
) external view returns (uint256)
\`\`\`
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
const marketTokensOut = await reader.getDepositAmountOut(
dataStore.address,
market,
prices,
longTokenAmount,
shortTokenAmount,
ethers.constants.AddressZero,
swapPricingType,
true
);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ------------------------------- | ----------------------------------- | ------------------------------------------------------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`market\` | \`Market.Props\` | The market to deposit into |
| \`prices\` | \`MarketUtils.MarketPrices\` | Current prices for the index, long, and short tokens |
| \`longTokenAmount\` | \`uint256\` | Amount of the long token to deposit |
| \`shortTokenAmount\` | \`uint256\` | Amount of the short token to deposit |
| \`uiFeeReceiver\` | \`address\` | Address of the UI fee receiver. Pass the zero address if not applicable. |
| \`swapPricingType\` | \`ISwapPricingUtils.SwapPricingType\` | Pricing method to use for the internal swap component of the deposit |
| \`includeVirtualInventoryImpact\` | \`bool\` | Pass \`true\` to include virtual inventory impact in the price impact calculation |
\*\*Returns:\*\* \`uint256\` — the estimated number of GM tokens minted.
## Output amount for withdrawals
Use \`Reader.getWithdrawalAmountOut\` to estimate how many long and short tokens you receive when withdrawing GM tokens.
### Reader.getWithdrawalAmountOut
\`\`\`solidity
function getWithdrawalAmountOut(
DataStore dataStore,
Market.Props memory market,
MarketUtils.MarketPrices memory prices,
uint256 marketTokenAmount,
address uiFeeReceiver,
ISwapPricingUtils.SwapPricingType swapPricingType
) external view returns (uint256, uint256)
\`\`\`
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
const \[longTokenAmountOut, shortTokenAmountOut\] = await reader.getWithdrawalAmountOut(
dataStore.address,
market,
prices,
marketTokenAmount,
ethers.constants.AddressZero,
swapPricingType
);
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ------------------- | ----------------------------------- | ------------------------------------------------------------------------ |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`market\` | \`Market.Props\` | The market to withdraw from |
| \`prices\` | \`MarketUtils.MarketPrices\` | Current prices for the index, long, and short tokens |
| \`marketTokenAmount\` | \`uint256\` | Amount of GM tokens to burn |
| \`uiFeeReceiver\` | \`address\` | Address of the UI fee receiver. Pass the zero address if not applicable. |
| \`swapPricingType\` | \`ISwapPricingUtils.SwapPricingType\` | Pricing method to use for the internal swap component of the withdrawal |
\*\*Returns:\*\* A tuple of \`(uint256 longTokenAmount, uint256 shortTokenAmount)\` — the estimated amounts of long and short tokens returned.
## Direct lookups
Use these methods when you already have a key, salt, or account and want the raw stored value without additional pricing or fee calculations.
### Reader.getMarket
\`\`\`solidity
function getMarket(DataStore dataStore, address key)
external view returns (Market.Props memory)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | ------------------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`key\` | \`address\` | Market token address used as the market key |
\*\*Returns:\*\* \`Market.Props\` for the requested market.
### Reader.getMarketBySalt
\`\`\`solidity
function getMarketBySalt(DataStore dataStore, bytes32 salt)
external view returns (Market.Props memory)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | ------------------------------------ |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`salt\` | \`bytes32\` | Deterministic market deployment salt |
\*\*Returns:\*\* \`Market.Props\` for the requested market.
### Reader.getDeposit
\`\`\`solidity
function getDeposit(DataStore dataStore, bytes32 key)
external view returns (Deposit.Props memory)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`key\` | \`bytes32\` | Deposit request key |
\*\*Returns:\*\* Raw \`Deposit.Props\` for the requested deposit.
### Reader.getWithdrawal
\`\`\`solidity
function getWithdrawal(DataStore dataStore, bytes32 key)
external view returns (Withdrawal.Props memory)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`key\` | \`bytes32\` | Withdrawal request key |
\*\*Returns:\*\* Raw \`Withdrawal.Props\` for the requested withdrawal.
### Reader.getShift
\`\`\`solidity
function getShift(DataStore dataStore, bytes32 key)
external view returns (Shift.Props memory)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`key\` | \`bytes32\` | Shift request key |
\*\*Returns:\*\* Raw \`Shift.Props\` for the requested shift.
### Reader.getPosition
\`\`\`solidity
function getPosition(DataStore dataStore, bytes32 key)
external view returns (Position.Props memory)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`key\` | \`bytes32\` | Position key |
\*\*Returns:\*\* Raw \`Position.Props\` for the requested position.
### Reader.getOrder
\`\`\`solidity
function getOrder(DataStore dataStore, bytes32 key)
external view returns (Order.Props memory)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`key\` | \`bytes32\` | Order key |
\*\*Returns:\*\* Raw \`Order.Props\` for the requested order.
## Account and position state helpers
Use these methods when you need raw account orders, PnL diagnostics, or liquidation checks rather than the higher-level position info helpers above.
### Reader.getPositionPnlUsd
\`\`\`solidity
function getPositionPnlUsd(
DataStore dataStore,
Market.Props memory market,
MarketUtils.MarketPrices memory prices,
bytes32 positionKey,
uint256 sizeDeltaUsd
) external view returns (int256, int256, uint256)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| -------------- | -------------------------- | -------------------------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`market\` | \`Market.Props\` | Market for the position |
| \`prices\` | \`MarketUtils.MarketPrices\` | Current prices for the market |
| \`positionKey\` | \`bytes32\` | Position key |
| \`sizeDeltaUsd\` | \`uint256\` | Position size delta to evaluate when computing PnL |
\*\*Returns:\*\* A tuple of \`(positionPnlUsd, cappedPositionPnlUsd, sizeDeltaInTokens)\`.
### Reader.isPositionLiquidatable
\`\`\`solidity
function isPositionLiquidatable(
DataStore dataStore,
IReferralStorage referralStorage,
bytes32 positionKey,
Market.Props memory market,
MarketUtils.MarketPrices memory prices,
bool shouldValidateMinCollateralUsd,
bool forLiquidation
) public view returns (bool, string memory, PositionUtils.IsPositionLiquidatableInfo memory)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| -------------------------------- | -------------------------- | -------------------------------------------------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`referralStorage\` | \`address\` | Address of the ReferralStorage contract |
| \`positionKey\` | \`bytes32\` | Position key |
| \`market\` | \`Market.Props\` | Market for the position |
| \`prices\` | \`MarketUtils.MarketPrices\` | Current prices for the market |
| \`shouldValidateMinCollateralUsd\` | \`bool\` | Whether to enforce the minimum collateral USD checks |
| \`forLiquidation\` | \`bool\` | Pass \`true\` when checking liquidation conditions, \`false\` for a soft check |
\*\*Returns:\*\* A tuple of \`(isLiquidatable, reason, info)\` with the liquidation result, reason string, and detailed diagnostics.
### Reader.getAccountOrders
\`\`\`solidity
function getAccountOrders(
DataStore dataStore,
address account,
uint256 start,
uint256 end
) external view returns (ReaderUtils.OrderInfo\[\] memory)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`account\` | \`address\` | Account to retrieve orders for |
| \`start\` | \`uint256\` | Start index for pagination |
| \`end\` | \`uint256\` | End index for pagination |
\*\*Returns:\*\* Array of \`ReaderUtils.OrderInfo\` values for the account.
## Market state and PnL helpers
Use these methods when you need one-market diagnostics without going through the paginated market list helpers.
### Reader.getMarketInfo
\`\`\`solidity
function getMarketInfo(
DataStore dataStore,
MarketUtils.MarketPrices memory prices,
address marketKey
) public view returns (ReaderUtils.MarketInfo memory)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | -------------------------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`prices\` | \`MarketUtils.MarketPrices\` | Current prices for the market |
| \`marketKey\` | \`address\` | Market token address |
\*\*Returns:\*\* \`ReaderUtils.MarketInfo\` for the requested market.
### Reader.getPendingPositionImpactPoolDistributionAmount
\`\`\`solidity
function getPendingPositionImpactPoolDistributionAmount(
DataStore dataStore,
address market
) external view returns (uint256, uint256)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | --------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`market\` | \`address\` | Market token address |
\*\*Returns:\*\* A tuple of pending long-token and short-token impact pool distribution amounts.
### Reader.getNetPnl
\`\`\`solidity
function getNetPnl(
DataStore dataStore,
Market.Props memory market,
Price.Props memory indexTokenPrice,
bool maximize
) external view returns (int256)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------------- | -------------- | ---------------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`market\` | \`Market.Props\` | Market to evaluate |
| \`indexTokenPrice\` | \`Price.Props\` | Index token price range |
| \`maximize\` | \`bool\` | Whether to use the maximizing price path |
\*\*Returns:\*\* Net market PnL as an \`int256\`.
### Reader.getPnl
\`\`\`solidity
function getPnl(
DataStore dataStore,
Market.Props memory market,
Price.Props memory indexTokenPrice,
bool isLong,
bool maximize
) external view returns (int256)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------------- | -------------- | ---------------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`market\` | \`Market.Props\` | Market to evaluate |
| \`indexTokenPrice\` | \`Price.Props\` | Index token price range |
| \`isLong\` | \`bool\` | Pass \`true\` for long-side PnL |
| \`maximize\` | \`bool\` | Whether to use the maximizing price path |
\*\*Returns:\*\* Long-side or short-side PnL as an \`int256\`.
### Reader.getOpenInterestWithPnl
\`\`\`solidity
function getOpenInterestWithPnl(
DataStore dataStore,
Market.Props memory market,
Price.Props memory indexTokenPrice,
bool isLong,
bool maximize
) external view returns (int256)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------------- | -------------- | ---------------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`market\` | \`Market.Props\` | Market to evaluate |
| \`indexTokenPrice\` | \`Price.Props\` | Index token price range |
| \`isLong\` | \`bool\` | Pass \`true\` for long-side open interest |
| \`maximize\` | \`bool\` | Whether to use the maximizing price path |
\*\*Returns:\*\* Open interest with PnL included, as an \`int256\`.
### Reader.getPnlToPoolFactor
\`\`\`solidity
function getPnlToPoolFactor(
DataStore dataStore,
address marketAddress,
MarketUtils.MarketPrices memory prices,
bool isLong,
bool maximize
) external view returns (int256)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| --------------- | -------------------------- | ---------------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`marketAddress\` | \`address\` | Market token address |
| \`prices\` | \`MarketUtils.MarketPrices\` | Current prices for the market |
| \`isLong\` | \`bool\` | Pass \`true\` for the long side |
| \`maximize\` | \`bool\` | Whether to use the maximizing price path |
\*\*Returns:\*\* Current PnL-to-pool factor as an \`int256\`.
## Pricing and risk helpers
Use these methods when you need direct swap-impact or ADL diagnostics without calling the larger quote helpers.
### Reader.getSwapPriceImpact
\`\`\`solidity
function getSwapPriceImpact(
DataStore dataStore,
address marketKey,
address tokenIn,
address tokenOut,
uint256 amountIn,
Price.Props memory tokenInPrice,
Price.Props memory tokenOutPrice
) external view returns (int256, int256, int256)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| --------------- | ------------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`marketKey\` | \`address\` | Market token address |
| \`tokenIn\` | \`address\` | Input token address |
| \`tokenOut\` | \`address\` | Output token address |
| \`amountIn\` | \`uint256\` | Input token amount |
| \`tokenInPrice\` | \`Price.Props\` | Input token price range |
| \`tokenOutPrice\` | \`Price.Props\` | Output token price range |
\*\*Returns:\*\* A tuple of swap price impact values as signed integers.
### Reader.getAdlState
\`\`\`solidity
function getAdlState(
DataStore dataStore,
address market,
bool isLong,
MarketUtils.MarketPrices memory prices
) external view returns (uint256, bool, int256, uint256)
\`\`\`
\*\*Parameters:\*\*
| Parameter | Type | Description |
| ----------- | -------------------------- | --------------------------------- |
| \`dataStore\` | \`address\` | Address of the DataStore contract |
| \`market\` | \`address\` | Market token address |
| \`isLong\` | \`bool\` | Pass \`true\` for the long side |
| \`prices\` | \`MarketUtils.MarketPrices\` | Current prices for the market |
\*\*Returns:\*\* A tuple describing the ADL state, including the ADL phase, whether ADL is enabled, the PnL factor, and the minimum PnL factor for ADL.
---
## Simulations
The \`ExchangeRouter\` and \`GlvRouter\` contracts expose public simulation functions that let you dry-run an execution against a set of supplied prices before submitting a real request for keeper execution. Running a simulation catches validation errors — such as price impact limits or insufficient output amounts — without spending gas on a failed transaction.
For the full \`CreateOrderParams\` and \`CreateDepositParams\` structures, see \[ExchangeRouter\](./exchange-router.md). For contract addresses, see \[Contract addresses\](./addresses.md).
## How simulations work
Simulation functions use the \`withSimulatedOraclePrices\` modifier in \`OracleModule\`. The modifier injects synthetic price data into the oracle, executes the handler logic through the router/controller path, then unconditionally reverts with \`EndOfOracleSimulation\`. Because the transaction always reverts, no state changes are persisted.
The caller interprets the revert reason: if the error is \`EndOfOracleSimulation\`, the simulation succeeded and the supplied prices passed validation. Any other revert reason indicates an error that would also occur on-chain. In practice, this is a preflight tool for users and integrators; actual request execution is still performed by keeper-only handler functions.
In practice, simulations are usually called in the same \`multicall\` flow that creates the request. You create the deposit, withdrawal, or order first, then call the corresponding \`simulateExecuteLatest...\` function with the prices you want to test against.
\*\*Example (TypeScript / ethers):\*\*
\`\`\`typescript
const currentTimestamp = (await provider.getBlock("latest")).timestamp + 2;
await expect(
exchangeRouter.multicall(
\[\
exchangeRouter.interface.encodeFunctionData("sendWnt", \[depositVault.address, executionFee\]),\
exchangeRouter.interface.encodeFunctionData("sendTokens", \[usdc.address, depositVault.address, shortTokenAmount\]),\
exchangeRouter.interface.encodeFunctionData("createDeposit", \[depositParams\]),\
exchangeRouter.interface.encodeFunctionData("simulateExecuteLatestDeposit", \[\
{\
primaryTokens: \[wnt.address, usdc.address\],\
primaryPrices: \[\
{ min: wethPrice, max: wethPrice },\
{ min: usdcPrice, max: usdcPrice },\
\],\
minTimestamp: currentTimestamp,\
maxTimestamp: currentTimestamp,\
},\
\]),\
\],
{ value: executionFee }
)
).to.be.revertedWithCustomError(errorsContract, "EndOfOracleSimulation");
\`\`\`
If the call reverts with \`EndOfOracleSimulation\`, the simulated execution passed. If it reverts with any other error, treat that as the actual validation error for the supplied prices.
## Available simulation functions
The latest-request helpers use the latest created request key. In practice, call the simulation immediately after creating the request in the same \`multicall\`, so it targets the action you just created.
### ExchangeRouter functions
| Function | Action type |
| ------------------------------------------------------------------------------------------- | ----------------------- |
| \`simulateExecuteLatestDeposit(SimulatePricesParams)\` | GM deposit |
| \`simulateExecuteLatestWithdrawal(SimulatePricesParams, SwapPricingType)\` | GM withdrawal |
| \`simulateExecuteLatestShift(SimulatePricesParams)\` | GM pool shift |
| \`simulateExecuteLatestOrder(SimulatePricesParams)\` | Perpetual or swap order |
| \`simulateExecuteLatestJitOrder(GlvShiftUtils.CreateGlvShiftParams\[\], SimulatePricesParams)\` | JIT order |
### GlvRouter functions
| Function | Action type |
| ------------------------------------------------------------- | ------------------------------ |
| \`simulateExecuteGlvDeposit(bytes32, SimulatePricesParams)\` | GLV deposit by explicit key |
| \`simulateExecuteLatestGlvDeposit(SimulatePricesParams)\` | Latest GLV deposit |
| \`simulateExecuteGlvWithdrawal(bytes32, SimulatePricesParams)\` | GLV withdrawal by explicit key |
| \`simulateExecuteLatestGlvWithdrawal(SimulatePricesParams)\` | Latest GLV withdrawal |
## SimulatePricesParams
\`\`\`solidity
struct SimulatePricesParams {
address\[\] primaryTokens; // token addresses to price
Price.Props\[\] primaryPrices; // { min, max } price for each token
uint256 minTimestamp; // lower bound of the price window
uint256 maxTimestamp; // upper bound of the price window
}
\`\`\`
Supply current oracle prices for all tokens involved in the action. The \`minTimestamp\` and \`maxTimestamp\` fields must bracket the expected execution timestamp; a common pattern is to set both to \`block.timestamp + 120\`.
### Field notes
| Field | Description |
| --------------- | ------------------------------------------------------------------------------------------------------------- |
| \`primaryTokens\` | Token addresses to assign simulated prices to. Include every token the action depends on. |
| \`primaryPrices\` | Simulated oracle prices for each token, in the same order as \`primaryTokens\`. Each price uses \`{ min, max }\`. |
| \`minTimestamp\` | Lower bound for the simulated oracle timestamp window. |
| \`maxTimestamp\` | Upper bound for the simulated oracle timestamp window. |
---
## GraphQL
GMX provides GraphQL endpoints powered by Subsquid for querying indexed on-chain data.
| Network | URL |
| --------------------- | ---------------------------------------------------------------------------------- |
| \*\*Arbitrum One\*\* | |
| \*\*Avalanche C-Chain\*\* | |
| \*\*Botanix\*\* | |
| \*\*MegaETH\*\* | |
## Schema changes
### 2026-03-31 — Referral analytics added
The GraphQL schema now exposes referral analytics for both affiliates and traders. Five new entities track referral code ownership and hourly trade statistics, and two new query resolvers aggregate that data into time-windowed summaries with period-over-period comparisons.
\*\*New entities.\*\*
| Entity | What it provides |
| ------ | ---------------- |
| \`ReferralCodeOwner\` | Maps a referral code to its \`owner\` address, with \`updatedAtTimestamp\`, \`updatedAtBlock\`, and \`updatedTxnHash\` |
| \`TraderReferral\` | Records which \`referralCode\` and \`affiliate\` a trader is associated with, plus update metadata |
| \`AffiliateReferralTradeStatsByHour\` | Hourly trade stats for an affiliate: \`volumeUsd\`, \`tradesCount\`, and \`rebatesUsd\` |
| \`TraderReferralTradeStatsByHour\` | Hourly trade stats for a trader using a referral code: \`volumeUsd\` and \`discountsUsd\` |
| \`AffiliateTraderStatsByHour\` | Hourly net trader flow for an affiliate: \`tradersGained\`, \`tradersLost\`, and \`tradersNet\` |
\*\*New query resolvers.\*\*
These are custom server-extension resolvers, not standard entity queries. Call them by name with a \`where\` argument:
| Resolver | Input fields | What it returns |
| -------- | ------------ | --------------- |
| \`affiliateStats\` | \`affiliate\` (required), \`from?\`, \`to?\` | Time-windowed volume, trade count, rebates, and trader flow for an affiliate, with optional period comparison |
| \`traderReferralStats\` | \`trader\` (required), \`from?\`, \`to?\` | Time-windowed volume and discounts for a trader using a referral code, with optional period comparison |
Both resolvers align timestamps to hourly buckets and choose a bucket size automatically based on the requested window length.
\*\*Example queries.\*\*
\`\`\`graphql
# Affiliate dashboard: volume, rebates, and trader flow for a 7-day window
query AffiliateStats($affiliate: String!) {
affiliateStats(where: { affiliate: $affiliate, from: 1743292800, to: 1743897600 }) {
affiliate
from
to
bucketSizeSeconds
hasComparison
summary {
volumeUsd
volumeUsdDelta
rebatesUsd
rebatesUsdDelta
tradersNet
tradersNetDelta
}
points {
timestamp
volumeUsd
rebatesUsd
tradersGained
tradersLost
tradersNet
}
}
}
\`\`\`
\`\`\`graphql
# Trader dashboard: volume and discounts earned through a referral code
query TraderReferralStats($trader: String!) {
traderReferralStats(where: { trader: $trader, from: 1743292800, to: 1743897600 }) {
trader
from
to
bucketSizeSeconds
summary {
volumeUsd
discountsUsd
}
points {
timestamp
volumeUsd
discountsUsd
}
}
}
\`\`\`
### 2026-03-10 - Staking power and account analytics added
The GraphQL schema now exposes staking power analytics plus expanded daily account aggregates for PnL and capital-tracking queries.
\*\*New entities.\*\*
| Entity | What it provides |
| ------ | ---------------- |
| \`StakingPower\` | Per-account staking power state, including \`accumulatedPower\`, \`currentStakedBalance\`, \`historicalMaxStaked\`, \`lastPowerResetAt\`, and \`powerResetCount\` |
| \`NetworkStakingPower\` | Network-wide staking power totals through \`totalAccumulatedPower\`, \`totalCurrentStaked\`, and \`lastUpdateTimestamp\` |
\*\*Expanded analytics fields.\*\*
| Entity | Added fields |
| ------ | ------------ |
| \`AccountStat\` | \`account\`, \`period\`, \`dayTimestamp\`, \`netCapitalDelta\`, \`maxNetCapitalRunningDelta\` |
| \`Position\` | \`maxCapital\` |
These additions let you query staking-power history and daily account-level capital changes without replaying raw position-change events yourself.
\*\*Example query.\*\*
\`\`\`graphql
query AccountAnalytics($account: String!) {
stakingPower(id: $account) {
accumulatedPower
currentStakedBalance
historicalMaxStaked
lastPowerResetAt
powerResetCount
}
accountStats(
where: { account\_eq: $account, period\_eq: "1d" }
orderBy: dayTimestamp\_DESC
limit: 7
) {
dayTimestamp
netCapitalDelta
maxNetCapitalRunningDelta
volume
realizedPnl
}
}
\`\`\`
### 2026-02-24 — Transaction entity removed
The \`Transaction\` entity type has been removed from the GraphQL schema. This change is live on all main endpoints. A backward-compatible endpoint is available until March 1, 2026:
\`\`\`
https://gmx.squids.live/gmx-synthetics-arbitrum@786bd0/api/graphql
\`\`\`
\*\*Field changes.\*\* Entities that previously referenced \`transaction: Transaction!\` now expose a flat \`transactionHash: String!\` field. The \`timestamp\` field that was nested inside \`Transaction\` is now a top-level field on each entity.
| Entity | Old field | New field |
| -------------------- | --------------------------- | -------------------------- |
| \`TradeAction\` | \`transaction: Transaction!\` | \`transactionHash: String!\` |
| \`ClaimAction\` | \`transaction: Transaction!\` | \`transactionHash: String!\` |
| \`Order\` | \`createdTxn: Transaction!\` | \`createdTxnHash: String!\` |
| \`Order\` | \`cancelledTxn: Transaction\` | \`cancelledTxnHash: String\` |
| \`Order\` | \`executedTxn: Transaction\` | \`executedTxnHash: String\` |
| \`SwapFeesInfo\` | \`transaction: Transaction!\` | \`transactionHash: String!\` |
| \`SwapInfo\` | \`transaction: Transaction!\` | \`transactionHash: String!\` |
| \`PositionFeesEntity\` | \`transaction: Transaction!\` | \`transactionHash: String!\` |
| \`Distribution\` | \`transaction: Transaction!\` | \`transactionHash: String!\` |
\*\*Sort field changes.\*\* Sort values that referenced the \`transaction\` relation are replaced with direct field sorts:
| Old sort value | New sort value |
| ---------------------------- | ---------------- |
| \`transaction\_timestamp\_DESC\` | \`timestamp\_DESC\` |
| \`transaction\_timestamp\_ASC\` | \`timestamp\_ASC\` |
\*\*Example migration.\*\* A \`TradeAction\` query before and after:
\`\`\`graphql
# Before
tradeActions(limit: 50, orderBy: transaction\_timestamp\_DESC) {
eventName
transaction {
timestamp
hash
}
}
# After
tradeActions(limit: 50, orderBy: timestamp\_DESC) {
eventName
timestamp
transactionHash
}
\`\`\`
---
## Fallback URLs
When the primary API endpoint is unavailable for a chain, use the corresponding fallback endpoint below.
| Network | Fallback 1 | Fallback 2 |
| --------- | ------------------------------------------------ | ------------------------------------------------- |
| Arbitrum | | |
| Avalanche | | |
| Botanix | | |
---
## Liquidity
REST endpoints for APY, performance, and GLV information.
Use this page for public liquidity and yield reads. For a broader comparison with SDK and GraphQL surfaces, start with the \[API integration guide\](../integration-guide.md).
## Fee APYs
To retrieve fee APYs for GM pools and GLV vaults:
| Network | URL |
| --------- | ---------------------------------------------------- |
| Arbitrum | |
| Avalanche | |
| Botanix | |
Accepted query parameters:
- \`period\`: \`1d\`, \`7d\`, \`30d\`, \`90d\`, \`180d\`, \`1y\`, \`total\`. Defaults to \`7d\`.
## Performance
To retrieve annualized performance for GM pools and GLV vaults:
| Network | URL |
| --------- | -------------------------------------------------------------------- |
| Arbitrum | |
| Avalanche | |
| Botanix | |
Accepted query parameters:
- \`period\`: \`7d\`, \`30d\`, \`90d\`, \`180d\`, \`1y\`, \`total\`. Defaults to \`90d\`. The \`1d\` period is not supported and returns a 400 error.
- \`address\`: Address of a specific GM pool or GLV vault to retrieve data for only that entity.
## GLV tokens
To retrieve a list of GMX Liquidity Vault (GLV) tokens:
| Network | URL |
| --------- | ---------------------------------------- |
| Arbitrum | |
| Avalanche | |
| Botanix | |
## GLV info
To retrieve extended information for GLV vaults, including market exposure, GM pool balances in USD, \`isDisabled\` status, and listing date:
| Network | URL |
| --------- | --------------------------------------------- |
| Arbitrum | |
| Avalanche | |
| Botanix | |
## Operational notes
- \`/apy\` currently caches responses for \`1800\` seconds and returns \`400\` for an invalid \`period\`.
- \`/performance/annualized\` and \`/performance/snapshots\` currently cache by day and return \`400\` for unsupported periods such as \`1d\`.
- Use these routes for yield and performance reporting, not for near-live position or order state.
- If you need write-path status after a transaction, use \[SDK v1\](../../sdk/v1/readme.mdx) or direct contracts and then poll the relevant read surface.
---
## Markets(Rest-api)
REST endpoints for trading market information.
Use this page when you need public market reads from API v1 REST. For exact “which surface should I use” guidance, start with the \[API integration guide\](../integration-guide.md).
## Trading markets and GM tokens
To retrieve a list of tradable markets and their associated tokens (for example, GM tokens for liquidity pools):
| Network | URL |
| --------- | ----------------------------------------- |
| Arbitrum | |
| Avalanche | |
| Botanix | |
This endpoint caches responses for 60 seconds.
## Trading markets and GM info
To retrieve detailed information about tradable markets and their tokens — including liquidity, open interest, token amounts, funding/borrowing/net rates, \`isDisabled\` status, and listing date:
| Network | URL |
| --------- | ---------------------------------------------- |
| Arbitrum | |
| Avalanche | |
| Botanix | |
The \`/markets/info\` endpoint refreshes market values on a \`5000\` ms pull interval and caches responses with a \`1\` second TTL. Treat it as a near-live snapshot, not as same-block state.
## Operational notes
- Use \`/markets\` for a market catalog or configuration view. The current implementation caches this route for \`60\` seconds.
- Use \`/markets/info\` for near-live liquidity, open interest, funding, borrowing, token amounts, and \`isDisabled\` state. The current implementation caches this route for \`1\` second.
- Use \`/markets/tickers\` when you need filtered ticker reads. Invalid \`addresses\` or \`symbols\` query values return \`400\`.
- If you need fallback behavior, use the alternate public URLs documented on \[Fallback URLs\](./fallback-urls.mdx).
## Funding rate data freshness
The \`/rates\` endpoint returns \*\*hourly snapshots\*\* produced by the Squid indexer — it is not realtime data. Each snapshot is timestamped at the start of the hour. Use \`/rates\` for historical rate analysis, averages, and trend charts.
For \*\*near-live funding rates\*\*, use \`/markets/info\` instead. It refreshes market values on a \`5000\` ms pull interval and includes current funding and borrowing rates alongside liquidity and open interest.
---
## Oracle Prices
REST endpoints for oracle information.
Use this page for public price and token reads. For workflow guidance across REST, GraphQL, and SDK surfaces, start with the \[API integration guide\](../integration-guide.md).
## Ping
Use the ping endpoint to check whether the oracle API is healthy. The endpoint verifies database connectivity and returns a JSON response.
| Network | URL |
| --------- | ---------------------------------------- |
| Arbitrum | |
| Avalanche | |
| Botanix | |
\*\*Success response\*\* (\`200 OK\`):
\`\`\`json
{ "ok": true }
\`\`\`
\*\*Error response\*\* (\`500 Internal Server Error\`):
\`\`\`json
{ "errors": \["db is unavailable"\] }
\`\`\`
## Tickers
The tickers endpoint returns the latest price data for all supported tokens. Use this endpoint for real-time price display in your application.
| Network | URL |
| --------- | -------------------------------------------------- |
| Arbitrum | |
| Avalanche | |
| Botanix | |
\*\*Response\*\* — an array of ticker objects:
\`\`\`json
\[\
{\
"tokenSymbol": "ETH",\
"tokenAddress": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",\
"minPrice": "1799910000000000000000000000000000",\
"maxPrice": "1800090000000000000000000000000000",\
"medianPrice": "1800000000000000000000000000000000",\
"oracleDecimals": 8,\
"updatedAt": 1708956120\
}\
\]
\`\`\`
Prices are represented as strings scaled to 30 decimal places. Divide by \`10^(30 - tokenDecimals - oracleDecimals)\` to get the USD price.
## Signed prices
The signed prices endpoint returns the latest oracle-signed price data for each supported token. Include these signed prices in your transaction payloads when interacting with GMX contracts on-chain.
| Network | URL |
| --------- | -------------------------------------------------------- |
| Arbitrum | |
| Avalanche | |
| Botanix | |
\*\*Response\*\*:
\`\`\`json
{
"signedPrices": \[\
{\
"tokenSymbol": "ETH",\
"tokenAddress": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",\
"minPrice": "1799910000000000000000000000000000",\
"maxPrice": "1800090000000000000000000000000000",\
"medianPrice": "1800000000000000000000000000000000",\
"oracleDecimals": 8,\
"signer": "0xabc...def",\
"signature": "0x...",\
"signatureWithoutBlockHash": "0x...",\
"tokenOracleType": 0,\
"salt": "0x...",\
"minBlockNumber": 123456789,\
"minBlockTimestamp": 1708956000,\
"minBlockHash": "0x...",\
"maxBlockNumber": 123456799,\
"maxBlockTimestamp": 1708956120,\
"maxBlockHash": "0x...",\
"createdAt": 1708956120.5\
}\
\]
}
\`\`\`
## Candlesticks
The candlesticks endpoint returns OHLC price data for a given token and time period. Candles are returned in descending order (most recent first).
| Network | Base URL |
| --------- | -------------------------------------------------- |
| Arbitrum | |
| Avalanche | |
| Botanix | |
\*\*Required query parameters:\*\*
- \`tokenSymbol\` — the token symbol, for example \`ETH\` or \`BTC\`
- \`period\` — one of \`1m\`, \`5m\`, \`15m\`, \`1h\`, \`4h\`, or \`1d\`
\*\*Optional query parameters:\*\*
- \`limit\` — maximum number of candles to return. Defaults to \`1000\`. Minimum: \`1\`. Maximum: \`10000\`.
\*\*Example request:\*\*
\`\`\`bash
GET https://arbitrum-api.gmxinfra.io/prices/candles?tokenSymbol=ETH&period=1d&limit=2
\`\`\`
\*\*Response:\*\*
\`\`\`json
{
"period": "1d",
"candles": \[\
\[1701388800, 2150.25, 2180.5, 2145.0, 2175.3\],\
\[1701302400, 2120.1, 2155.0, 2110.0, 2150.25\]\
\]
}
\`\`\`
Each candle is an array of five values in this order:
1. \`timestamp\` — Unix timestamp (seconds) of the candle period start
2. \`open\` — opening price
3. \`high\` — highest price during the period
4. \`low\` — lowest price during the period
5. \`close\` — closing price
## Tokens
The tokens endpoint returns a list of all tokens supported by the oracle on a given network.
| Network | URL |
| --------- | ------------------------------------------ |
| Arbitrum | |
| Avalanche | |
| Botanix | |
## Operational notes
- \`/prices/tickers\`, \`/signed\_prices/latest\`, and \`/prices/candles\` use a \`10\` second route timeout in the current oracle-keeper implementation.
- \`/prices/tickers\` uses a short in-process cache of \`0.3\` seconds in the current implementation.
- \`/signed\_prices/latest\` is cached for \`1\` second in the current implementation.
- \`/prices/candles\` is cached for \`15\` seconds for \`1m\` and \`5m\` periods, and \`60\` seconds for larger periods.
- \`/tokens\` returns the configured token list for the network. If you need richer token data with current prices, use API v2 or SDK v2, which read from \`/tokens/info\`.
- If you need retries or fallback behavior, implement that in your app. These docs do not publish a public SLA.
---
## Contracts for V1
Docs for the GMX V1 contracts.
## Important Notes
:::danger Important
GMX V1 contracts have been sunset, and trading or providing liquidity is no longer supported.
:::
:::info Important
Please note that these docs are meant just as an overview, please check the actual contract code for the exact implementation and for any possible edge cases if building an application, integration or similar using the contracts.
Please subscribe to the channels in the \[Updates and Support\](../api/updates-support.md) page for important contract update notifications.
:::
## Overview
A technical overview of GMX V1 can be found in this \[Notion Doc\](https://gmx-io.notion.site/GMX-Technical-Overview-47fc5ed832e243afb9e97e8a4a036353).
## Arbitrum
- GMX: \[0xfc5A1A6EB076a2C7aD06eD22C90d7E710E35ad0a\](https://arbiscan.io/address/0xfc5A1A6EB076a2C7aD06eD22C90d7E710E35ad0a)
- Vault: \[0x489ee077994B6658eAfA855C308275EAd8097C4A\](https://arbiscan.io/address/0x489ee077994B6658eAfA855C308275EAd8097C4A)
- Router: \[0xaBBc5F99639c9B6bCb58544ddf04EFA6802F4064\](https://arbiscan.io/address/0xaBBc5F99639c9B6bCb58544ddf04EFA6802F4064)
- PositionRouter: \[0xb87a436B93fFE9D75c5cFA7bAcFff96430b09868\](https://arbiscan.io/address/0xb87a436B93fFE9D75c5cFA7bAcFff96430b09868)
- OrderBook: \[0x09f77e8a13de9a35a7231028187e9fd5db8a2acb\](https://arbiscan.io/address/0x09f77e8a13de9a35a7231028187e9fd5db8a2acb)
- Reader: \[0x22199a49A999c351eF7927602CFB187ec3cae489\](https://arbiscan.io/address/0x22199a49A999c351eF7927602CFB187ec3cae489)
- RewardReader: \[0x8BFb8e82Ee4569aee78D03235ff465Bd436D40E0\](https://arbiscan.io/address/0x8BFb8e82Ee4569aee78D03235ff465Bd436D40E0)
- OrderBookReader: \[0xa27C20A7CF0e1C68C0460706bB674f98F362Bc21\](https://arbiscan.io/address/0xa27C20A7CF0e1C68C0460706bB674f98F362Bc21)
- StakedGmx: \[0xd2D1162512F927a7e282Ef43a362659E4F2a728F\](https://arbiscan.io/address/0xd2D1162512F927a7e282Ef43a362659E4F2a728F)
- StakedGlp: \[0x5402B5F40310bDED796c7D0F3FF6683f5C0cFfdf\](https://arbiscan.io/address/0x5402B5F40310bDED796c7D0F3FF6683f5C0cFfdf)
- GlpManager: \[0x3963FfC9dff443c2A94f21b129D429891E32ec18\](https://arbiscan.io/address/0x3963FfC9dff443c2A94f21b129D429891E32ec18)
- RewardRouter: \[0x5E4766F932ce00aA4a1A82d3Da85adf15C5694A1\](https://arbiscan.io/address/0x5E4766F932ce00aA4a1A82d3Da85adf15C5694A1)
- GlpRewardRouter: \[0xB95DB5B167D75e6d04227CfFFA61069348d271F5\](https://arbiscan.io/address/0xB95DB5B167D75e6d04227CfFFA61069348d271F5)
- ReferralStorage: \[0xe6fab3F0c7199b0d34d7FbE83394fc0e0D06e99d\](https://arbiscan.io/address/0xe6fab3F0c7199b0d34d7FbE83394fc0e0D06e99d)
- GMX-ETH Uniswap Pool: \[0x80A9ae39310abf666A87C743d6ebBD0E8C42158E\](https://arbiscan.io/address/0x80A9ae39310abf666A87C743d6ebBD0E8C42158E)
## Avalanche
- GMX: \[0x62edc0692BD897D2295872a9FFCac5425011c661\](https://snowtrace.io/address/0x62edc0692BD897D2295872a9FFCac5425011c661)
- Vault: \[0x9ab2De34A33fB459b538c43f251eB825645e8595\](https://snowtrace.io/address/0x9ab2De34A33fB459b538c43f251eB825645e8595)
- Router: \[0x5F719c2F1095F7B9fc68a68e35B51194f4b6abe8\](https://snowtrace.io/address/0x5F719c2F1095F7B9fc68a68e35B51194f4b6abe8)
- PositionRouter: \[0xffF6D276Bc37c61A23f06410Dce4A400f66420f8\](https://snowtrace.io/address/0xffF6D276Bc37c61A23f06410Dce4A400f66420f8)
- OrderBook: \[0x4296e307f108B2f583FF2F7B7270ee7831574Ae5\](https://snowtrace.io/address/0x4296e307f108B2f583FF2F7B7270ee7831574Ae5)
- Reader: \[0x67b789D48c926006F5132BFCe4e976F0A7A63d5D\](https://snowtrace.io/address/0x67b789D48c926006F5132BFCe4e976F0A7A63d5D)
- RewardReader: \[0x04Fc11Bd28763872d143637a7c768bD96E44c1b6\](https://snowtrace.io/address/0x04Fc11Bd28763872d143637a7c768bD96E44c1b6)
- OrderBookReader: \[0xccFE3E576f8145403d3ce8f3c2f6519Dae40683B\](https://snowtrace.io/address/0xccFE3E576f8145403d3ce8f3c2f6519Dae40683B)
- StakedGmx: \[0x4d268a7d4C16ceB5a606c173Bd974984343fea13\](https://snowtrace.io/address/0x4d268a7d4C16ceB5a606c173Bd974984343fea13)
- StakedGlp: \[0xaE64d55a6f09E4263421737397D1fdFA71896a69\](https://snowtrace.io/address/0xaE64d55a6f09E4263421737397D1fdFA71896a69)
- GlpManager: \[0xD152c7F25db7F4B95b7658323c5F33d176818EE4\](https://snowtrace.io/address/0xD152c7F25db7F4B95b7658323c5F33d176818EE4)
- RewardRouter: \[0x091eD806490Cc58Fd514441499e58984cCce0630\](https://snowtrace.io/address/0x091eD806490Cc58Fd514441499e58984cCce0630)
- GlpRewardRouter: \[0xB70B91CE0771d3f4c81D87660f71Da31d48eB3B3\](https://snowtrace.io/address/0xB70B91CE0771d3f4c81D87660f71Da31d48eB3B3)
- ReferralStorage: \[0x827ED045002eCdAbEb6e2b0d1604cf5fC3d322F8\](https://snowtrace.io/address/0x827ED045002eCdAbEb6e2b0d1604cf5fC3d322F8)
- GMX-AVAX Trader Joe Pool: \[0x0c91a070f862666bBcce281346BE45766d874D98\](https://snowtrace.io/address/0x0c91a070f862666bBcce281346BE45766d874D98)
## Swap
To execute a swap:
- Approve the Router contract for the token and amount you would like to swap
- Call Router.swap with parameters:
- \\\_path: \[tokenIn, tokenOut\]
- \\\_amountIn: amount of tokenIn to swap
- \\\_minOut: minimum expected output amount
- \\\_receiver: address of the receiver of tokenOut
- The function will revert if the amount of tokenOut sent to the receiver is less than \\\_minOut
To get swap amounts before execution:
- Call Reader.getMaxAmountIn with parameters:
- \\\_vault: address of the vault
- \\\_tokenIn: address of token that will be given
- \\\_tokenOut: address of token to be received
- The max amount of tokenIn that can be swapped will be returned
- Call Reader.getAmountOut with parameters:
- \\\_vault: address of the vault
- \\\_tokenIn: address of token that will be given
- \\\_tokenOut: address of token to be received
- \\\_amountIn: amount of tokenIn to swap
- Two values will be returned, the first is the amount out after fees, and the second is the fee amount
- The fee amount will be in terms of tokenOut
Tokens have a usdgAmount in the Vault contract used for some calculations, this amount is updated on minting of GLP, redemption of GLP and swaps based on the price of the token at the time. Due to price fluctuations this value may drift slightly from the actual USD value of the tokens in the pool, the usdgAmount is periodically updated to re-align values.
## Query Available Amounts
The maximum sum of all position sizes is limited by the amount of tokens there are in the pool and any additional caps.
To calculate the available amount of liquidity for long positions:
- indexToken: the address of the token to long
- Available amount in tokens: Vault.poolAmounts(indexToken) - Vault.reservedAmounts(indexToken)
- Available amount in USD: PositionRouter.maxGlobalLongSizes(indexToken) - Vault.guaranteedUsd(indexToken)
- The available liquidity will be the lower of these two values
- PositionRouter.maxGlobalLongSizes(indexToken) can be zero, in which case there is no additional cap, and available liquidity is based only on the available amount of tokens
To calculate the available amount of liquidity for short positions:
- indexToken: the address of the token to short
- collateralToken: the address of the stablecoin token to be used as collateral
- Available amount in tokens: Vault.poolAmounts(collateralToken) - Vault.reservedAmounts(collateralToken)
- Available amount in USD: PositionRouter.maxGlobalShortSizes(indexToken) - Vault.globalShortSizes(indexToken)
- The available liquidity will be the lower of these two values
- PositionRouter.maxGlobalShortSizes(indexToken) can be zero, in which case there is no additional cap, and available liquidity is based only on the available amount of tokens
## Opening / Increasing a Position
To open or increase the size of an existing position:
- Approve the PositionRouter as a Router plugin for your account
- Router.approvePlugin(PositionRouter address)
- Approve the Router contract for the token and amount you would deposit as collateral for the position
- Call PositionRouter.createIncreasePosition with parameters:
- \\\_path: \[collateralToken\] or \[tokenIn, collateralToken\] if a swap is needed
- \\\_indexToken: the address of the token you want to long or short
- \\\_amountIn: the amount of tokenIn you want to deposit as collateral
- \\\_minOut: the min amount of collateralToken to swap for
- \\\_sizeDelta: the USD value of the change in position size
- \\\_isLong: whether to long or short
- \\\_acceptablePrice: the USD value of the max (for longs) or min (for shorts) index price acceptable when executing the request
- \\\_executionFee: can be set to PositionRouter.minExecutionFee
- \\\_referralCode: \[referral code\](../referrals.md) for affiliate rewards and rebates
- \\\_callbackTarget: an optional callback contract, this contract will be called on request execution or cancellation
- After this transaction is sent a keeper will execute the request, the request will either be executed or cancelled
- If the position cannot be increased for reasons such as the \\\_acceptablePrice not being fulfillable or there being insufficient liquidity then the request will be cancelled and funds will be sent back to the msg.sender that called PositionRouter.createIncreasePosition
- \\\_minOut can be zero if no swap is required
- USD values for \\\_sizeDelta and \\\_price are multiplied by (10 \\\*\\\* 30), so for example to open a long position of size 1000 USD, the value 1000 \\\* (10 \\\*\\\* 30) should be used
Note that if the position increase request is created with PositionRouter.createIncreasePositionETH then in case of cancellation the PositionRouter would send ETH to the receiver using \`receiver.send(amount)\`, this has a limit of 2300 gas. If the receiver is a contract and the receive function invoked on the transfer requires more than 2300 gas, this call can fail which would cause the ETH to be left in the PositionRouter.
WETH and PositionRouter.createIncreasePosition should be used instead to avoid this issue.
## Closing / Decreasing a Position
To close or decrease an existing position:
- Call PositionRouter.createDecreasePosition with parameters:
- \\\_path: \[collateralToken\] or \[collateralToken, tokenOut\] if a swap is needed
- \\\_indexToken: the index token of the position
- \\\_collateralDelta: the amount of collateral in USD value to withdraw
- \\\_sizeDelta: the USD value of the change in position size
- \\\_isLong: whether the position is a long or short
- \\\_receiver: the address to receive the withdrawn tokens
- \\\_acceptablePrice: the USD value of the min (for longs) or max (for shorts) index price acceptable when executing the request
- \\\_minOut: the min output token amount
- \\\_executionFee: can be set to PositionRouter.minExecutionFee
- \\\_withdrawETH: only applicable if WETH will be withdrawn, the WETH will be unwrapped to ETH if this is set to true
- \\\_callbackTarget: an optional callback contract, this contract will be called on request execution or cancellation
- After this transaction is sent a keeper will execute the request, the request will either be executed or cancelled
- If the position cannot be decreased for reasons such as the \\\_acceptablePrice not being fulfillable then the request will be cancelled and there will be no change to the position
- \\\_minOut can be zero if no swap is required
Note that if \`\_withdrawETH\` is \`true\` then the position decrease request would send ETH to the receiver using \`receiver.send(amount)\`, this has a limit of 2300 gas. If the receiver is a contract and the receive function invoked on the transfer requires more than 2300 gas, this call can fail which would cause the ETH to be left in the PositionRouter.
Set \`\_withdrawETH\` to \`false\` instead to avoid this issue.
## Positions List
A list of position details can be retrieved by calling Reader.getPositions with params:
- \\\_vault: the vault contract address
- \\\_account: the account of the user
- \\\_collateralTokens: an array of collateralTokens
- \\\_indexTokens: an array of indexTokens
- \\\_isLong: an array of whether the position is a long position
The returned positions will be in the order of the query, for example, given the following inputs:
- \\\_collateralTokens: \[WBTC.address, WETH.address, USDC.address\]
- \\\_indexTokens: \[WBTC.address, WETH.address, WBTC.address\]
- \\\_isLong: \[true, true, false\]
The position details would be returned for:
- Long BTC position, positionIndex: 0
- Long ETH position, positionIndex: 1
- Short BTC position, positionIndex: 2
The returned array would be a list of values ordered by the positions:
- size
- position size in USD
- value at: positionIndex \\\* 9
- collateral
- position collateral in USD
- value at: positionIndex \\\* 9 + 1
- averagePrice
- average entry price of the position in USD
- value at: positionIndex \\\* 9 + 2
- entryFundingRate
- a snapshot of the cumulative funding rate at the time the position was entered
- value at: positionIndex \\\* 9 + 3
- hasRealisedProfit
- 1 if the position has a positive realised profit, 0 otherwise
- value at: positionIndex \\\* 9 + 4
- realisedPnl
- the realised PnL for the position in USD
- value at: positionIndex \\\* 9 + 5
- lastIncreasedTime
- timestamp of the last time the position was increased
- value at: positionIndex \\\* 9 + 6
- hasProfit
- 1 if the position is currently in profit, 0 otherwise
- value at: positionIndex \\\* 9 + 7
- delta
- amount of current profit or loss of the position in USD
- value at: positionIndex \\\* 9 + 8
## Buying / Selling GLP
Buying and selling GLP can be done through the GlpRewardRouter.
To buy GLP, call mintAndStakeGlp with params:
- \\\_token: the token to buy GLP with
- \\\_amount: the amount of token to use for the purchase
- \\\_minUsdg: the minimum acceptable USD value of the GLP purchased
- \\\_minGlp: the minimum acceptable GLP amount
To sell GLP, call unstakeAndRedeemGlp with params:
- \\\_tokenOut: the token to sell GLP for
- \\\_glpAmount: the amount of GLP to sell
- \\\_minOut: the minimum acceptable amount of tokenOut to be received
- \\\_receiver: the address to send tokenOut to
Note that GLP can only be redeemed up to the reservedAmount, which is based on the amount of open interest, if the pool has been fully redeemed up to the reservedAmount then redeemers will need to wait for positions to close before further redemptions can be done, in this scenario the borrowing fee APR would be very high so liquidity providers will be incentivised to mint GLP and traders will be incentivised to close positions
## GLP Price
The price of GLP can be retrieved using the \`getPrice(\_maximise)\` function of the GlpManager.
- To get the price of GLP for buying GLP use \`GlpManager.getPrice(true)\`
- To get the price of GLP for selling GLP use \`GlpManager.getPrice(false)\`
The price of GLP factors in the pending PnL of the open long and short positions.
If you are calculating the pending PnL for shorts manually please use the \`glpManager.shortsTracker.globalShortAveragePrices\` value instead of the \`vault.globalShortAveragePrices\` value.
## Transferring Staked GLP
When GLP is bought it is automatically staked and when it is sold it is automatically unstaked, for integrations adding GLP the StakedGlp contract can be used to transfer staked GLP tokens.
StakedGlp behaves like a regular ERC20 token, the user can call approve on it to approve your contract, then your contract can call transferFrom to transfer the GLP tokens to any receiving account or contract. When transferring, the StakedGlp contract will unstake GLP from the user and stake the GLP for the receiving account, the receiving account or contract would then start earning rewards which can be compounded or claimed by calling handleRewards on the RewardRouter contract.
## Staking
The RewardRouter contract handles the necessary actions needed for staking in a single transaction.
When staking GMX:
- The RewardRouter deposits the GMX token into the StakedGmxTracker contract
- The StakedGmxTracker issues itself as a token for each token deposited
- esGMX can similarly be deposited into the StakedGmxTracker
- The StakedGmxTracker distributes esGMX to staked tokens
- After this step, the RewardRouter deposits the StakedGmxTracker tokens into the BonusGmxTracker
- The BonusGmxTracker distributes Multiplier Points to staked tokens
- Finally the BonusGmxTracker tokens are deposited into the FeeGmxTracker which distributes ETH or AVAX to staked tokens
When buying GLP:
- The RewardRouter sends the funds to be deposited to the GlpManager and mints GLP tokens
- The RewardRouter then deposits the GLP tokens to the FeeGlpTracker which distributes ETH or AVAX to the staked tokens
- Finally the RewardRouter deposits the FeeGlpTracker tokens into the StakedGlpTracker which distributes esGMX to staked tokens
Addresses for contracts can be found in the \[interface code\](https://github.com/gmx-io/gmx-interface/blob/master/src/config/contracts.ts).
To get the deposit balances for an account you can use RewardTracker.depositBalances(account, token), or RewardReader.getDepositBalances(account, depositTokens, rewardTrackers).
To get claimable rewards you can use RewardReader.getStakingInfo(account rewardTrackers), this returns an array of uint256 values in the order:
- Claimable rewards
- Amount of reward token distribution per second
- Average staked amount for account
- Total rewards distributed to account
- Total staked tokens in the rewardTracker
---
## Liquidity on V1
GLP was the liquidity provider token for V1. Since July 2025, GLP has been phased out and no longer provides liquidity as V1 trading is disabled, so buying GLP tokens is no longer possible. You may only redeem existing GLP via the \[sell GLP\](https://v1.app.gmx.io/#/sell\_glp) page.
If you have been holding GLP, you may have claims available, please check \[distributions section\](https://app.gmx.io/#/earn/distributions) for any claims.
## GLP Token Addresses
- Arbitrum: \[0x1aDDD80E6039594eE970E5872D247bf0414C8903\](https://arbiscan.io/token/0x1aDDD80E6039594eE970E5872D247bf0414C8903)
- Avalanche: \[0x9e295B5B976a184B14aD8cd72413aD846C299660\](https://snowtrace.io/address/0x9e295B5B976a184B14aD8cd72413aD846C299660)
---
## Trading on V1
Trading on V1 has been phased out since July 2025. Please close any positions using \[v1.app.gmx.io\](https://v1.app.gmx.io/#/v1).
---
## Community
Stay up to date with GMX news and connect with the community across the channels listed below.
## Official channels
The following channels carry announcements and updates from the GMX team.
- \[Telegram announcements\](https://t.me/GMX\_Announcements)
- \[Telegram technical announcements\](https://t.me/GMX\_Technical\_Announcements)
- \[Discord\](https://discord.com/invite/H5PeQru3Aa)
- \[Twitter\](https://twitter.com/GMX\_IO)
- \[Substack\](https://gmxio.substack.com/)
- \[Telegram (English)\](https://t.me/GMX\_IO)
- \[GitHub\](https://github.com/gmx-io)
## Community groups
The following are spaces for discussion and support.
- \[Telegram (Portuguese)\](https://t.me/GMX\_Portuguese)
- \[Telegram (Chinese)\](https://t.me/gmxch)
- \[Telegram trading chat\](https://t.me/gambittradingchat)
## Media kit
The \[GMX assets repository\](https://github.com/gmx-io/gmx-assets) contains logos for GMX and its liquidity products — including GM pools and GLV vaults — in SVG and PNG formats.
## Courses
The \[Cyfrin GMX course\](https://updraft.cyfrin.io/courses/gmx-perpetuals-trading) covers GMX protocol mechanics, token pricing, fees, and advanced features. It is sponsored by GMX and Arbitrum DAO.
---
## Proposal Process
Submitting a proposal to the GMX DAO follows a structured process, outlined below:
## Phase 1: Ideation
Phase 1 is where a proposal begins. You share your concept with the community to gather early feedback before committing to a formal document.
Post your idea on \[the GMX governance forum\](https://gov.gmx.io/) using the \`#idea\` tag. This creates a dedicated discussion thread where community members can weigh in. Many ideas also take shape informally in Discord or Telegram before a forum post is created.
If your idea gains traction, you may use Telegram polls to gauge community endorsement for the specifications you plan to include in a future Request for Comment (RFC). This soft consensus helps you understand whether your concept is ready to advance to Phase 2.
\*\*Duration:\*\* Open
## Phase 2: Request for Comment
In Phase 2, you shape your idea into a formal Request for Comment (RFC) and post it to the governance forum using the RFC template (link pending DAO approval). This invites structured community input and marks the start of the formal review process.
As you draft your RFC, incorporate community feedback and revise the proposal iteratively. The goal is to build enough endorsement to establish soft consensus, reducing the risk of rejection when the proposal advances to a formal vote.
Your RFC must follow this structure:
- Summary
- Motivation
- Rationale
- Specifications
- Conclusion
Once your RFC has addressed the community's questions and feedback, it can advance to Phase 3.
\*\*Duration:\*\* Open
## Phase 3: Snapshot Voting
Once your RFC has built sufficient community support, it advances to a formal off-chain vote on \[Snapshot\](https://snapshot.org/#/gmx.eth/). Voting power is based on token balance, which gives the broader GMX community a direct voice in the outcome.
The following parameters apply:
- \*\*Voting mechanism:\*\* Simple majority (50% + 1 of the smallest token unit)
- \*\*Minimum tokens to submit a proposal:\*\* 10,000
- \*\*Quorum:\*\* 50,000
- \*\*Voting window:\*\* 5 days
If a vote passes on Snapshot but a GMX DAO delegate opposes the result, the delegate must initiate a veto proposal on Tally promptly.
## Phase 4: Tally (Optional)
Create a Tally proposal only when an on-chain transaction is required from the GMX DAO. Submit your proposal to \[the GMX DAO on Tally\](https://www.tally.xyz/gov/gmx) for on-chain execution.
Your proposal must include a title and a clear description of its proposed actions. The following parameters apply:
- \*\*Voting mechanism:\*\* Qualified majority (65% + 1 of the smallest token unit)
- \*\*Quorum:\*\* \[View current quorum on Tally\](https://www.tally.xyz/gov/gmx/delegates)
- \*\*Minimum tokens to submit a proposal:\*\* 30,000
- \*\*Voting delay:\*\* 24 hours
- \*\*Voting window:\*\* 5 days
- \*\*Execution delay:\*\* 24 hours
The minimum token threshold for proposing a GIP may increase depending on voter turnout and the DAO’s total voting power.
Follow-up implementations of proposals already approved on Snapshot don’t require a new Snapshot vote.
GMX DAO delegates on Tally are expected to vote “For” proposals that have already passed the Snapshot vote, unless there is a veto proposal or a particularly strong reason to vote against.
---
## Voting power
## Overview
The \`GMX\_DAO\` token is the governance token of the GMX DAO. It lets you participate directly in protocol governance through on-chain voting and delegation.
The governance system is built on three interconnected contracts: \`GovToken\` (an ERC-20 with on-chain vote checkpointing via ERC20Votes), \`ProtocolGovernor\` (an OpenZeppelin Governor contract with compatibility for the Bravo governance interface and a 3% quorum requirement), and \`GovTimelockController\` (a TimelockController that enforces a mandatory delay before approved proposals are executed). Together, these contracts decentralize protocol decision-making and strengthen community involvement in the GMX ecosystem.
## Staking and voting power
To participate in GMX DAO governance, you must stake your GMX (or esGMX) tokens in the Earn section of the \[GMX App\](https://app.gmx.io/#/earn). When you stake, the \`RewardRouterV2\` contract mints \`GMX\_DAO\` tokens to your address at a 1:1 ratio. These tokens carry your voting power and let you vote on proposals directly or delegate your votes to a representative.
\`GMX\_DAO\` is a non-transferable governance token. Only the staking contract (which holds the \`GOV\_TOKEN\_CONTROLLER\` role) can mint, burn, or move \`GMX\_DAO\` tokens — you can't transfer them freely between wallets. When you unstake your GMX or esGMX, the contract burns the corresponding \`GMX\_DAO\` balance and you lose the associated voting power immediately.
:::warning
On Arbitrum, if you hold \`GMX\_DAO\` tokens but haven't delegated them — either to yourself or to another address — the GMX App disables the Stake and Claim buttons. To restore access, delegate your tokens on \[Tally\](https://www.tally.xyz/gov/gmx) before attempting these actions. This enforcement applies to Arbitrum only; the Avalanche frontend does not apply the same restriction.
:::
:::note
Unstaked GMX and esGMX tokens carry no voting power. You must stake first to receive \`GMX\_DAO\` tokens and become eligible to vote or delegate.
:::
## Nominating yourself as a delegate
To nominate yourself as a GMX DAO delegate, complete the following steps.
1. Write a delegate statement on the \[GMX Governance forum\](https://gov.gmx.io/). Your statement serves as your application to the community — describe your experience, areas of expertise, and how you intend to contribute to the protocol.
2. Navigate to \[Tally\](https://www.tally.xyz/gov/gmx) and connect your wallet. Ensure your wallet is connected to the Arbitrum network.
3. Click \*\*My Voting Power\*\* on the right side of the screen to open the delegation page.
4. Click \*\*Delegate\*\*. You'll see two options:
- \*\*Myself\*\* — delegates voting power to the currently connected wallet. Select this to nominate yourself as a delegate.
- \*\*Someone else\*\* — delegates voting power to a different wallet address. Enter the target wallet address to proceed.
5. Confirm the transaction. Once confirmed, your name appears on the GMX DAO landing page alongside other delegates.
## Delegating your voting power
If you hold GMX tokens but can't actively participate in governance, you can delegate your voting power to a community member who votes on your behalf.
:::warning
When you delegate your voting power, you're entrusting another party to vote on your behalf. Choose a delegate whose values align with yours and who you trust to act in the best interest of the GMX DAO and its community.
:::
To delegate your voting power, complete the following steps.
1. Open the \[GMX App\](https://app.gmx.io/#/) and click \*\*Earn\*\* in the navigation menu.
2. Click \*\*Stake\*\* to open the staking dialog and stake your GMX tokens. Once staked, your voting power is reflected as \`GMX\_DAO\` tokens.
3. Click \*\*Delegate\*\* to open the \[My Voting Power page on Tally\](https://www.tally.xyz/gov/gmx/my-voting-power).
4. Connect your wallet to Tally and ensure it's connected to the Arbitrum network.
5. Browse for a delegate: review the \*\*Rising Delegates\*\* section, or click \*\*Explore all delegates\*\* to see all available delegates.
6. Click \*\*Delegate\*\* next to your chosen representative to assign your voting power.
- Alternatively, click \*\*My Voting Power\*\* to manage delegation directly. From that page, click \*\*Delegate\*\* and choose \*\*Myself\*\* or \*\*Someone else\*\*. If you choose \*\*Someone else\*\*, enter the wallet address of your intended delegate.
7. Wait for the transaction to be confirmed on the blockchain. Delegation is complete once the transaction is confirmed.
You can update your delegation on Tally at any time.
## Next steps
- \[Proposal process\](proposal-process.md) — learn how proposals move from ideation to on-chain vote and execution.
---
## Providing liquidity
GMX lets you earn yield by depositing tokens into liquidity pools. These pools back leverage trading and swaps on the platform, and liquidity providers earn the majority of the fees generated from trading, liquidations, borrow fees, and swaps (63% on Arbitrum and Avalanche, 50% on Botanix). There are two types of pools: automated GLV pools and individual GM pools.
## GLV pools
A GLV (GMX Liquidity Vault) pool consists of:
- \*\*Supported markets:\*\* The markets in which liquidity is provided.
- \*\*Long token:\*\* The token that backs long positions.
- \*\*Short token:\*\* The token that backs short positions.
For example, a GLV \[WETH-USDC\] pool uses WETH to back long positions and USDC to back short positions. The supported markets and allowed liquidity in each market are recommended by \[Chaos Labs\](https://snapshot.org/#/gmx.eth/proposal/0xe5631173e5f81906e0497b6fe209ef2c72b4b8d882a0250ce0feeafb8278fb72).
Liquidity is automatically shifted between supported markets based on utilization and Chaos Labs recommendations. The list of supported markets displayed for each GLV can change as additional markets are approved and added.
## GM pools
A GM (GMX Market) pool consists of:
- \*\*Index price feed:\*\* Positions are opened and closed based on this price feed.
- \*\*Long token:\*\* The token that backs long positions.
- \*\*Short token:\*\* The token that backs short positions.
For example, an ETH/USD \[WETH-USDC\] market uses the ETH/USD price feed, with WETH backing long positions and USDC backing short positions.
If a market is labeled as SWAP-ONLY or SPOT-ONLY, it only supports swaps and does not support leverage trading.
For single-token backed pools, both the long and short token are the same. For example, a single-token WETH pool uses WETH for both.
### Single-token vs multi-token pools
Single-token pools differ from multi-token pools in how they handle swaps, price impact, and asset exposure. The differences affect both liquidity providers and traders.
\*\*For liquidity providers:\*\*
- \*\*Zero swap price impact on deposits and withdrawals.\*\* In multi-token pools, depositing a single token shifts the balance between the long and short token pools, incurring swap price impact. In single-token pools, both sides of the pool are the same token, so the swap price impact factor is set to zero — deposits and withdrawals have no price impact regardless of size.
- \*\*Single-asset exposure.\*\* You hold one token instead of two. There is no rebalancing between different assets, so your position tracks the price of a single token rather than a mix.
- \*\*No swaps.\*\* Single-token pools do not support swap operations — they are used for leverage trading only.
\*\*For traders:\*\*
- \*\*No swap fees on position operations.\*\* In multi-token pools, opening or closing a position may require a swap between the collateral token and the PnL token, incurring swap fees and swap price impact. In single-token pools, collateral, PnL, and pool backing all use the same token — no token conversion is needed, so there are no swap fees or swap price impact on any position operation.
- \*\*Reduced or zero position price impact.\*\* The \[net price impact\](./trading/fees.md#price-impact-and-price-impact-rebates) based on open interest imbalance is configured per market. The major single-token markets (BTC/USD \[WBTC.e-WBTC.e\], ETH/USD \[WETH-WETH\]) have position impact factors set to zero — meaning no position price impact at all. Smaller single-token markets may have non-zero position impact factors configured based on their liquidity depth.
Each GM pool is risk-isolated — liquidity providers are only exposed to the markets they deposit into. Profits and losses of traders in one market do not affect pools in other markets.
## Market types
GM pools back two types of markets, which differ in how the pool's tokens cover trader PnL.
### Fully backed markets
In a fully backed market, the index token and the long collateral token are the same asset. For example, an ETH/USD perp market backed by an ETH-USDC pool uses ETH as both the index token and the long collateral token.
Because long position profits are paid out in ETH and the pool holds ETH directly, the pool's ETH balance can always cover the pending PnL of long positions — as long as open interest caps are respected. The protocol enforces these caps via the \`MAX\_OPEN\_INTEREST\` parameter, which is configured per market and per side.
For example, a pool holds 1,000 ETH and 1,000,000 USDC. The max long open interest is capped at 900 ETH and the max short open interest at 900,000 USDC. Under these constraints, all profits can be paid regardless of how the price of ETH moves, because the pool holds the same asset that backs the positions.
### Synthetic markets
In a synthetic market, the index token differs from the long collateral token. For example, a DOGE/USD perp market backed by an ETH-USDC pool uses DOGE as the index token but ETH as the long collateral. This means long position profits are denominated in DOGE price terms but paid out from the pool's ETH balance.
If DOGE's price rises faster than ETH's price, the pending profits of DOGE long positions — measured in USD — can grow faster than the USD value of ETH in the pool. In extreme cases, pending profits may exceed the pool's capacity to pay them out.
For example, a pool holds 1,000 ETH and 1,000,000 USDC. The max DOGE long open interest is capped at 300 ETH worth. If DOGE increases 10x while ETH increases only 2x, the pending USD profits of DOGE longs outpace the USD value of the ETH backing them, and the pool may not be able to cover all profits.
## Buying GLV / GM tokens
You can buy GLV / GM tokens on the \[GLV / GM pools\](https://app.gmx.io/#/pools) page. ETH or AVAX is required to send the buy transaction. If you need to bridge funds, you can use \[Jumper Exchange\](https://jumper.exchange/).
To buy tokens:
1. Select the "Market" and "Pool" of the GLV / GM token you want to purchase.
2. Review the price impact displayed in the "Buy GLV / GM" box. Your purchase has a positive or negative price impact depending on whether it improves or reduces the balance of tokens in the pool.
3. If the pool is mostly balanced, a large purchase may result in a significant negative price impact. To avoid this, select the "Pair" option to buy with an equal USD amount of long and short tokens.
## Selling GLV / GM tokens
You can sell GLV / GM tokens on the \[GLV / GM pools\](https://app.gmx.io/#/pools) page.
Tokens in a market are reserved based on the total open interest. The reserve factor determines how much of the pool can be committed to backing positions:
\`\`\`
available liquidity = (pool tokens × reserve factor) − reserved tokens
\`\`\`
Where \*\*reserved tokens\*\* are tokens already committed to cover open positions. The reserve factor is a per-market parameter (typically between 0.5 and 0.95) that prevents the pool from being fully drained by trader positions.
Additionally, each market has \`MAX\_OPEN\_INTEREST\` caps per side (long/short) and \`MAX\_POOL\_AMOUNT\` caps that limit total deposits. These parameters ensure the pool can always cover trader profits under normal conditions.
If the available liquidity for redemption reaches zero, you need to wait for positions to close or for other providers to deposit liquidity before you can sell. The borrow fee rate is also higher in this case, which helps incentivize new deposits.
## Shifting GM tokens
You can shift GM tokens on the \[GM pools\](https://app.gmx.io/#/pools) page.
GM tokens can only be shifted to another pool that has the same backing tokens, which lets you move liquidity without incurring buy or sell fees. Price impact still applies to shifts, but for balanced pools it is minimal. Price impact costs are displayed on the interface as usual.
## Token pricing
The price of a GM token is:
\`\`\`
GM token price = (pool value + net pending PnL) / GM totalSupply
\`\`\`
Where \*\*pool value\*\* includes the USD worth of deposited long and short tokens plus accumulated borrowing fees, and \*\*net pending PnL\*\* is the aggregate unrealized profit/loss of all open trader positions in the market.
The pending PnL component is capped using the \`MAX\_PNL\_FACTOR\` parameter, which has separate values for deposits, withdrawals, and trader position closures. This capping prevents extreme trader profits from fully draining pool value during a single deposit or withdrawal. GLV token prices follow the same principle, aggregated across all underlying GM markets in the vault.
Fees from trading, swaps, borrowing, and liquidations flow directly into the pool, increasing pool value and therefore the GM token price over time. There is no separate claim or distribution step — holding GM tokens is enough to earn fees. On Arbitrum and Avalanche, 63% of collected fees go to the pool and 37% go to the protocol. On Botanix the split is 50/50. You can check the current annualized performance for each pool on the \[Pools\](https://app.gmx.io/#/pools) page.
Some long and short tokens may have a spread, which results in a corresponding spread when buying or selling GLV / GM tokens.
GLV / GM pools aim to maintain an equal worth of long and short tokens. When the price of a long token increases, there may be a positive price impact to incentivize selling long tokens for short tokens, rebalancing the pool. While this balancing is incentivized, pools may not always be perfectly balanced. If a pool maintains its balance, its pricing (excluding PnL) mimics a portfolio that is 50% long token and 50% short token, rebalancing as prices change.
## Performance APY calculation
The annualized performance APY for GM and GLV tokens measures the excess return compared to a benchmark strategy of holding the underlying tokens in a geometric mean portfolio.
### Variable definitions
| Variable | Definition |
| ------------- | --------------------------------------------------- |
| \`TokenA\_S\` | Token A starting price |
| \`TokenB\_S\` | Token B starting price |
| \`TokenA\_E\` | Token A ending price |
| \`TokenB\_E\` | Token B ending price |
| \`GM\_S\` | GM token starting price |
| \`GM\_E\` | GM token ending price |
| \`Benchmark\_S\` | Benchmark investment starting price (equals \`GM\_S\`) |
| \`Benchmark\_E\` | Benchmark investment ending price |
| \`duration\` | Number of days in the measurement period |
### Calculation steps
\*\*Step 1: Calculate benchmark ending price\*\*
The benchmark represents a geometric mean portfolio of the underlying tokens:
\`\`\`
Benchmark\_E = GM\_S × √((TokenA\_E × TokenB\_E) / (TokenA\_S × TokenB\_S))
\`\`\`
\*\*Step 2: Calculate annualized performance\*\*
The annualized performance APY is the excess return of GM compared to the benchmark, annualized:
\`\`\`
Annualized Performance (%) = ((GM\_E - Benchmark\_E) / GM\_S) × 100 × (365 / duration)
\`\`\`
Worked example
Given:
- \`TokenA\_S\` = $100, \`TokenA\_E\` = $110
- \`TokenB\_S\` = $200, \`TokenB\_E\` = $190
- \`GM\_S\` = $141.42, \`GM\_E\` = $144.57
- \`duration\` = 30 days
\*\*Benchmark calculation:\*\*
\`\`\`
Benchmark\_E = 141.42 × √((110 × 190) / (100 × 200))
= 141.42 × √(20,900 / 20,000)
= 141.42 × √1.045
= 141.42 × 1.0222
= 144.56
\`\`\`
\*\*Performance calculation:\*\*
\`\`\`
Annualized Performance = ((144.57 - 144.56) / 141.42) × 100 × (365 / 30)
= (0.01 / 141.42) × 100 × 12.167
= 0.000071 × 100 × 12.167
= 0.086%
\`\`\`
## Protocol protections
GMX uses multiple layered mechanisms to keep pools solvent and markets balanced. Each is documented in detail on its respective page.
- \*\*\[Price impact\](./trading/fees.md#price-impact-and-price-impact-rebates)\*\* — Trades that increase the open interest imbalance pay a price impact fee; trades that reduce it receive a better price. Per-market caps limit the maximum impact.
- \*\*\[Adaptive funding\](./trading/fees.md#adaptive-funding)\*\* — The dominant side (longs or shorts) pays the minority side. The rate increases over time while the imbalance persists and decreases as it resolves.
- \*\*\[Borrow fees\](./trading/fees.md#borrow-fees)\*\* — Only the side with larger open interest pays. Uses a kink rate model — the rate increases linearly up to an optimal utilization threshold, then rises steeply above it.
- \*\*\[Open interest caps\](#selling-glv--gm-tokens)\*\* — Each market has per-side \`MAX\_OPEN\_INTEREST\` limits that prevent any single market from over-committing pool liquidity.
- \*\*\[Reserve factor\](#selling-glv--gm-tokens)\*\* — Limits how much of the pool can be committed to backing positions, ensuring liquidity remains available for redemptions.
- \*\*\[PnL factor caps\](#token-pricing)\*\* — \`MAX\_PNL\_FACTOR\` limits how much pending trader PnL can affect pool value during deposits, withdrawals, and position closures.
- \*\*\[Auto-Deleveraging (ADL)\](./trading/liquidations.md#auto-deleveraging-adl)\*\* — Automatically reduces profitable positions when the PnL-to-pool ratio exceeds the market's configured threshold, protecting pool solvency.
- \*\*\[Two-phase execution\](./api/contracts/architecture.md#execution-model)\*\* — Orders are committed on-chain before oracle prices are included, preventing frontrunning and sandwich attacks.
- \*\*\[Virtual inventory\](./api/contracts/known-issues.md#virtual-inventory)\*\* — Tracks impact across correlated markets to prevent users from reducing their net price impact by opening opposing positions in different markets.
- \*\*\[Price impact rebates\](./trading/fees.md#price-impact-and-price-impact-rebates)\*\* — Excess negative price impact beyond a market's cap is claimable as a rebate after a five-day delay, protecting traders from outsized impact during volatile periods.
## Risks
:::warning
Smart contracts carry inherent risk. The team mitigates risks through testing, audits, and bug bounties, but vulnerabilities in smart contract code are always possible. For details on contract operation, see \[Contracts\](./api/contracts/overview.md).
:::
A non-exhaustive list of risks:
- \*\*Smart contract risks:\*\* Vulnerabilities in smart contract code despite testing and audits.
- \*\*Counterparty risks:\*\* The GLV / GM pool is the counterparty to traders. If traders profit, that profit comes from the value of the GLV / GM pool.
- \*\*Token risks:\*\* Bridged tokens depend on the security of the bridge, and pegged tokens carry the risk of depegging.
- \*\*Open interest imbalance:\*\* While funding fees and price impact incentivize balanced long and short open interest, positions may not always be balanced. For example, if long positions are balanced against high-leverage short positions and a sudden price spike occurs, the short positions could be liquidated, temporarily creating an imbalance.
- \*\*GLV shift exploitation:\*\* The GLV shift feature rebalances liquidity between markets based on utilization. An attacker could temporarily inflate utilization in a low-utilization market to trigger a shift, then reverse the position. Position fees and price impact are configured to make this costly.
- \*\*GLV illiquid GM tokens:\*\* GM tokens in a GLV can become illiquid due to high PnL factor or high reserved USD. Users could deposit illiquid GM tokens into a GLV and withdraw liquidity from a different market, leaving the GLV holding illiquid tokens. The \`glvMaxMarketTokenBalanceUsd\` and \`glvMaxMarketTokenBalanceAmount\` parameters limit exposure to risky markets.
- \*\*GLV negative market value:\*\* If the value of a GM market within a GLV becomes negative, the GLV may be unusable until that market's value recovers.
### Hedging open interest imbalance
For liquidity providers that hedge the difference between long and short open interest, the relevant difference is between the long and short \`openInterestInTokens\` values multiplied by the current index token price (notional value), not the difference in \`openInterest\` USD values recorded at position entry. Funding rates and borrow fees use this same notional-based comparison to incentivize balanced long and short open interest.
## Next steps
- \[Trade on GMX\](./trading/overview.md) — Open leveraged positions using pool liquidity.
- \[Contracts\](./api/contracts/overview.md) — Review smart contract details.
- \[GLV / GM pools app\](https://app.gmx.io/#/pools) — Start providing liquidity.
---
## Referrals(Docs)
Get fee discounts and earn rewards through the GMX referral program.
## How it works
The GMX referral program lets you earn rewards when traders you refer open or close positions on GMX V2. To participate as an affiliate, create a referral code and share your referral link.
To create a referral code:
1. Go to the \[Referrals\](https://app.gmx.io/#/referrals) page.
2. Select the \*\*Affiliates\*\* tab.
3. Enter a referral code using letters (A–Z, a–z), digits (0–9), or underscores. Codes are case-sensitive and can be up to 20 characters long.
4. Submit the transaction to register the code on-chain.
:::note
You must create your referral code separately on each network (Arbitrum and Avalanche) to earn rewards on that network.
:::
Once your code is registered, copy your referral link from the Referrals page. The link format is:
\`\`\`text
https://app.gmx.io/#/trade/?ref=your-code
\`\`\`
Share this link on any platform. When a trader opens the link, your referral code is stored in their browser. The code is written permanently to the contract the first time they create an order. From that point on, the trader receives a fee discount and you earn rewards — both are applied automatically.
The referral program is subject to change as determined by GMX token holders. The full \[referral terms\](https://gmx.io/#/referral-terms) are available on the GMX website.
## Claiming rewards
Rewards in the referral program work differently depending on whether you're a trader receiving discounts or an affiliate earning rewards.
### V2
Traders receive fee discounts automatically. The discount is deducted from the position fee at trade execution.
Affiliates accumulate rewards on every trade made by their referred traders. Rewards accrue per market in the collateral token of each market. You can claim them at any time from the \[Referrals\](https://app.gmx.io/#/referrals) page using the "Claimable rebates" card.
### V1 (historical)
V1 trading is no longer active. No new V1 referral rewards are earned. Historically, V1 rewards and discounts were distributed as airdrops — ETH on Arbitrum and AVAX on Avalanche — every Wednesday. Your past V1 distribution history remains viewable on the \[Referrals\](https://app.gmx.io/#/referrals) page, labeled "V1 airdrop."
## Tiers
The referral program uses a tier system to prevent gaming through self-referrals, ensuring affiliates receive rewards for the traders they brought to the platform.
| Tier | Trader discount | Affiliate reward |
| ---- | --------------- | ---------------- |
| 1 | 5% | 5% |
| 2 | 10% | 10% |
| 3 | 10% | 15% |
Anyone can create a Tier 1 code. To upgrade to Tier 2 or Tier 3, your account must meet the following weekly thresholds:
| Tier | Active users | Combined volume |
| ---- | ------------ | --------------- |
| 2 | 15+ | $5M+ |
| 3 | 30+ | $25M+ |
If your account meets these criteria, send a DM to \[@GMXPartners\](https://t.me/GMXPartners) to request an upgrade. Wallet providers and other protocols are also eligible for Tier 2 and Tier 3 rewards.
Rewards and discounts apply to opening and closing fees for leverage trading. They don't apply to borrow fees or funding fees.
Tier 3 affiliates receive their 15% reward in the market's collateral token.
### esGMX rewards
Tier 3 affiliates previously received a weekly esGMX bonus via the fee distributor, capped at 5,000 \[esGMX tokens\](./tokenomics/rewards.md#escrowed-gmx) per week. This distribution ended on February 4, 2026.
If you received esGMX through the referral program before it ended, you can still vest it using the Affiliate vault. To access it, open the vesting modal from the esGMX card on the \[Earn\](https://app.gmx.io/#/earn) page and select the Affiliate vault tab. Unlike standard vesting, the Affiliate vault doesn't require a paired GMX or GLP deposit.
## Transferring a referral code
To transfer ownership of a referral code to a new address, you interact directly with the \`ReferralStorage\` contract through a block explorer. There's no frontend UI for this action.
:::warning
Transferring a referral code is permanent. Once transferred, you lose ownership and only the new owner can transfer it further. There is no way to reclaim the code without the new owner's cooperation. Verify the destination address carefully before submitting.
:::
The \`ReferralStorage\` contract addresses are:
- \*\*Arbitrum:\*\* \[\`0xe6fab3F0c7199b0d34d7FbE83394fc0e0D06e99d\`\](https://arbiscan.io/address/0xe6fab3F0c7199b0d34d7FbE83394fc0e0D06e99d#writeContract)
- \*\*Avalanche:\*\* \[\`0x827ed045002ecdabeb6e2b0d1604cf5fc3d322f8\`\](https://snowtrace.io/address/0x827ed045002ecdabeb6e2b0d1604cf5fc3d322f8#writeContract)
To transfer a code on a given network:
1. Convert your referral code to its \`bytes32\` encoding using a tool like \[DEVoven\](https://www.devoven.com/string-to-bytes32) with the "Append Zeros" option checked. For example, the code \`code\` encodes to \`0x636f646500000000000000000000000000000000000000000000000000000000\`.
2. Open the \`ReferralStorage\` contract link for your network from the list above.
3. Go to the "Write Contract" tab.
4. Connect the wallet that currently owns the referral code.
5. Expand the \`setCodeOwner\` function. Enter the \`bytes32\` value from step 1 in the \`\_code\` field and the destination wallet address in the \`\_newAccount\` field.
6. Submit the transaction by clicking "Write."
---
## Getting Started(V1)
The full SDK v1 client (\`GmxSdk\`) exposes these top-level modules:
- \*\*\`markets\`\*\* — fetch market definitions, pricing, and daily volumes
- \*\*\`tokens\`\*\* — fetch token metadata and balances
- \*\*\`positions\`\*\* — read open positions for an account
- \*\*\`orders\`\*\* — read active orders and submit new ones (long, short, swap, cancel)
- \*\*\`trades\`\*\* — fetch historical trade activity
- \*\*\`accounts\`\*\* — read governance delegate data
- \*\*\`oracle\`\*\* — read raw oracle markets, tokens, and tickers from the configured oracle URL
- \*\*\`utils\`\*\* — fee estimation, price impact, and other calculation helpers
## Before you start
To use \`GmxSdk\`, you need the following:
- An RPC endpoint for your target chain
- A GMX oracle keeper URL — see \[Oracle Prices\](../../api/rest-api/oracle-prices.mdx)
- A Subsquid GraphQL URL — see \[GraphQL\](../../api/graphql.mdx)
- A viem \`WalletClient\` for write operations. For read-only use, you can omit the wallet client, but you still configure the RPC, oracle, and Subsquid URLs.
## Initialization
The following example shows the minimum setup to initialize the SDK and fetch positions for an account on Arbitrum mainnet.
\`\`\`typescript
// 1. Create the SDK instance
const sdk = new GmxSdk({
chainId: 42161, // Arbitrum
rpcUrl: "https://arb1.arbitrum.io/rpc",
oracleUrl: "https://arbitrum-api.gmxinfra.io",
subsquidUrl: "https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql",
});
// 2. Set the account you want to query
sdk.setAccount("0x9f7198eb1b9Ccc0Eb7A07eD228d8FbC12963ea33");
// 3. Fetch market and token data (required for most queries)
const { marketsInfoData, tokensData } = await sdk.markets.getMarketsInfo();
// 4. Fetch open positions for the account
const { positionsData } = await sdk.positions.getPositions({
marketsData: marketsInfoData,
tokensData,
});
console.log(positionsData);
\`\`\`
The SDK doesn't require a wallet client for read-only operations. To submit orders, pass a viem \`WalletClient\`:
\`\`\`typescript
const account = privateKeyToAccount("0x...your-private-key");
const walletClient = createWalletClient({
account,
chain: arbitrum,
transport: http("https://arb1.arbitrum.io/rpc"),
});
const sdk = new GmxSdk({
chainId: 42161,
rpcUrl: "https://arb1.arbitrum.io/rpc",
oracleUrl: "https://arbitrum-api.gmxinfra.io",
subsquidUrl: "https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql",
walletClient,
});
\`\`\`
If you're using CommonJS, require the v1 client from the package root:
\`\`\`javascript
const { GmxSdk } = require("@gmx-io/sdk");
const sdk = new GmxSdk({
chainId: 42161,
rpcUrl: "https://arb1.arbitrum.io/rpc",
oracleUrl: "https://arbitrum-api.gmxinfra.io",
subsquidUrl: "https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql",
});
\`\`\`
:::tip
If you're using wagmi in a React application, pass \`useWalletClient().data\` as the \`walletClient\` parameter after the wallet connects.
:::
## Common workflows
If you want exact "I want to do X" steps, start with the \[Integration guide\](./integration-guide.md):
- Read positions, active orders, and recent trades for one account
- Submit a \`Market Increase\` order with \`orders.long()\`
- Cancel active orders by on-chain order key
- Understand the SDK's simulation, retry, timeout, and eventual-consistency behavior
- Debug duplicate submits, missing receipts, stale reads, and cancel/replace races in \[Troubleshooting\](./troubleshooting.md)
## API Reference
The SDK groups methods into modules, each accessed as a property on the \`GmxSdk\` instance. All methods are async.
### Read methods
#### \`sdk.markets\`
| Method | Parameters | Returns | Notes |
| ----------------------------- | --------------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------- |
| \`getMarkets(offset?, limit?)\` | \`offset: bigint = 0n\`, \`limit: bigint = 300n\` | \`{ marketsData?, marketsAddresses?, error? }\` | Builds the listed market set from oracle market configs plus on-chain reader data |
| \`getMarketsInfo()\` | — | \`{ marketsInfoData?, tokensData?, pricesUpdatedAt? }\` | Fetches full market details including token prices; use this for most workflows |
| \`getDailyVolumes()\` | — | \`Record \\| undefined\` | Returns a map of market address → daily volume in USD (30-decimal precision) |
#### \`sdk.tokens\`
| Method | Parameters | Returns | Notes |
| ----------------- | ---------- | --------------------------------- | -------------------------------------------------------------------------------- |
| \`getTokensData()\` | — | \`{ tokensData, pricesUpdatedAt }\` | Fetches token metadata and current prices for all tokens on the configured chain |
#### \`sdk.positions\`
| Method | Parameters | Returns | Notes |
| ----------------- | ------------------------------------------------------------- | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| \`getPositions(p)\` | \`marketsData\`, \`tokensData\`, \`start?: number\`, \`end?: number\` | \`{ positionsData? }\` | Requires an account set via \`sdk.setAccount()\`. \`start\`/\`end\` are pagination offsets (default 0/1000) |
#### \`sdk.orders\`
| Method | Parameters | Returns | Notes |
| -------------- | -------------------------------------------------------------------------------------------- | --------------------------- | ------------------------------------------------------------------------------------------------ |
| \`getOrders(p)\` | \`marketsInfoData\`, \`tokensData\`, \`account?\`, \`orderTypesFilter?\`, \`marketsDirectionsFilter?\` | \`{ count, ordersInfoData }\` | Returns all active orders for the account; supports filtering by order type and market direction |
#### \`sdk.trades\`
| Method | Parameters | Returns | Notes |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ | --------------------------------------------------------- |
| \`getTradeHistory(p)\` | \`pageSize\`, \`pageIndex\`, \`marketsInfoData?\`, \`tokensData?\`, \`fromTxTimestamp?\`, \`toTxTimestamp?\`, \`marketsDirectionsFilter?\`, \`orderEventCombinations?\`, \`forAllAccounts?\` | \`Promise\` | Fetches paginated trade history from the Subsquid indexer |
#### \`sdk.accounts\`
| Method | Parameters | Returns | Notes |
| -------------------------------- | ------------------ | ---------- | --------------------------------------------------------------------- |
| \`getGovTokenDelegates(account?)\` | \`account?: string\` | \`string\[\]\` | Returns the governance token delegates for the given account address; on chains without a configured GovToken it resolves to \`\[\]\` |
#### \`sdk.oracle\`
| Method | Parameters | Returns | Notes |
| ------ | ---------- | ------- | ----- |
| \`getMarkets()\` | — | \`Promise\` | Fetches raw market configs from the configured oracle URL |
| \`getTokens()\` | — | \`Promise\` | Fetches raw token configs from the configured oracle URL |
| \`getTickers()\` | — | \`Promise\` | Fetches current oracle ticker data from \`/prices/tickers\` |
### Write methods
Write methods submit transactions on-chain and require a \`walletClient\` and an account set via \`sdk.setAccount()\`.
#### Quick order helpers (\`sdk.orders\`)
The quick helpers automatically calculate swap paths, amounts, and fees from the current market state. You don't need to pre-fetch \`marketsInfoData\` or \`tokensData\` — the helpers fetch what they need unless you pass them directly.
| Method | Key parameters | Notes |
| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| \`long(p)\` | \`payAmount\` or \`sizeAmount\`, \`marketAddress\`, \`payTokenAddress\`, \`collateralTokenAddress\`, \`allowedSlippageBps?\`, \`leverage?\`, \`limitPrice?\` | Opens a long position; see \[Usage Examples\](#usage-examples) |
| \`short(p)\` | Same as \`long\` | Opens a short position |
| \`swap(p)\` | \`fromAmount\` or \`toAmount\`, \`fromTokenAddress\`, \`toTokenAddress\`, \`allowedSlippageBps?\`, \`triggerPrice?\` | Executes a token swap; set \`triggerPrice\` for a Limit Swap |
#### Full order methods (\`sdk.orders\`)
Full methods require pre-computed amounts (use the \`utils\` module or the calculation helpers in \`@gmx-io/sdk/utils/trade\`).
| Method | Notes |
| ----------------------------------- | ---------------------------------------------------------------------------------------- |
| \`createIncreaseOrder(p)\` | Creates a Market Increase or Limit Increase order; see \[Usage Examples\](#usage-examples) |
| \`createDecreaseOrder(p)\` | Creates a Market Decrease, Stop-Loss, or Take-Profit order |
| \`createSwapOrder(p)\` | Creates a Market Swap or Limit Swap order |
| \`cancelOrders(orderKeys: string\[\])\` | Cancels one or more orders by their on-chain keys |
## Configuration Options
Pass a \`GmxSdkConfig\` object to the \`GmxSdk\` constructor. The full interface is:
\`\`\`typescript
interface GmxSdkConfig {
// Required
chainId: number; // 42161 (Arbitrum), 43114 (Avalanche), 3637 (Botanix), 43113 (Avalanche Fuji), or 421614 (Arbitrum Sepolia)
rpcUrl: string; // RPC endpoint for the chain
oracleUrl: string; // GMX oracle keeper URL
subsquidUrl: string; // GMX Subsquid GraphQL URL
// Optional — connection
account?: string; // Wallet address; can also be set via sdk.setAccount()
publicClient?: PublicClient; // Custom viem PublicClient; auto-created from rpcUrl if omitted
walletClient?: WalletClient; // Viem WalletClient; required for write operations
// Optional — overrides
tokens?: Record>; // Override token metadata by address
markets?: Record>; // Override market config by address
// Optional — fees
settings?: {
uiFeeReceiverAccount?: string; // Address that receives UI fees on orders you submit
};
}
\`\`\`
### Network URLs
Use the following endpoints for each production network:
| Network | Oracle URL | Chain ID |
| --------- | ------------------------------------------------------- | -------- |
| Arbitrum | | 42161 |
| Avalanche | | 43114 |
| Botanix | | 3637 |
For Subsquid GraphQL endpoints per network, see \[GraphQL\](../../api/graphql.mdx). The Arbitrum endpoint is \`https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql\`.
The table above lists production endpoints. Alpha-5 also accepts Arbitrum Sepolia (\`421614\`) and Avalanche Fuji (\`43113\`) in \`chainId\` where you provide matching RPC, oracle, and Subsquid endpoints for those environments.
For the underlying contract ABIs and parameters the SDK wraps, see \[Contracts\](/docs/category/contracts).
:::tip
The SDK source exports \`getOracleKeeperUrl(chainId)\` from \`@gmx-io/sdk/configs/oracleKeeper\` if you want to look up the URL programmatically.
:::
### Setting up custom viem clients
By default, the SDK creates its own viem \`PublicClient\` from \`rpcUrl\`. If you create your own client, include the batching configuration to optimize multicall performance:
:::warning
If you inject a custom viem \`publicClient\` without \`BATCH\_CONFIGS\`, large GMX multicalls may be split into many smaller requests. The SDK's batch config sets the client-side multicall calldata limit to \`1024 \* 1024\` bytes; omitting it can cause unexpected request fan-out, rate limits, or browser-side transport failures on public RPC endpoints.
:::
\`\`\`typescript
const publicClient = createPublicClient({
chain: arbitrum,
transport: http("https://arb1.arbitrum.io/rpc", {
batch: BATCH\_CONFIGS\[42161\].http,
}),
batch: BATCH\_CONFIGS\[42161\].client,
});
const sdk = new GmxSdk({
chainId: 42161,
rpcUrl: "https://arb1.arbitrum.io/rpc",
oracleUrl: "https://arbitrum-api.gmxinfra.io",
subsquidUrl: "https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql",
publicClient,
});
\`\`\`
If you supply your own transport as well, carry over both parts of the batch config:
- \`BATCH\_CONFIGS\[chainId\].http\` for the viem HTTP transport
- \`BATCH\_CONFIGS\[chainId\].client\` for client-side multicall batching
### Customizing token data
To override default token properties, pass a \`tokens\` map keyed by token address:
\`\`\`typescript
const sdk = new GmxSdk({
chainId: 42161,
rpcUrl: "https://arb1.arbitrum.io/rpc",
oracleUrl: "https://arbitrum-api.gmxinfra.io",
subsquidUrl: "https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql",
tokens: {
"0x912CE59144191C1204E64559FE8253a0e49E6548": {
name: "My Custom Name for ARB",
},
},
});
\`\`\`
The \`name\` field for this token address uses your custom value throughout the SDK.
### Customizing market availability
To hide specific markets from the SDK, set \`isListed: false\` in the \`markets\` override map:
\`\`\`typescript
const sdk = new GmxSdk({
chainId: 42161,
rpcUrl: "https://arb1.arbitrum.io/rpc",
oracleUrl: "https://arbitrum-api.gmxinfra.io",
subsquidUrl: "https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql",
markets: {
"0x47c031236e19d024b42f8AE6780E44A573170703": {
isListed: false,
},
},
});
\`\`\`
## Usage Examples
These examples show the most common integration workflows. All examples assume you've initialized \`sdk\` and called \`sdk.setAccount()\` as shown in \[Initialization\](#initialization).
### Quick order helpers
For most use cases, use the quick helper methods. They automatically calculate swap paths, amounts, and execution fees from the current market state. You can optionally pass \`marketsInfoData\` and \`tokensData\` yourself to reduce API calls if you've already fetched them.
\*\*Open a long position on ETH/USD (WETH-USDC) using WETH as collateral:\*\*
\`\`\`typescript
await sdk.orders.long({
payAmount: 100031302n, // Raw pay-token amount in the token's native decimals
marketAddress: "0x70d95587d40A2caf56bd97485aB3Eec10Bee6336", // ETH/USD \[WETH-USDC\]
payTokenAddress: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", // WETH
collateralTokenAddress: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC
allowedSlippageBps: 125, // 1.25% slippage tolerance
leverage: 50000n, // 5x leverage (basis points, 10000 = 1x)
});
\`\`\`
\*\*Swap ARB to LINK:\*\*
\`\`\`typescript
await sdk.orders.swap({
fromAmount: 1000n,
fromTokenAddress: "0x912CE59144191C1204E64559FE8253a0e49E6548", // ARB
toTokenAddress: "0xf97f4df75117a78c1A5a0DBb814Af92458539FB4", // LINK
allowedSlippageBps: 125,
});
\`\`\`
:::tip
Pass \`payAmount\` to specify your input amount. Pass \`sizeAmount\` instead to target a specific position size. The helper calculates the other value automatically.
:::
#### Synthetic token addresses
The \`payTokenAddress\` is the token you're depositing. The \`collateralTokenAddress\` is the token held as margin. Some markets use synthetic index tokens — for example, the BTC/USD \[WBTC-USDC\] market's index token is a synthetic BTC, so you pass the WBTC address (\`0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f\`) as \`collateralTokenAddress\`, not the synthetic address.
### Full order method
Use \`createIncreaseOrder\` when you need precise control over order amounts, for example in automated strategies where you compute \`increaseAmounts\` yourself using \`getIncreasePositionAmounts\` from \`@gmx-io/sdk/utils/trade\`.
\`\`\`typescript
const { marketsInfoData, tokensData } = await sdk.markets.getMarketsInfo();
if (!marketsInfoData || !tokensData) {
throw new Error("Failed to fetch market data");
}
// ETH/USD \[WETH-USDC\] on Arbitrum
const marketInfo = marketsInfoData\["0x70d95587d40A2caf56bd97485aB3Eec10Bee6336"\];
// USDC as collateral
const collateralToken = tokensData\["0xaf88d065e77c8cC2239327C5EDb3A432268e5831"\];
// Compute increaseAmounts with getIncreasePositionAmounts().
// That helper needs the full IncreasePositionParams input shown in:
// /docs/sdk/v1/exports/utils/trade/increase
const increaseAmounts: IncreasePositionAmounts = /\* precomputed \*/;
await sdk.orders.createIncreaseOrder({
marketsInfoData,
tokensData,
isLimit: false,
isLong: true,
marketAddress: marketInfo.marketTokenAddress,
allowedSlippage: 50,
collateralToken,
collateralTokenAddress: collateralToken.address,
receiveTokenAddress: collateralToken.address,
fromToken: collateralToken,
marketInfo,
indexToken: marketInfo.indexToken,
increaseAmounts,
});
\`\`\`
:::note
The \`increaseAmounts\` object has a complex structure including \`swapStrategy\`, price impact data, and fee components. Use \`getIncreasePositionAmounts\` from \`@gmx-io/sdk/utils/trade\` to compute it rather than constructing it manually. The complete low-level input shape is documented in \[trade/increase\](./exports/utils/trade/increase.md).
:::
## Operational notes
Keep these behaviors in mind when you integrate SDK v1 into a production app:
- Write methods return a transaction hash after submission. They do not wait for keeper execution or refetch the resulting order state for you.
- The default viem HTTP clients created by \`GmxSdk\` disable transport retries. Add your own retry and backoff policy around safe read paths.
- The SDK does not provide idempotency keys or client order IDs. Prevent duplicate submits in your UI while a transaction is pending.
- Market increases and market swaps simulate before submit by default. Some non-market flows skip simulation in the current implementation. See the \[Integration guide\](./integration-guide.md#simulation-behavior) for the exact behavior.
### Next steps
- Start with the \[Integration guide\](./integration-guide.md) for scenario-based walkthroughs
- See \[SDK Examples\](./examples.md) for more complete integration patterns
- See \[Exports\](./exports/exports.md) for utility functions available in the SDK
---
## Security
This page covers general safety practices, audit reports, and the bug bounty program.
## General safety
Exercise caution when interacting with any smart contract or blockchain application. Although the GMX team mitigates risk through rigorous testing, independent audits, and an active bug bounty program, smart contract code can contain vulnerabilities that remain undetected even after review.
Keep the following points in mind:
- \[Phishing\](https://en.wikipedia.org/wiki/Phishing) attacks and scams are prevalent in both traditional and blockchain contexts.
- Blockchain-specific phishing techniques include tricking users into revealing private keys or seed phrases, or into signing malicious transactions.
- Consider maintaining two separate wallets — one to store the majority of your holdings (a "cold" wallet with minimal dApp exposure), and a separate wallet for interacting with new or unfamiliar websites.
- Before signing any transaction, verify the target contract address and review the operation being signed. Most wallets display the operation name and contract details to assist with this.
- Only interact with the official GMX interface and verified contract addresses listed in the \[contracts\](./api/contracts/overview.md) page.
## Audits
Audit reports for GMX V2 contracts are available in the \[gmx-synthetics repository\](https://github.com/gmx-io/gmx-synthetics/tree/updates/audits). The following firms have conducted audits:
- \*\*Guardian\*\* — Primary auditor for GMX. Conducted 8 engagements between October 2022 and September 2023, totalling 88 person-weeks and resulting in the remediation or acknowledgement of 365 findings across the full severity range. Guardian continues to audit all smart contract updates, with additional engagements through 2024, 2025, and 2026 covering GLV, buybacks, pro tiers, gasless calls, cross-chain V2.2, fee automations, and subsequent protocol changes.
- \*\*ABDK\*\* — Audited the GMX Synthetics contracts at a specific commit.
- \*\*Certora\*\* — Audited GMX Synthetics (November 2023).
- \*\*Dedaub\*\* — Audited GMX Synthetics.
- \*\*Sherlock\*\* — Audited GMX Synthetics updates.
## Bug bounty
GMX maintains an active bug bounty program covering all repositories under \[github.com/gmx-io\](https://github.com/gmx-io). Full program details, scope, and reward tiers are available on the \[GMX Immunefi\](https://immunefi.com/bounty/gmx/) page.
---
## GMX token
GMX is the platform's utility and governance token. Staking GMX earns you a share of protocol fees — 27% of fees from leverage trading, liquidations, borrowing fees, and swaps are used to buy back GMX. Distribution of bought-back GMX is currently suspended; see \[Staking\](#staking) for details. For more on fee distribution, see \[Fees\](../trading/fees.md). GMX also grants \[voting power\](../governance/voting-power.md) in protocol governance.
Escrowed GMX (esGMX) has historically been distributed as a staking and referral incentive. Learn more about esGMX on the \[Rewards\](./rewards.md) page.
## Token addresses
- Arbitrum: \[0xfc5A1A6EB076a2C7aD06eD22C90d7E710E35ad0a\](https://arbiscan.io/token/0xfc5A1A6EB076a2C7aD06eD22C90d7E710E35ad0a)
- Avalanche: \[0x62edc0692BD897D2295872a9FFCac5425011c661\](https://snowtrace.io/address/0x62edc0692BD897D2295872a9FFCac5425011c661)
- Solana: \[9wX6Qz1Y5YQe71dfnFYFfZYXZhKqjYKQwdqfrRkmYUSX\](https://solscan.io/token/9wX6Qz1Y5YQe71dfnFYFfZYXZhKqjYKQwdqfrRkmYUSX)
GMX can be bridged between Arbitrum and Avalanche using \[Stargate\](https://stargate.finance/bridge?srcChain=arbitrum&srcToken=0xfc5A1A6EB076a2C7aD06eD22C90d7E710E35ad0a&dstChain=avalanche&dstToken=0x62edc0692BD897D2295872a9FFCac5425011c661). For bridging between other chains, you can use \[Jumper Exchange\](https://jumper.exchange/).
## Buying GMX
You can buy GMX on the \[Buy\](https://app.gmx.io/#/buy) page.
## Staking
Staking GMX earns you a share of protocol fee buybacks. 27% of protocol fees are used to buy back GMX on the open market through a mechanism approved by the DAO \[Tally vote\](https://www.tally.xyz/gov/gmx/proposal/81921330482579592877925554009800798217173652653143694483196169672340561914053).
:::note
GMX staking rewards are suspended. Bought-back GMX accumulates in the Treasury and will be distributed to stakers when GMX reaches $90. Your share is based on \[staking power\](./rewards.md#staking-power), which accrues continuously based on the amount staked and the duration of staking.
:::
You can stake GMX on the \[Earn\](https://app.gmx.io/#/earn) page. For programmatic access to staking power data, use the \[\`fetchStakingPower()\`\](../sdk/v2/readme.md#methods) method in SDK v2 or the \`/staking/power\` REST endpoint.
### Staked GMX token addresses
After staking GMX, you receive a Staked GMX token. The balance of this token reflects your total staked amount, including any esGMX tokens.
- Arbitrum: \[0xd2D1162512F927a7e282Ef43a362659E4F2a728F\](https://arbiscan.io/token/0xd2D1162512F927a7e282Ef43a362659E4F2a728F)
- Avalanche: \[0x4d268a7d4C16ceB5a606c173Bd974984343fea13\](https://snowtrace.io/address/0x4d268a7d4C16ceB5a606c173Bd974984343fea13)
## Treasury
The GMX treasury is funded by:
- Fees from the GMX/ETH protocol-owned liquidity
- 8.8% of V2 fees (10% is allocated to Chainlink, the treasury, and keeper costs, of which 1.2% goes to Chainlink)
The treasury is held in multiple contracts:
- DAO Treasury: \[0x4bd1cdAab4254fC43ef6424653cA2375b4C94C0E\](https://www.tally.xyz/gov/gmx/treasury)
- POL Multisig: \[0xc6378ddf536410c14666dc59bc92b5ebc0f2f79e\](https://debank.com/profile/0xc6378ddf536410c14666dc59bc92b5ebc0f2f79e)
- Governance Committee: \[0x0263ad94023a5Df6d64f54BFEF089F1FBF8A4CA0\](https://debank.com/profile/0x0263ad94023a5Df6d64f54BFEF089F1FBF8A4CA0)
- Bond Protocol: \[0xea8a734db4c7EA50C32B5db8a0Cb811707e8ACE3\](https://debank.com/profile/0xea8a734db4c7EA50C32B5db8a0Cb811707e8ACE3)
- GM Holdings: \[0xe1f7c5209938780625e354dc546e28397f6ce174\](https://debank.com/profile/0xe1f7c5209938780625e354dc546e28397f6ce174)
- \[0x68863dDE14303BcED249cA8ec6AF85d4694dea6A\](https://debank.com/profile/0x68863dDE14303BcED249cA8ec6AF85d4694dea6A)
- \[0x0339740d92fb8BAf73bAB0E9eb9494bc0Df1CaFD\](https://debank.com/profile/0x0339740d92fb8BAf73bAB0E9eb9494bc0Df1CaFD)
- \[0x2c247a44928d66041d9f7b11a69d7a84d25207ba\](https://debank.com/profile/0x2c247a44928d66041d9f7b11a69d7a84d25207ba)
The GMX DAO owns protocol-owned liquidity in the form of Uniswap V3 NFT LP tokens:
- \[0x4bd1cdAab4254fC43ef6424653cA2375b4C94C0E\](https://arbiscan.io/token/0xc36442b4a4522e871399cd717abdd847ab11fe88?a=0x4bd1cdAab4254fC43ef6424653cA2375b4C94C0E#inventory)
If required, the treasury may be used to pay for issues submitted through the \[bug bounty\](../security.md#bug-bounty).
## Token supply
The supply of GMX can be viewed on the \[Dashboard\](https://app.gmx.io/#/dashboard). The increase in circulating supply varies depending on the number of tokens that are vested.
The forecasted max supply is 13.25 million GMX tokens. Minting beyond this cap requires a governance vote approved by GMX token holders.
### Supply allocation
- 6 million GMX: \[XVIX\](https://xvix.finance/) and \[Gambit\](https://gambit.financial/) migration. GMX was formed by a merger of the XVIX and Gambit communities.
- 2 million GMX: Paired with ETH for liquidity on \[Uniswap\](https://app.uniswap.org/#/swap?inputCurrency=ETH&outputCurrency=0xfc5A1A6EB076a2C7aD06eD22C90d7E710E35ad0a).
- 2 million GMX: Reserved for vesting of \[escrowed GMX\](./rewards.md#escrowed-gmx) tokens.
- 2 million GMX: For the treasury.
- 1 million GMX: For integration incentives and community developers.
- 250,000 GMX: Distributed to contributors linearly over 2 years.
Circulating supply calculation
The supply displayed on the dashboard is the \[total minted GMX tokens\](https://arbiscan.io/token/0xfc5A1A6EB076a2C7aD06eD22C90d7E710E35ad0a) minus the tokens held in \[vesting\](./rewards.md#escrowed-gmx), bonding, and treasury contracts:
- GMX Bonds (Arbitrum): \[0xea8a734db4c7EA50C32B5db8a0Cb811707e8ACE3\](https://arbiscan.io/address/0xea8a734db4c7EA50C32B5db8a0Cb811707e8ACE3)
- GMX Vester (Arbitrum): \[0x199070DDfd1CFb69173aa2F7e20906F26B363004\](https://arbiscan.io/address/0x199070DDfd1CFb69173aa2F7e20906F26B363004)
- GLP Vester (Arbitrum): \[0xA75287d2f8b217273E7FCD7E86eF07D33972042E\](https://arbiscan.io/address/0xA75287d2f8b217273E7FCD7E86eF07D33972042E)
- Affiliate Vester (Arbitrum): \[0x7c100c0F55A15221A4c1C5a25Db8C98A81df49B2\](https://arbiscan.io/address/0x7c100c0F55A15221A4c1C5a25Db8C98A81df49B2)
- Treasury (Arbitrum): \[0x68863dDE14303BcED249cA8ec6AF85d4694dea6A\](https://arbiscan.io/address/0x68863dDE14303BcED249cA8ec6AF85d4694dea6A)
- GMX Vester (Avalanche): \[0x472361d3cA5F49c8E633FB50385BfaD1e018b445\](https://snowtrace.io/address/0x472361d3cA5F49c8E633FB50385BfaD1e018b445)
- GLP Vester (Avalanche): \[0x62331A7Bd1dfB3A7642B7db50B5509E57CA3154A\](https://snowtrace.io/address/0x62331A7Bd1dfB3A7642B7db50B5509E57CA3154A)
- Affiliate Vester (Avalanche): \[0x754eC029EF9926184b4CFDeA7756FbBAE7f326f7\](https://snowtrace.io/address/0x754eC029EF9926184b4CFDeA7756FbBAE7f326f7)
## Ethereum bridging
GMX tokens can be bridged between Ethereum and Arbitrum using the Arbitrum bridge. Bridging from Arbitrum to Ethereum has a 7-day waiting period during which you don't have access to your tokens. All GMX features are on Arbitrum, so there is rarely a reason to bridge to Ethereum.
For step-by-step instructions, see \[this bridging guide\](https://gist.github.com/xvi10/6125b5fbd73f12a2bfce9b729a52255a).
## Next steps
- \[Rewards\](./rewards.md) — Learn about esGMX, vesting, and managing rewards.
- \[Voting power\](../governance/voting-power.md) — Participate in protocol governance.
- \[Fees\](../trading/fees.md) — Understand how trading fees are generated and distributed.
- \[Earn page\](https://app.gmx.io/#/earn) — Start staking GMX.
---
## Rewards
Staking GMX earns you a share of protocol fees. 27% of fees from leverage trading, liquidations, borrowing fees, and swaps are used to buy back GMX on the open market — a mechanism approved by the DAO \[Tally vote\](https://www.tally.xyz/gov/gmx/proposal/81921330482579592877925554009800798217173652653143694483196169672340561914053). Staking also grants \[voting power\](../governance/voting-power.md) in protocol governance. You can stake and manage rewards on the \[Earn\](https://app.gmx.io/#/earn) page. For more on the GMX token, see \[GMX token\](./gmx-token.md).
:::note
GMX staking rewards are accumulating in the Treasury. Bought-back GMX will be distributed to stakers when GMX reaches $90. Your share of accumulated rewards is based on \[staking power\](#staking-power). The APR display on the Earn page shows "Accumulating" while distribution is suspended.
:::
## Staking Power
Staking power determines each staker's share of accumulated Treasury rewards. It accrues continuously based on the amount staked and the duration of staking. You can query staking power data programmatically through the \[REST API\](../api/overview.md) (\`GET /staking/power\`) or \[GraphQL\](../api/graphql.mdx).
### How Power Accrues
The system computes staking power as a continuous time-weighted integral of your staked balance (both GMX and esGMX in the StakedGmxTracker). Power accrues every second rather than through periodic snapshots.
On each stake or unstake event, the system updates your accumulated power:
\`\`\`
accumulatedPower += currentBalance × (eventTimestamp − lastUpdateTimestamp)
\`\`\`
A user who stakes 1,000 GMX for 90 days without changes accumulates power equal to \`1,000 × 90 days\` of staking. Your share of Treasury rewards equals your cumulative power divided by the total network power across all stakers.
Power accrual began on March 4, 2026, when the last bought-back GMX reward distribution ended.
### Loyalty Threshold
A loyalty system protects against large unstaking events. Loyalty tracking started on March 25, 2026, at which point the system began tracking each address's peak staked balance. If the staked balance drops below 80% of this peak, all accumulated power resets to zero. The address's historical peak is then reset to its new staked balance, and power begins accruing again from zero from that point.
Key details:
- After a reset, previous accumulation is lost and is not restored. This means the address loses the previously accumulated share of the GMX-at-$90 distribution and starts rebuilding from zero
- Forfeited power is removed from the total network power. Because each staker's share equals their own power divided by the total, reducing the total automatically increases every remaining staker's share proportionally — there is no separate redistribution step
- After a reset, the address's current balance becomes its new historical peak
- Staking additional tokens raises the historical peak and the 80% threshold accordingly
- Unstaking esGMX to deposit it into a vesting vault lowers the tracked staked balance. If that drop puts the address below 80% of its historical peak, accumulated power resets to zero
- Staking power and loyalty tracking are independent per address; accumulated power and historical peak do not carry across wallets
- Vesting completion (esGMX converting to GMX within a single transaction) does not trigger false resets
## Escrowed GMX
Escrowed GMX (esGMX) is a non-transferable token that was historically awarded as an incentive for GMX staking, GLP, referrals, and other programs. Stakers now receive GMX directly through the buyback mechanism rather than esGMX. Existing esGMX can be used in two ways:
- Staked for staking power — each staked esGMX token contributes to \[staking power\](#staking-power) the same way as a staked GMX token
- Vested to become GMX tokens over a period of one year (365 days)
esGMX is not transferrable unless you are doing a \[full account transfer\](https://app.gmx.io/#/begin\_account\_transfer). The amount of GMX or GLP required to vest esGMX is unique per account, and the maximum amount of esGMX that can be vested is capped to the esGMX rewards received by that account.
:::note
GLP is a legacy liquidity token that preceded GM and GLV pools. While GLP is no longer available for new minting, GLP vesting vaults remain active for users with existing esGMX earned through GLP staking.
:::
## Vesting
Escrowed GMX (esGMX) tokens can be converted into GMX tokens through vesting on the \[Earn\](https://app.gmx.io/#/earn) page. There are two separate vesting vaults — one for esGMX earned from GMX staking (GMX Vault) and one for esGMX earned from GLP staking (GLP Vault). Each vault tracks its own balances, reserved tokens, and vesting progress independently. The \[v1 Earn page\](https://v1.app.gmx.io/#/earn) displays both vaults as separate cards, so you can see the breakdown of your esGMX by source.
When vesting is initiated, the average amount of GMX or GLP tokens used to earn the esGMX rewards is reserved. For example, if you staked 1,000 GMX and earned 100 esGMX tokens, then to vest 100 esGMX tokens, 1,000 GMX tokens are reserved. To vest 50 esGMX, 500 GMX tokens are reserved. The actual ratio depends on the average staked amount and rewards earned for your account.
Key details:
- esGMX tokens that have been unstaked and deposited for vesting stop counting toward staking power. Staked GMX or esGMX tokens that are reserved for vesting remain in the staked balance and continue to count toward staking power and the GMX-at-$90 Treasury distribution.
- If you unstake esGMX to start vesting it, those unstaked tokens stop counting toward staking power. If that drop puts the address below 80% of its historical peak staked balance, accumulated power resets to zero.
- After initiating vesting, esGMX tokens are converted into GMX every second and fully vest over 365 days. Vested GMX tokens are claimable at any time.
- If you sell GMX or GLP tokens and want to vest your esGMX rewards later, you need to re-buy the GMX or GLP tokens.
- GMX and esGMX can be used interchangeably for the required reserve amount.
- Depositing into the vesting vault while existing vesting is ongoing is supported.
### Withdrawing from vesting
Tokens reserved for vesting can't be unstaked or sold. To unreserve them, use the "Withdraw" button on the \[Earn\](https://app.gmx.io/#/earn) page. Partial withdrawals are not supported — withdrawing unreserves all tokens and pauses vesting. Any esGMX tokens that had already vested into GMX remain as GMX tokens.
## Next steps
- \[GMX token\](./gmx-token.md) — Token addresses, supply, and staking details.
- \[Voting power\](../governance/voting-power.md) — Participate in protocol governance.
- \[Earn page\](https://app.gmx.io/#/earn) — Stake GMX and manage rewards.
---
## Direct URLs
The GMX frontend supports direct URLs that pre-fill trade parameters, letting you share specific trading configurations or deep-link users into a particular state.
## Trade parameters
Use the \`/trade/:tradeType\` path to open the trade page with pre-selected settings. The trade type is a URL path segment, not a query parameter. All query parameters are removed from the URL after two seconds.
| Parameter | Location | Description | Accepted values |
| ---------------- | --------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------- |
| \`tradeType\` | Path segment | The type of trade | \`long\`, \`short\`, \`swap\` (case-insensitive) |
| \`mode\` | Query parameter | The order mode | \`market\`, \`limit\`, \`stopmarket\`, \`trigger\`, \`twap\` (case-insensitive); \`tpsl\` is an alias for \`trigger\` |
| \`from\` | Query parameter | The token used for payment | Token symbol such as \`eth\`, \`btc\`, \`usdc\` (case-insensitive) |
| \`to\` or \`market\` | Query parameter | The asset to long, short, or swap to | Token symbol such as \`eth\`, \`btc\`, \`uni\` (case-insensitive); \`to\` and \`market\` are interchangeable |
| \`collateral\` | Query parameter | The collateral asset | Token symbol such as \`eth\`, \`usdc\`, \`usdt\` (case-insensitive) |
| \`pool\` | Query parameter | The liquidity pool for the trade | Pool name such as \`weth-usdc\`, \`btc-usdc\` (case-insensitive) |
| \`chainId\` | Query parameter | Triggers a network switch on load | Numeric chain ID such as \`42161\` (Arbitrum) |
:::note
Not all order modes are available for every trade type. \`Stop Market\` is only available for long and short positions. \`TWAP\` is available for long, short, and swap trades. Swaps do not support \`Stop Market\`.
:::
### Examples
- \`https://app.gmx.io/#/trade/long?mode=limit&from=eth&market=sol\`
- \`https://app.gmx.io/#/trade/short?mode=limit&from=eth&to=btc\`
- \`https://app.gmx.io/#/trade/short?mode=market&from=eth&to=btc&collateral=usdc\`
- \`https://app.gmx.io/#/trade/short?mode=market&from=eth&to=sol&collateral=usdc&pool=sol-usdc\`
## GM pools parameters
Use the \`/pools/details\` path to open a specific GM pool with a pre-selected operation and mode. The \`market\` parameter must be the pool's contract address, not a token symbol.
| Parameter | Description | Accepted values |
| ----------- | ----------------------------------- | ------------------------------------------------- |
| \`market\` | The GM or GLV pool to open | Contract address (hex) of the market or GLV token |
| \`operation\` | The deposit or withdrawal direction | \`Deposit\`, \`Withdrawal\`, \`Shift\` (case-sensitive) |
| \`mode\` | The deposit or withdrawal mode | \`Single\`, \`Pair\` (case-sensitive) |
:::warning
The \`operation\` and \`mode\` values are case-sensitive. \`Deposit\`, \`Withdrawal\`, \`Shift\`, \`Single\`, and \`Pair\` must be capitalized exactly as shown. Values in any other case are ignored and the page opens with its default state.
:::
### Examples
- \`https://app.gmx.io/#/pools/details?market=0x450bb6774Dd8a756274E0ab4107953259d2ac541&operation=Deposit&mode=Single\`
- \`https://app.gmx.io/#/pools/details?market=0x450bb6774Dd8a756274E0ab4107953259d2ac541&operation=Withdrawal&mode=Pair\`
- \`https://app.gmx.io/#/pools/details?market=0x450bb6774Dd8a756274E0ab4107953259d2ac541&operation=Deposit&mode=Pair\`
---
## Fees(Trading)
This page covers all fees on GMX, including trading fees, swap fees, price impact, funding, borrowing, and network fees.
## Open / close fees
The position fee is 0.04% or 0.06% of the position size. It applies when opening, closing, increasing, or partially decreasing a position.
The rate depends on whether your trade improves the balance between long and short open interest:
- 0.04% — your trade reduces the absolute difference between long and short open interest
- 0.06% — your trade increases the absolute difference between long and short open interest
For example, if there is more long open interest than short open interest, opening a short position reduces the imbalance and qualifies for the 0.04% fee. Opening another long position increases the imbalance and incurs the 0.06% fee.
All markets currently use these same rates — there are no per-market overrides.
## Swap fees
Swap fees on GMX vary by market type — standard or stablecoin — and whether your swap improves or worsens the pool's balance. All fees are calculated on the swap input amount.
### Standard swap fees
For a standard swap, the fee is either 0.05% or 0.07% of the swap amount:
- \*\*0.05%\*\* — if the swap decreases the USD imbalance between the long and short token pools (balance improved)
- \*\*0.07%\*\* — if the swap increases that imbalance (balance not improved)
The pool balance check compares the absolute USD difference between the long and short token pool values before and after your swap. If the post-swap difference is smaller, the lower fee applies.
### Stablecoin swap fees
Stablecoin swap markets use significantly lower fees than standard markets. Rates differ by chain:
| Chain | Fee (balance improved) | Fee (balance not improved) |
| ------------------------------------------------------------- | ---------------------- | -------------------------- |
| Arbitrum (USDC/USDC.e, USDC/USDT, USDC/DAI) | 0.005% | 0.02% |
| Avalanche (USDC/USDT.e, USDC/USDC.e, USDT/USDT.e, USDC/DAI.e) | 0.01% | 0.01% |
### Atomic swap fees
Atomic swaps use a separate fee of 3.75% on standard markets. An atomic swap executes in a single transaction and uses a separate fee factor.
:::tip
Single-token pools (where both the long and short token are the same) have no swap fees on any position operation, because collateral, PnL, and pool backing all use the same token — no token conversion is needed. The BTC/USD \[WBTC.e-WBTC.e\] and ETH/USD \[WETH-WETH\] pools also have position impact factors set to zero, meaning no price impact of any kind on these markets. For a full comparison, see \[Single-token vs multi-token pools\](../providing-liquidity.md#single-token-vs-multi-token-pools).
:::
## Slippage
Slippage is the difference between the expected execution price when you submit an order and the actual price when the order executes, caused by price movement during the brief window while the order is processing. The default allowed slippage is 1% and can be adjusted in settings or directly in the trade box. Slippage applies to market orders only — limit and trigger orders use a fixed acceptable price you set at order creation.
When you submit a market order, the interface computes an \`acceptablePrice\` by applying your slippage setting to the mark price. At execution, the contract checks whether the actual execution price satisfies that \`acceptablePrice\`, and reverts if it doesn't.
For example, consider a Market Increase on ETH/USD:
- Expected execution price: $4,000 (long position).
- Actual price at execution: $4,080 (2% higher) due to volatility.
- Since the price moved against you (higher entry for a long), this is unfavorable slippage.
- The order won't execute unless your allowed slippage was set to 2% or higher.
You can set slippage up to a maximum of 5%. The interface shows a warning when slippage exceeds 2%.
Slippage is separate from price impact. Price impact is an additional positive or negative adjustment based on open interest imbalances, applied independently of slippage. See \[Price impact and price impact rebates\](#price-impact-and-price-impact-rebates) for details.
:::note\[Slippage on GMX vs. other platforms\]
On most trading venues — AMMs, DEX aggregators, and some centralized exchanges — "slippage" refers to the total difference between the quoted price and the execution price, which includes the effect of your trade on market liquidity (what GMX calls price impact).
On GMX, these are two distinct mechanisms:
- \*\*Slippage\*\* protects only against oracle price movement between the time you submit an order and when a keeper executes it.
- \*\*Price impact\*\* is a separate adjustment based on pool imbalance, calculated and applied independently at execution time.
The expected output shown in the interface already accounts for estimated fees and price impact. Your slippage setting adds an additional buffer on top of that estimate to cover oracle price movement during the execution window. This means setting 1% slippage on GMX is not equivalent to setting 1% slippage on a DEX aggregator — on a DEX aggregator, that 1% must cover both price impact and price movement, while on GMX it only needs to cover price movement.
:::
## Price impact and price impact rebates
On GMX, opening a position incurs no price impact at entry. The entry price is determined by the oracle price (\`maxPrice\` for longs, \`minPrice\` for shorts). See \[Pricing on GMX\](./order-types.md#pricing-on-gmx) for details. Price impact is calculated based on the net open interest imbalance caused by both opens and closes, but it is only applied (charged or credited) when you close or decrease a position — hence the name "net price impact."
Net price impact can be positive or negative, up to a market-specific cap. Unlike orderbook models, GMX caps price impact, so you don't have to worry about orderbook depth. Also unlike orderbooks, a positive price impact means you can be paid rather than penalized.
### Price impact formula
Price impact is calculated from the change in pool imbalance caused by a trade:
\`\`\`
priceImpact = (initialImbalance ^ exponent × factor) − (finalImbalance ^ exponent × factor)
\`\`\`
Where:
- \*\*initialImbalance\*\* — the absolute difference between long and short values before the trade
- \*\*finalImbalance\*\* — the absolute difference after the trade
- \*\*factor\*\* and \*\*exponent\*\* — per-market configuration parameters (separate values for positive and negative impact paths)
For \*\*positions\*\*, the imbalance is the difference between long and short open interest. For \*\*swaps\*\*, the imbalance is the difference between the USD values of the long and short token pools.
When a trade reduces the imbalance (final < initial), the result is positive — the trader receives a better price. When it increases the imbalance, the result is negative — the trader receives a worse price. If a trade crosses the balance point (the larger side becomes the smaller side), the calculation splits: the portion toward balance uses the positive factor and the portion past balance uses the negative factor.
For position operations, price impact adjusts the entry or exit price rather than deducting from collateral, which preserves the intended leverage ratio. The protocol also maintains a virtual inventory that tracks impact across correlated markets to prevent users from reducing their net impact by opening opposing positions in different markets.
For the SDK implementation of this formula, see \[\`getPriceImpactUsd\`\](../sdk/v1/exports/utils/fees/priceImpact.md#getpriceimpactusd) and related functions in the price impact module.
The prices shown in the trade history — for both opens and closes — are the mark prices (oracle prices) at which the orders executed. For closing, the net price impact is a separate value not included in the displayed mark price. Instead, price impact adjusts your collateral received independently. For example, if the close price is $1,900 and the net price impact is +$1, the mark price remains $1,900 but you receive an additional $1 in collateral, making your effective value $1,901. Conversely, a -$1 net price impact means $1 is deducted from your collateral received.
You can view net price impact in the net value tooltip on the positions list or close modal. The claimable rebate amount is also included in the net value calculation, so your position's net value reflects any rebate you're owed. For a detailed breakdown, enable \*\*"Break down net price impact"\*\* in the display settings — this shows the price impact stored when you opened the position, the price impact from closing, and how they combine into the net amount.
### Price impact caps by market
Negative and positive price impact have separate caps. The max negative price impact varies per market based on liquidity depth (see table below), while the max positive price impact is 40 bps (0.4%) for most markets. This creates an asymmetry — for example, a market with a 500 bps negative cap still has only a 40 bps positive cap.
Negative price impact caps by market:
- Major markets (BCH, BNB, BTC, ETH, PEPE, SOL): 50 bps (0.5%) cap
- Lower-liquidity markets: 75–1000 bps (0.75%–10%) cap, depending on the market's liquidity depth
For example, if the cap is 50 bps, you never pay more than 50 bps in price impact, regardless of order size. Markets with less liquidity have higher caps to better reflect execution conditions.
| Cap | Markets |
| -------- | -------------------------------------------------------------------------------------------------------------- |
| 50 bps | BCH, BNB, BTC, ETH, PEPE, SOL, XAUT |
| 75 bps | BONK, LTC |
| 100 bps | ASTER, AVAX, CRO, CRV, DOGE, ENA, FLOKI, HYPE, LINK, NEAR, SHIB, TRX, XPL, ZEC |
| 150 bps | 0G, AAVE, ADA, APE, APT, ARB, ATOM, FARTCOIN, INJ, OP, PENGU, PUMP, TON, TRUMP, UNI, WLD, XLM |
| 200 bps | AR, DASH, DYDX, EIGEN, FIL, ICP, ONDO, SUI, VIRTUAL, XMR, XRP |
| 250 bps | DOT, HBAR, IP, KTA, LDO, MOODENG, ORDI, S, SEI, TAO, TIA |
| 300 bps | AERO, AIXBT, ANIME, AVNT, BERA, BOME, CAKE, FET, JUP, KAS, LINEA, OM, PENDLE, POL, SYRUP, WIF, ZORA |
| 400 bps | WLFI |
| 500 bps | ALGO, BRETT, CHZ, CVX, DOLO, GMX, JTO, LIT, MEME, MEW, MNT, MON, OKB, PI, RENDER, SKY, SPX6900, STX, WELL, ZRO |
| 700 bps | SATS |
| 1000 bps | CC, MELANIA, MET, MORPHO, VVV |
You can view the current price impact cap for each market on the \[Monitor\](https://app.gmx.io/#/monitor) page under the Config column.
For large orders (typically $1,000,000 or more with negative price impact exceeding 0.2%), consider using TWAP to reduce price impact by executing in smaller parts over time. For swaps, positive price impact increases the tokens you receive, while negative price impact decreases them.
:::note
Capped negative price impact is factored into liquidation price calculations. Positive price impact is excluded. For details, see \[Price impact in liquidations\](./liquidations.md#price-impact-in-liquidations).
:::
Long and short open interest in markets is typically balanced, leading to minimal net price impact. During high volatility, imbalances can cause higher net price impacts. Price impact rebates help mitigate this. If a decrease order has a negative net price impact exceeding the market's cap, the excess becomes claimable as a rebate after a five-day delay.
:::tip
You can claim rebates in the claims section on the trade page. The delay protects against manipulation, and rebates are reviewed before being granted.
:::
Price impact cap configurations are adjusted per market based on recommendations from Chaos Labs to align with current liquidity conditions.
## Funding fees
Funding fees may be a cost or a credit while a position is open. The funding fee rate is visible on the interface when you open or review a trade. The rate changes over time based on the balance of longs and shorts in the market.
If you receive positive funding fees, you can claim them using the "Claim" button in the "Claimable Funding" box of the \[Trade\](https://app.gmx.io/#/v2) page.
### Adaptive funding
Funding rates gradually adjust over time based on the ratio of long to short open interest. A sudden shift in the OI balance does not immediately reverse the funding direction — the previously larger side may continue to receive funding until the rate adjusts.
Which side pays and at what rate is governed by a signed state variable, \`savedFundingFactorPerSecond\`, that the contract updates on every market transaction. A positive value means longs pay shorts; a negative value means shorts pay longs.
The imbalance ratio used for threshold comparisons and rate adjustments is:
\`\`\`
longShortImbalance = \[abs(longOpenInterest - shortOpenInterest) / totalOpenInterest\] ^ fundingExponentFactor
\`\`\`
The rate adjusts according to three zones defined by this imbalance relative to two thresholds, \`thresholdForStableFunding\` and \`thresholdForDecreaseFunding\`:
- \*\*Above \`thresholdForStableFunding\`:\*\* The imbalance is large. The rate increases by \`longShortImbalance × fundingIncreaseFactorPerSecond\` per second until the imbalance falls or the rate reaches its maximum cap.
- \*\*Between the two thresholds:\*\* The rate remains constant.
- \*\*Below \`thresholdForDecreaseFunding\`:\*\* The imbalance is small. The rate decreases by \`fundingDecreaseFactorPerSecond\` per second toward zero.
If the imbalance reverses direction (for example, longs were dominant and shorts become dominant), the rate immediately starts increasing in the opposite direction, regardless of which threshold zone it was in.
For example, suppose longs exceed shorts and the rate is increasing with longs paying shorts. If shorts are opened or longs are closed so that shorts now exceed longs, the rate begins increasing in the opposite direction — toward shorts paying longs — until a threshold is reached or the maximum cap is hit.
### Accrual and settlement
Funding fees accrue continuously using per-second arithmetic. Each market stores \`savedFundingFactorPerSecond\` (the signed adaptive rate) and a \`fundingUpdatedAt\` timestamp on-chain. The unsigned \`fundingFactorPerSecond\` for the paying side is derived on-demand inside \`getNextFundingAmountPerSize\` and is never stored persistently. The total funding accrued for the paying side over a period is:
\`\`\`
fundingUsd = sizeOfPayingSide × durationInSeconds × fundingFactorPerSecond
\`\`\`
Settlement is event-driven, not scheduled. The on-chain funding state updates whenever a transaction touches the market — executing an order, a deposit, or a withdrawal. Between transactions, funding accrues implicitly via the time elapsed since the last update. When a position is modified or closed, the contract computes the exact funding owed using the elapsed time since that last update.
Per-position settlement uses a checkpoint pattern. Each position stores a \`fundingFeeAmountPerSize\` value recorded at the time the position was last updated. When the position is settled, the contract computes:
\`\`\`
positionFundingFeeAmount = positionSizeInUsd
× (latestFundingAmountPerSize − position.fundingFeeAmountPerSize)
/ PRECISION
\`\`\`
The result is rounded up for the paying side and rounded down for the receiving side.
:::note
The \`fundingFactorPerSecond\` exposed by the interface and API represents the rate for the paying side. The receiving side's effective rate is scaled proportionally by \`payingOI / receivingOI\`, so total funding inflow equals total outflow.
:::
## Borrow fees
A borrow fee applies to open positions to prevent traders from reserving all pool liquidity by opening equal long and short positions at minimal cost. If the side with larger open interest fully reserves the pool, the borrow fee also incentivizes liquidity providers to add more capital to the pool.
Only the side with the larger open interest pays the borrow fee. If longs exceed shorts, longs pay; if shorts exceed longs, shorts pay.
The borrow fee accrues continuously per second and is settled when you modify or close a position. The fee is calculated as:
\`\`\`
borrowingFeeUsd = positionSizeUsd × (cumulativeBorrowingFactor − positionBorrowingFactor)
\`\`\`
where \`cumulativeBorrowingFactor\` increases over time at \`borrowingFactorPerSecond\`, and \`positionBorrowingFactor\` is the snapshot taken when your position was last updated.
The current borrow fee rate is shown on the trade interface as a percentage per hour, applied to your position size. The rate changes over time based on pool utilization.
### Rate models
Most markets use a kink model (two-segment curve). The rate increases linearly up to an optimal utilization threshold, then rises more steeply above it:
\`\`\`
borrowingFactorPerSecond = baseBorrowingFactor × usageFactor
if usageFactor > optimalUsageFactor:
diff = usageFactor − optimalUsageFactor
additional = (aboveOptimalUsageBorrowingFactor − baseBorrowingFactor) × diff / (1 − optimalUsageFactor)
borrowingFactorPerSecond += additional
\`\`\`
A typical configuration is:
- Optimal utilization: 75%
- Rate at or below 75% utilization: 45–55% per year
- Rate at 100% utilization: 100–130% per year
Some markets use a power (curve) model instead:
\`\`\`
borrowingFactorPerSecond = borrowingFactor × reservedUsd ^ borrowingExponentFactor / poolUsd
\`\`\`
The default base configuration uses a linear exponent of 1, which targets approximately 15.77% per year at 100% utilization.
Of the borrow fee collected, 63% goes to the pool (accruing to liquidity providers) and 37% goes to the protocol fee receiver.
## Network fee
Every trade on GMX involves two transactions: your request and the keeper's execution. The network fee covers the gas cost of the second transaction.
1. You send a transaction to request an action — open, close, deposit collateral, or withdraw collateral.
2. A keeper observes the request on-chain and executes it in a separate transaction.
The gas cost of the keeper's execution transaction is what the interface calls the network fee. Because gas prices can spike between your request and the keeper's execution, the interface charges a max network fee that overestimates the likely cost. When the keeper executes your order, only the gas actually consumed is paid to the keeper — the remainder is refunded to your account automatically.
The interface displays the network fee row after subtracting an estimated refund. The full max network fee amount, along with an estimated refund breakdown, is visible in the tooltip next to the fee row.
:::note
The estimated refund shown in the tooltip is an approximation based on recent data, not a guaranteed amount. The actual refund depends on gas prices at the time of execution.
:::
### Max network fee buffer
The max network fee includes a configurable buffer to guard against gas price spikes. You can adjust this buffer in the \*\*Max network fee buffer\*\* setting, found in the settings panel.
When Express Trading is enabled, an additional 10% buffer is applied on top of your configured buffer to account for the higher gas reliability requirements of Express order execution.
### TP/SL and additional orders
When you place a position with Take-Profit or Stop-Loss orders, the max network fee includes fees for those additional orders. If those orders don't trigger and are canceled, their network fees are refunded in full.
## Arbitraging
GMX's fee and price impact mechanics reward trades that rebalance pools, which creates arbitrage opportunities for both perpetuals and swaps. When a pool is imbalanced, you can profit while helping restore balance.
### Perps
You can arbitrage positive price impact and \[funding fees\](#funding-fees) on perpetual markets.
For example, if ETH long open interest exceeds short open interest, opening a short position reduces the imbalance. The contract calculates price impact based on the change in the absolute difference between long and short open interest before and after your trade. Because the imbalance decreases, you receive a positive price impact — a better entry price than the current mark price. While the position is open, you also earn funding fees, because the dominant (long) side pays the minority (short) side.
If ETH long positions subsequently close such that short open interest exceeds long open interest, closing your short position also reduces the (now reversed) imbalance, and you receive a positive price impact on exit — a better exit price than the mark price.
For markets where the index token is the same as the collateral token (for example, using ETH as collateral in the ETH/USD market), you can open a delta-neutral short position by posting the index token as collateral. This exposes you to funding income without directional ETH price risk. When arbitraging with a long position, opening a 1x long with a stablecoin as collateral gives you 1x exposure to the index token without additional leverage.
:::note
With adaptive funding, the rate decreases toward the market's \`minFundingFactorPerSecond\` floor as open interest becomes balanced — not necessarily to zero. Factor this in when sizing an arbitrage position, as the funding income may be lower by the time open interest equalizes.
:::
Pool balances and funding rates per hour can be viewed on the \[Stats\](https://app.gmx.io/#/stats) page. For programmatic access, the \[\`/markets/info\`\](../api/rest-api/markets.mdx) endpoint provides near-live funding rates (refreshed every 5 seconds), while the \[\`/rates\`\](../api/gmx-api/get-rates.api.mdx) endpoint provides hourly historical snapshots.
### Swaps
You can arbitrage positive price impact on swap markets.
Swap price impact is calculated based on the change in the absolute USD difference between the long token pool value and the short token pool value. If your swap reduces that difference, you receive a positive price impact — additional output tokens beyond the baseline swap amount.
For example, in the ETH/USDC pool, if the USD value of ETH in the pool exceeds the USD value of USDC, swapping USDC for ETH reduces the imbalance and earns a positive price impact. You receive more ETH than the unadjusted swap would provide.
Pool balances can be viewed on the \[Stats\](https://app.gmx.io/#/stats) page.
---
## Liquidations and ADL
This page covers liquidation mechanics, Auto-Deleveraging (ADL), and trading risks.
## Liquidations
A position is liquidated when its remaining collateral, after accounting for unrealized losses, accrued fees, and capped negative price impact, falls below the market's minimum collateral threshold. This threshold ranges from 0.25% to 1% of position size, depending on market configuration. The protocol uses the minimum index price (\`minPrice\`) to calculate PnL for long positions and the maximum index price (\`maxPrice\`) for short positions. Collateral value always uses the minimum collateral token price (\`collateralTokenPrice.min\`), regardless of position side.
:::warning
Your liquidation price is not static. Borrow fees and funding fees accumulate over time, moving it closer. You can deposit additional collateral using the "Edit" button to improve your liquidation price.
:::
:::note
When a position is liquidated, any remaining collateral after deducting losses and fees is returned to your wallet.
:::
### Minimum collateral floor
In addition to the percentage-based threshold, the protocol enforces an absolute minimum collateral amount (\`MIN\_COLLATERAL\_USD\`). The effective liquidation threshold is whichever value is greater: the market's percentage of position size or this absolute floor.
For larger positions, the percentage-based threshold exceeds the floor and the floor has no effect. For small positions, the floor can dominate — reserving most of the collateral as the required minimum and leaving very little buffer before liquidation triggers.
For example, with a $1.00 floor and a 0.5% minimum collateral factor, two 1x short positions behave very differently:
| Position size | Collateral (1x) | Factor threshold | Effective threshold | Usable buffer | Liquidation distance |
|---|---|---|---|---|---|
| $1,000 | $1,000 | $5.00 | $5.00 (factor) | $995 | ~100% from entry |
| $1.15 | $1.15 | ~$0.006 | $1.00 (floor) | $0.15 | ~12% from entry |
The $1.15 position must maintain at least $1.00 in remaining collateral, leaving only $0.15 as buffer against price movement and accumulated fees. This is why small positions can have liquidation prices much closer to entry than their leverage alone would suggest.
### Liquidation fees
The liquidation fee is a percentage of the position's notional size (not the collateral). The applicable rate depends on the market type:
| Market type | Liquidation fee |
| --------------------------------------- | ---------------------- |
| Standard (non-synthetic) | 0.20% of position size |
| Single-token (BTC/BTC, ETH/ETH) | 0.30% of position size |
| Synthetic (SOL, ARB, LINK, and similar) | 0.30% of position size |
| High-volatility (newly listed markets) | 0.45% of position size |
The liquidation fee is not factored into the protocol's liquidatability check — it is deducted only when the position is actually closed.
### Price impact in liquidations
Negative price impact is included in the liquidation check, capped by the \`MAX\_POSITION\_IMPACT\_FACTOR\_FOR\_LIQUIDATIONS\` parameter. Positive price impact is zeroed out for the purpose of the liquidation check. The same capped negative price impact is used in the frontend's liquidation price calculation.
### Stop-Loss orders and liquidations
When a position becomes liquidatable, keepers attempt to execute any associated Stop-Loss orders before proceeding with liquidation. If a Stop-Loss order successfully closes the position, the liquidation is skipped. When multiple Stop-Loss orders exist, they are processed in descending order by size — the largest is attempted first.
Stop-Loss execution before liquidation can fail when:
- The trigger price condition is not satisfied at the current oracle prices
- Valid signed prices are unavailable for the order's tokens
- The order fails on-chain validation (for example, insufficient liquidity or max leverage exceeded)
- The execution transaction reverts
If all associated Stop-Loss orders fail to close the position, the keeper proceeds with liquidation. Any remaining orders on the position that were created with auto-cancel enabled are then auto-cancelled (see \[auto-cancel TP/SL\](./order-types.md#auto-cancel-tpsl)).
:::warning
Only Stop-Loss orders (\`StopLossDecrease\`) are attempted before liquidation. Take-Profit orders (\`LimitDecrease\`), Limit Increase, and other order types are not. Setting a Stop-Loss above your liquidation price reduces your risk but does not guarantee you avoid liquidation — rapid price movements can cause both the Stop-Loss trigger and the liquidation threshold to be breached in the same oracle update.
Unlike resting limit orders on a centralized exchange, GMX orders don't fill passively as price moves through them. They're executed by keepers against oracle prices. While the liquidation keeper does attempt your Stop-Loss before submitting a liquidation transaction, a separate order-execution keeper runs concurrently — so there's no on-chain guarantee that your Stop-Loss executes before a liquidation check reaches your position.
:::
## Auto-Deleveraging (ADL)
Auto-Deleveraging (ADL) protects pool solvency by automatically reducing profitable positions when the ratio of pending PnL to pool value exceeds the market's configured \`MAX\_PNL\_FACTOR\_FOR\_ADL\` threshold. When this threshold is exceeded, profitable positions may be partially or fully closed to bring the ratio back within bounds.
ADL is most likely to occur in \[synthetic markets\](../providing-liquidity.md#synthetic-markets), where the index token differs from the pool's long collateral token. In these markets, the index token's price can rise faster than the collateral token's price, causing pending profits to outpace the pool's capacity to pay them. For background on how market types affect pool solvency, see \[Market types\](../providing-liquidity.md#market-types).
:::warning
If ADL is triggered on your position, it's partially or fully closed without your action.
:::
## Trading risks
GMX mitigates risks through testing, audits, and bug bounties, but trading on any smart contract protocol carries inherent risks.
:::warning
Use caution when interacting with any smart contract or blockchain application. The list below is non-exhaustive.
- \*\*Smart contract risks:\*\* Vulnerabilities in the protocol code could lead to loss of funds, despite audits and bug bounties.
- \*\*Liquidations:\*\* Positions can be liquidated if collateral falls below the required threshold, resulting in a loss of most or all of the position's collateral.
- \*\*ADL:\*\* In synthetic markets, profitable positions may be automatically deleveraged if pending PnL exceeds the market's configured threshold. See \[Auto-Deleveraging (ADL)\](#auto-deleveraging-adl) for details.
- \*\*Stablecoin pricing:\*\* If a stablecoin depegs from 1 USD, the price used to settle your position may differ from the peg value. There may be a spread from the Chainlink price to 1 USD, and if \[Chainlink Data Stream\](https://docs.chain.link/data-streams) prices are used, the spread comes from the bid/ask in the data stream report and may not be anchored to 1 USD.
Additionally, collateral and profits may be backed by bridged or pegged tokens that may not be guaranteed to maintain their peg.
:::
---
## Positions and order types
This page covers how pricing works on GMX, how to open and manage positions, the available order types, and swaps.
## Pricing on GMX
GMX uses oracle-based pricing rather than an orderbook model. Understanding this is important for limit orders, stop-loss orders, and other conditional order types.
### Oracle prices: minPrice and maxPrice
GMX receives price data from \[Chainlink Data Streams\](https://docs.chain.link/data-streams) as a spread with two values derived from the bid and ask in each data stream report:
- minPrice: The lower bound of the price spread (bid)
- maxPrice: The upper bound of the price spread (ask)
The oracle price used for both triggering and execution depends on the operation:
| Operation | Oracle price used | Reasoning |
| ------------------------- | ----------------- | ----------------------------------------------------- |
| Long open | maxPrice | You pay the higher price to enter a long |
| Long close / liquidation | minPrice | You receive the lower price when exiting a long |
| Short open | minPrice | You sell at the lower price to enter a short |
| Short close / liquidation | maxPrice | You buy back at the higher price when exiting a short |
:::info Entry price
Your entry price is the Chainlink oracle price used for your order — \`maxPrice\` for longs, \`minPrice\` for shorts. No price impact is applied at entry; it is \[stored and applied when you close\](./fees.md#price-impact-and-price-impact-rebates). Because the entry price is the market price from Chainlink with no additional adjustments, it is not displayed separately in the interface.
:::
### Mark price
The mark price is the midpoint of the oracle spread: \`(minPrice + maxPrice) / 2\`
The mark price is used for:
- Display in the interface and charts
- Funding rate calculations
- Price impact calculations (deposits, swaps, position sizing)
It is not used for order triggering or execution.
### Trigger price evaluation
This is a key difference from orderbook exchanges. On orderbook platforms, limit and stop orders fill when a counterparty matches at that price level in the orderbook. On GMX, there is no orderbook — trigger prices are evaluated against minPrice or maxPrice depending on the order direction, which is the same price used for execution.
Example: You set a Stop-Loss at $3,900 for your ETH long. The order triggers when minPrice reaches $3,900 (not when the mark price reaches $3,900). Since closing a long uses minPrice, the trigger and execution price are the same oracle price.
The spread between minPrice and maxPrice is typically small (a few basis points) but can widen during volatility.
### Charts
The current price displayed on the chart — the live price line and the price in the chart header — is the mark price: \`(minPrice + maxPrice) / 2\`.
Candlestick charts use:
- Open: previous candle's close (the average price at the end of the prior period)
- Close: average price (minPrice + maxPrice) / 2
- High: highest maxPrice reported by oracles
- Low: lowest minPrice reported by oracles
This means a candle may show your trigger price being reached, but your order may not trigger. For example, if you set a Limit Increase to open a long at $3,900, the chart might show a low of $3,900 (based on minPrice), but your order uses maxPrice — which may have only reached $3,901.
### Price gaps and volatility
During rapid price movements, the oracle price at execution may differ from your trigger price. This applies to all trigger-based orders (Limit Increase, Limit Decrease, Stop Market, TP/SL).
Examples:
- Stop-Loss at $4,000: Oracle price updates from $4,010 → $3,990 (skipping past $4,000). Order triggers and executes at $3,990.
- Take-Profit at $4,100: Oracle price updates from $4,090 → $4,110 (skipping past $4,100). Order triggers and executes at $4,110.
Trigger orders are not guaranteed to execute if the oracle price does not reach the specified trigger price.
## Opening a position
On the \[Trade\](https://app.gmx.io/#/v2) page, select "Long" or "Short," choose an order type (Market, Limit, or via the "More" dropdown: Stop Market or TWAP), and configure your position using the fields described below.
### Pool and collateral
Select the market you want to trade from the market selector at the top left of the trade page. At the top of the trade box, you can configure:
- \*\*Pool\*\* — if multiple pools are available for your market (for example, BTC-USDC and BTC-USDT), choose based on your preferred collateral, net rates, and price impact. Each pool may have different funding/borrowing rates and price impact levels depending on its balance.
- \*\*Collateral\*\* — choose which token your position's collateral is stored as. For example, in the BTC-USDC market, you can choose BTC or USDC.
Collateral choice affects your exposure:
- \*\*Long ETH with ETH collateral:\*\* You gain exposure from both the long position and the collateral itself. For example, a 0.1 ETH long with 1 ETH as collateral gives 1.1 ETH total exposure.
- \*\*Long ETH with USDC collateral:\*\* Exposure comes only from the long position. Useful if switching frequently between longing and shorting.
- \*\*Short ETH with ETH collateral:\*\* Useful for delta neutral strategies to earn funding fees. For example, a 1 ETH short with 1 ETH as collateral.
- \*\*Short ETH with USDC collateral:\*\* Useful if switching frequently between longing and shorting.
:::warning
If you open a long position with non-stablecoin collateral, your liquidation price may change as the collateral's price fluctuates.
:::
### Margin, size, and leverage
The trade box has three interconnected fields:
- \*\*Margin\*\* — the amount of collateral you deposit. You can select the pay token and fill your available balance from this field.
- \*\*Size\*\* — the total position size. You can toggle between USD and token units (for example, BTC). A percentage slider below the size field lets you quickly set the size as a percentage of your maximum available amount.
- \*\*Leverage\*\* — displayed at the top of the trade box. Click on it to open the leverage adjuster, which has a slider with preset marks (0.1x, 1x, 2x, 5x, 10x, 25x, 50x, 100x) and a manual input field.
How these fields interact depends on the \*\*Manual leverage\*\* setting (in Settings):
- \*\*Manual leverage on (default):\*\* You set the leverage and one of the other fields. The third is calculated automatically. For example, setting 10x leverage and 100 USDC margin gives a 1,000 USD position size.
- \*\*Manual leverage off:\*\* You set margin and size freely, and leverage is derived from their ratio.
### Are GMX perps linear or inverse?
GMX V2 uses linear PnL math rather than inverse perp math. In simple terms, GMX calculates profit and loss from your token exposure, while inverse perps are built around a fixed USD contract value and usually pay profit and loss in the underlying token. Internally, GMX keeps both token size and USD position value for pricing and risk calculations, while collateral remains flexible within the market's supported tokens.
For linear perps, price-move PnL equals \`size in tokens × price move\`, which is equivalently the position's USD notional at entry multiplied by the percentage price change. For example, a 10,000 USD ETH position that moves 10% has 1,000 USD of profit or loss before fees and price impact. On GMX, this is true whether your collateral is ETH or USDC.
What changes with collateral is your additional exposure outside the position itself:
- \*\*Stablecoin collateral\*\* feels more linear because the collateral value stays relatively stable while the position PnL moves.
- \*\*Non-stable collateral\*\* can feel more inverse-like because the collateral value can rise or fall with the market too.
Profitable longs use the market's long token and profitable shorts use the market's short token for PnL payments. In the close modal, the token you receive as profit can be changed, but this is done through a swap from that PnL token, so the final output token does not by itself determine whether a position is linear or inverse.
In practice, GMX is best thought of as a \*\*multi-collateral perpetual market with linear, USD-based PnL\*\*, not as an inverse perp venue.
### Take-Profit / Stop-Loss
You can set basic TP/SL orders directly in the trade box before opening a position. Toggle the TP/SL section to configure a trigger price and view estimated PnL for each. These orders fully close your position when triggered. For more advanced TP/SL configurations (partial closes, multiple entries), use the positions list after opening the position.
### Execution details
Before submitting, expand the "Execution details" section at the bottom of the trade box to review: liquidation price, fees, network fee, collateral spread, allowed slippage, stored price impact, leverage, size, and collateral. Adjust the allowed slippage in this section or in Settings if needed.
### Max leverage
The max allowed leverage of a pool decreases as the total open interest of the pool increases. This guards the pool against gaming of price impact using high-leverage positions. This mainly affects markets with less liquidity but can affect high-liquidity markets if the open interest is very large.
The interface shows a warning if the max allowed leverage would be exceeded. This only affects opening or increasing positions — it does not affect positions that have already been opened. For closing or decreasing positions, if the max allowed leverage would be exceeded, the order can still execute, but the collateral within the position would not be reduced.
:::note
When depositing collateral via the edit button, the interface validates against the full max leverage derived from \`minCollateralFactor\`. This is less restrictive than the halved limit (\`max leverage / 2\`) used for opening or increasing positions. A deposit is only blocked when the resulting leverage would exceed the actual market limit — not the halved limit applied to opens.
:::
## Managing positions
After opening a trade, you can view it under your positions list. Each position row displays the market and side, size, net value, collateral, entry price, mark price, liquidation price, and any active TP/SL orders.
You can also interact directly from the position row:
- Click the edit button next to the collateral value to deposit or withdraw collateral, adjusting your leverage and liquidation price.
- Use the "Market" or "TWAP" buttons in the Close column to close the position (see \[Closing a position\](#closing-a-position)).
### Position actions
Click the "..." menu on a position row to access additional actions:
- \*\*Increase size\*\* — add to your position using a Market, Limit, Stop Market, or TWAP order.
- \*\*Set TP/SL\*\* — create, edit, or cancel Take-Profit and Stop-Loss orders. You can set multiple TP/SL orders per position with different trigger prices and sizes.
- \*\*Share position\*\* — generate a shareable image of your position with optional PnL display, and share it via link or on X.
### Net value and collateral tooltips
Hover over the net value to see a breakdown of initial collateral, PnL, borrow fees, funding fees, net price impact, price impact rebates, and close fees. Hover over the collateral to see accrued borrow and funding fees, daily fee rates, and claimable positive funding fees.
## Closing a position
Close a position partially or completely by clicking the "Market" or "TWAP" button in the position row. This opens a dialog where you configure the close amount, receive token, and execution details. Closing realizes pending profits or losses proportional to the percentage of the position that is closed.
### Close amount
Enter the USD amount to close, or use the percentage slider (0–100%) and quick-select buttons (10%, 25%, 50%, 75%) to set a partial or full close.
If the remaining position size would be below 1 USD, the close is treated as a full close instead of leaving a dust position.
### Market vs TWAP close
- \*\*Market\*\* — closes immediately at the current oracle price.
- \*\*TWAP\*\* — splits the close into multiple smaller orders executed over a specified duration. Configure the duration (hours and minutes), number of parts, and review the calculated frequency and size per part. TWAP is recommended for large positions to reduce price impact — the interface suggests switching to TWAP if it detects high net price impact.
### Keep leverage
When partially closing with a Market order, the "Keep leverage" toggle maintains your current leverage ratio by proportionally reducing collateral alongside the size. This is enabled by default and disabled for full closes.
If a partial close would leave the position with collateral below the protocol minimum, the close is blocked. This can happen more easily when "Keep leverage" is enabled, since reducing size also withdraws collateral proportionally.
### Receive token
By default, long positions receive the asset you are longing (for example, ETH) and short positions receive the stablecoin used as collateral (for example, USDC). You can change the receive token in the close dialog — if this requires a swap, the associated swap fees are shown. If the swap fails during execution, the decrease order may output two tokens (one from each side of the pool) instead of a single token.
### Execution details
Before confirming, expand the "Execution details" section to review exit price, trade fees, network fee, allowed slippage, leverage, size, and collateral transitions. The net price impact and fees summary is shown above this section.
### PnL
The PnL from price movement is proportional to your position size. For example, if you open a 10,000 USD long ETH position and the price of ETH increases by 10%, the profit is 1,000 USD. If the price decreases by 10%, the loss is 1,000 USD. This excludes changes in your collateral's value — if your collateral is a non-stablecoin asset, its price movement also affects your net value.
Realized PnL shown in the trade history is labeled "Realized PnL after fees and net price impact." This value includes closing fees, borrowing fees, funding fees, UI fees, and net price impact — but it does not include the opening fee. The opening fee is deducted from the initial margin you pay when opening a position (initial margin − opening fee = initial collateral), so the initial collateral displayed on the interface already accounts for it. Because the opening fee is absorbed into the starting collateral, it is not subtracted again when calculating realized PnL at close.
For example, holding a position for an extended period accumulates borrowing fees, and closing during an imbalanced market may incur negative price impact. Hover over the net value in the positions list for a full breakdown. See \[Fees\](./fees.md) for details on each fee type.
Leverage for a position is displayed as (position size) / (position collateral). You can change this to (position size + PnL) / (position collateral) in "Settings."
## Swaps
GMX supports perpetual trading and swaps. To swap, click the "Swap" tab on the \[Trade\](https://app.gmx.io/#/v2) page.
### Swap order types
Three order types are available for swaps:
- \*\*Market Swap\*\* — executes immediately at the current oracle price, subject to your allowed slippage setting.
- \*\*Limit Swap\*\* — executes when the exchange rate reaches your specified limit price. See \[Limit orders\](#limit-orders) for details on how limit swap execution works.
- \*\*TWAP Swap\*\* — splits the swap into smaller parts executed over a specified duration to reduce price impact. See \[TWAP orders\](#twap-orders) for configuration details.
Wrap and unwrap operations (for example, ETH to WETH on Arbitrum, AVAX to WAVAX on Avalanche) are restricted to Market Swap only.
### Swap configuration
The swap form has two main fields:
- \*\*Pay\*\* — the token and amount you are swapping from. You can fill your available balance from this field.
- \*\*Receive\*\* — the token and amount you receive. For TWAP swaps, this value is approximate since the final amount depends on execution conditions across each part.
Use the swap button between the fields to reverse the token pair. For Limit Swaps, click the current mark price to prefill the limit price field.
### Routing
Swaps are routed through GM pools. The available tokens for swapping are the collateral tokens across all active GM pools on the connected network. This includes long tokens (for example, ETH, BTC), short tokens (for example, USDC, USDT), and native tokens where wrapped versions exist.
### Execution details
Before confirming, expand the "Execution details" section to review:
- \*\*Spread\*\* — the combined bid-ask spread for both tokens (Market Swap only). A warning is displayed if the spread is high.
- \*\*Min. receive\*\* — the minimum output amount after slippage is applied. See \[Min. receive\](#min-receive) for details.
- \*\*Price impact / fees\*\* — the net price impact percentage and total fee percentage. Positive price impact means you receive more tokens than expected. See \[Price impact\](./fees.md#price-impact-and-price-impact-rebates) and \[Swap fees\](./fees.md#swap-fees) for details.
- \*\*Network fee\*\* — the estimated blockchain execution fee. Overestimated amounts are refunded after execution.
### Min. receive
Min. receive is a slippage protection mechanism for swaps. It sets the minimum output amount you accept — if the actual output falls below this value, the swap reverts and you keep your input tokens.
The min. receive value is derived from the expected output and your allowed slippage:
\`\`\`
minReceive = expectedOutput × (1 − allowedSlippage)
\`\`\`
For example, with 1% slippage and an expected output of 1,000 USDC, the min. receive is 990 USDC.
#### Market Swaps vs. Limit Swaps
Min. receive is applied differently depending on the order type:
- \*\*Market Swap\*\* — the interface applies your allowed slippage automatically. It calculates the expected output, reduces it by your slippage tolerance, and sends the reduced value to the contract as \`minOutputAmount\`.
- \*\*Limit Swap\*\* — slippage is not applied. The expected output based on your limit price is sent directly as \`minOutputAmount\`, because the limit price itself provides price protection.
You can configure your slippage tolerance in the swap form's execution details section, which offers preset options of 0.3%, 0.5%, 1%, and 1.5%, or enter a custom value. Slippage can also be set in settings. The default is 1% (100 basis points).
#### What happens when the minimum isn't met
If the actual swap output is less than \`minOutputAmount\`, the contract reverts the transaction. You don't receive partial output — the swap either completes above the minimum or doesn't execute at all.
#### Factors that affect the output amount
The final output amount is determined by three factors:
- \*\*Swap fees\*\* — deducted from the swap amount. Rates depend on whether the swap improves pool balance and on the token types involved. See \[Swap fees\](./fees.md#swap-fees) for rates.
- \*\*Price impact\*\* — based on pool balance changes caused by your swap. Positive price impact increases your output; negative price impact reduces it. See \[Price impact\](./fees.md#price-impact-and-price-impact-rebates).
- \*\*Oracle price movement\*\* — the oracle price may change between when you submit the swap and when a keeper executes it.
The expected output estimate already accounts for fees and price impact at submission time. Oracle price movement during the execution window is the remaining source of divergence — the slippage buffer protects against this.
:::note
On most DEX aggregators and AMMs, "slippage" covers everything that can reduce your output — including the price impact of your trade on liquidity pools. On GMX, slippage and \[price impact\](./fees.md#price-impact-and-price-impact-rebates) are separate: the expected output already factors in price impact and fees, and slippage only covers oracle price movement during execution. Setting 1% slippage on GMX is narrower in scope than 1% slippage on a typical DEX aggregator.
:::
## Limit orders
Limit orders let you specify a price at which to open or increase a position, or to execute a swap. Create a limit order by selecting "Limit" in the trade box, or by selecting "Increase Size (Limit)" from the position menu if you already have an open position.
### Perp limit orders
Limit orders on GMX work differently from orderbook exchanges. There is no orderbook — when the oracle price reaches your trigger price, a keeper picks up and executes the order at that oracle price.
:::warning
Unlike resting limit orders on a centralized exchange, GMX orders don't fill passively as price moves through them. They're executed by keepers against oracle prices — there is no queue priority or passive fill. Fast market moves can cause the oracle price to skip past your trigger price entirely, resulting in execution at a different price or non-execution. See \[Price gaps and volatility\](#price-gaps-and-volatility).
:::
On centralized exchanges, traders sometimes use limit orders to open a position immediately with controlled slippage — setting a limit price that would fill right away but caps the worst acceptable execution price. On GMX, use a Market Increase instead and set an acceptable slippage under the execution details.
### Limit swaps
For Limit Swaps, execution may occur at a price different from your set limit price. The actual execution price is influenced by fees and price impact. For example, with positive price impact, the order might execute before the limit price is reached. With negative price impact, it might execute only after the price moves past your limit.
If the order executes, you receive at least the minimum output amount derived from your limit price and allowed slippage. If this minimum can't be satisfied, the order doesn't execute. This means even if charts show the limit price was reached, execution isn't guaranteed.
### Managing limit orders
After creating a limit order, it appears under the "Orders" tab. You can edit the order to adjust the trigger price or limit price.
## Stop Market orders
A Stop Market order opens or increases a position when the oracle price reaches your specified stop price. Stop Market orders are available for long and short positions only — they are not available for swaps.
To create a Stop Market order, select "Stop Market" from the order type selector in the trade box. If you already have an open position, select "Increase size (Stop Market)" from the "..." menu in the position row.
### Trigger conditions
The oracle price checked against your stop price depends on the direction of your position:
- \*\*Long:\*\* The order triggers when \`maxPrice >= stop price\`. The \`maxPrice\` oracle value is also used for execution.
- \*\*Short:\*\* The order triggers when \`minPrice <= stop price\`. The \`minPrice\` oracle value is also used for execution.
The UI enforces that a long stop price must be set above the current mark price, and a short stop price must be set below it.
### Execution price
When the oracle price reaches your stop price, the order executes at the closest oracle price update to the trigger price — not necessarily at the exact stop price you set. During fast market moves, the oracle price may skip past your trigger price, causing execution at a different oracle update or no execution at all. See \[Price gaps and volatility\](#price-gaps-and-volatility).
### Acceptable price
Stop Market orders do not have a user-configurable acceptable price. The acceptable price is set automatically to the maximum possible value for longs and the minimum for shorts, meaning there is no upper or lower price constraint beyond the trigger condition. No acceptable price is shown for Stop Market orders. Because the acceptable price is set to a boundary value, the UI does not display it.
### Managing Stop Market orders
After creation, a Stop Market order appears under the "Orders" tab. You can edit the order to adjust the stop price. Stop Market orders cannot be partially filled — the full order executes when the trigger condition is met.
:::note
Stop Market orders are not guaranteed to execute. Execution may fail if the oracle price does not reach your stop price, if there is insufficient liquidity, or if the \[max allowed leverage\](#max-leverage) would be exceeded.
:::
## TWAP orders
TWAP (Time-Weighted Average Price) orders execute increases or decreases to positions, and swaps, in evenly distributed parts over a specified duration. By splitting into smaller parts executed at regular time intervals, TWAP reduces price impact — making it suitable for large positions where a single market order would move the price significantly.
The interface suggests switching to TWAP when your order size is at least $1,000,000 USD and the estimated negative price impact exceeds 0.2%.
### How TWAP works
When you create a TWAP order, the interface submits multiple individual orders — each a Limit Increase, Limit Decrease, or Limit Swap — with their total size divided equally across all parts. Each part has a staggered activation timestamp. The first part activates immediately; the last part activates at the end of your configured duration. Keepers execute each part once its timestamp is reached, using the current oracle price at execution.
TWAP is not a distinct on-chain order type. It is implemented at the application layer by grouping standard limit orders with time-gated activation.
### Configuration
The TWAP configuration panel exposes these fields:
- \*\*Duration\*\* — the total time over which parts are spread, entered as hours and minutes. There is no enforced minimum or maximum duration.
- \*\*Number of parts\*\* — the number of individual orders to create. The minimum is 2 and the maximum is 30. The default is 5.
- \*\*Frequency\*\* — a derived, display-only field: total duration in seconds divided by the number of parts.
- \*\*Size per part\*\* — a derived, display-only field: total position size divided by the number of parts.
The default duration is 10 hours.
For new positions (with no existing position), the minimum margin per part is $1 USD.
### Creating a TWAP order
- To open or increase a position: select "TWAP" from the order type selector (under the "More" dropdown in the trade box), or select "Increase size (TWAP)" from the "..." menu on the position row.
- To close or decrease a position: click the "TWAP" button in the Close column of the position row.
- To perform a TWAP swap: select "TWAP" in the order type selector on the Swap tab.
### Monitoring and cancelling TWAP orders
After creating a TWAP order, it appears under the "Orders" tab. The trigger price column shows "N/A" because each part executes at the oracle price at the time of execution, not at a fixed trigger price. Progress is displayed as the number of executed parts out of the total — for example, "(3/5)" means 3 of 5 parts have already executed.
TWAP orders can't be edited. To modify a TWAP order, cancel it and create a new one. Cancelling a TWAP order cancels all remaining unexecuted parts in a single transaction.
### Execution fees
The total execution fee for all parts is paid upfront when you create the TWAP order. This fee is divided equally across all parts. If network fees rise after creation and a part's allocated fee becomes insufficient for keeper execution, that part may be frozen rather than executed automatically.
:::note
If a TWAP part is frozen due to insufficient execution fee, you may need to top it up separately. This situation is the same as for any frozen limit order.
:::
TWAP orders are not guaranteed to execute. Individual parts may fail to execute if there is insufficient liquidity, the max allowed leverage would be exceeded, or the allocated execution fee is insufficient for the keeper to process the order at that time. See \[Order execution guarantees\](#order-execution-guarantees) for the full list of conditions that apply to all non-market order types.
## Take-Profit and Stop-Loss orders
Take-Profit and Stop-Loss (TP/SL) orders automatically close part or all of a position when the oracle price reaches a specified level. Take-Profit closes at a favorable price to lock in gains. Stop-Loss closes at an unfavorable price to limit losses.
You can create TP/SL orders in three ways:
- Select "Set TP/SL" from the "..." menu in the positions list.
- Use the TP/SL section in the trade box before opening a position.
- Use the close dialog on an open position.
After creating a TP/SL order, it appears in your position row and under the "Orders" tab. You can edit the order to adjust the trigger price if needed.
### Trigger price evaluation
Take-Profit and Stop-Loss orders are mapped to distinct on-chain order types — \`LimitDecrease\` and \`StopLossDecrease\` — each with its own trigger condition:
| Order | Side | Triggers when |
| ----------- | ----- | --------------------------- |
| Take-Profit | Long | \`minPrice >= trigger price\` |
| Take-Profit | Short | \`maxPrice <= trigger price\` |
| Stop-Loss | Long | \`minPrice <= trigger price\` |
| Stop-Loss | Short | \`maxPrice >= trigger price\` |
The same oracle price component used to trigger the order is also used as the base execution price, before any price impact adjustment is applied.
Fast market moves can cause the oracle price to skip past your trigger price, resulting in execution at the next oracle update or non-execution. See \[Price gaps and volatility\](#price-gaps-and-volatility).
### Auto-cancel TP/SL
When a position is fully closed — whether by a market close, liquidation, or a triggered TP/SL order — any remaining TP/SL orders on that position are automatically cancelled. This prevents orphaned orders from persisting after the position no longer exists.
Auto-cancel applies only to \`LimitDecrease\` (Take-Profit) and \`StopLossDecrease\` (Stop-Loss) order types. Limit Increase and Stop Market orders are not auto-cancelled.
Auto-cancel is enabled by default. You can turn it off in settings.
The current per-network limits for auto-cancel TP/SL orders per position are:
| Network | Max auto-cancel TP/SL orders |
| --------- | ---------------------------- |
| Arbitrum | 11 |
| Avalanche | 6 |
These limits are enforced on-chain. If creating an order with auto-cancel enabled would exceed the limit, the transaction reverts. The frontend handles this by automatically setting \`autoCancel\` to \`false\` for orders that would exceed the limit, so the order is still created but won't be auto-cancelled when the position closes. The interface displays a warning when this occurs — orders created without auto-cancel require manual cancellation.
:::note
The auto-cancel limit is read live from the on-chain data store and may change over time.
:::
## Order execution guarantees
:::warning
Limit, Stop Market, TWAP, and TP/SL orders are not guaranteed to execute. This can occur in situations including but not limited to:
- The oracle price did not reach the specified trigger price — see \[trigger price evaluation\](#trigger-price-evaluation) for how trigger conditions differ by order type and side (Limit, Stop Market, TP/SL)
- There may not be sufficient liquidity to execute the order
- The \[max allowed leverage\](#max-leverage) would be exceeded
- If your position becomes liquidatable, keepers attempt to execute associated Stop-Loss orders first, but this is not guaranteed to succeed — see \[Stop-Loss orders and liquidations\](./liquidations.md#stop-loss-orders-and-liquidations)
:::
---
## Trading overview
GMX is a decentralized exchange that lets you trade without a username or password. The platform uses oracle-based pricing sourced from aggregated exchange data, which reduces the risk of liquidations from temporary wicks. For details on how pricing works, see \[Pricing on GMX\](./order-types.md#pricing-on-gmx).
GMX V2 uses linear, USD-based PnL with flexible collateral, so your overall exposure can differ from a standard stablecoin-margined linear perp. For a practical explanation, see \[Are GMX perps linear or inverse?\](./order-types.md#are-gmx-perps-linear-or-inverse).
## Adding a wallet
If you don't have a wallet yet, you can use \[Rabby\](https://rabby.io/).
## Connecting and funding your wallet
After you have a wallet, connect it by pressing the "Connect wallet" button on the \[Trade\](https://app.gmx.io/#/trade) page.
To fund your wallet with the required gas tokens, refer to your wallet onboarding experience, which offers options for buying, bridging, and on-ramping. If you don't have the required gas token for the network, you can still trade using \[Express Trading\](#express-trading-and-one-click-trading).
## Multichain trading
GMX lets you trade from multiple blockchain networks. The method you use depends on which chain your wallet is connected to: direct wallet trading on chains where GMX markets are deployed, or the GMX Account for cross-chain access from other supported networks.
| Connected network | Wallet funds | GMX Account funds |
| ---------------------------------- | -------------------- | ------------------- |
| Arbitrum | ✅ Arbitrum markets | ✅ Arbitrum markets |
| Avalanche | ✅ Avalanche markets | ❌ Not available |
| Botanix | ✅ Botanix markets | ❌ Not available |
| MegaETH | ✅ MegaETH markets | ❌ Not available |
| Other chains (Ethereum, Base, BNB) | ❌ No GMX markets | ✅ Arbitrum markets |
### Direct wallet trading
GMX markets are deployed on Arbitrum, Avalanche, Botanix, and MegaETH. When your wallet is connected to any of these chains, you can trade directly using the funds in your wallet — no additional setup required.
### GMX Account (multichain)
The GMX Account lets you trade on GMX from chains that don't have GMX markets deployed, such as Ethereum, Base, or BNB. You can also use it when connected to Arbitrum. Arbitrum is the only supported settlement chain — all trades through the GMX Account execute on Arbitrum markets.
Here's how it works:
- Your GMX Account balance lives on Arbitrum.
- Deposit from any supported source chain — funds are automatically bridged using Stargate (token transfers) and LayerZero (cross-chain messaging).
- Trade on Arbitrum markets using your GMX Account balance.
- Withdraw to any supported chain, regardless of where you originally deposited.
Think of the GMX Account as a trading wallet on Arbitrum that you can fund and withdraw to from anywhere.
:::note
The GMX Account is not available on Avalanche, Botanix, or MegaETH. On these chains, only direct wallet trading is supported.
:::
#### Supported deposits and withdrawals
The following chains and tokens are available for deposits into and withdrawals from your GMX Account on Arbitrum.
| Chain | Deposit tokens | Withdrawal tokens |
| -------- | --------------- | ----------------- |
| Ethereum | USDC, USDT, ETH | USDC, USDT, ETH |
| Base | USDC, ETH | USDC, ETH |
| BNB | USDC, USDT | USDC, USDT |
:::note
Bridging for GMX Account deposits and withdrawals is limited by Stargate liquidity caps.
:::
## Express Trading and One-Click Trading
GMX provides different modes to suit trader preferences: Classic Trading, Express Trading, and Express + One-Click Trading. We recommend using Express or Express + One-Click, as they provide the best experience, and trading fees are the same on all modes.
| Mode | Signing method | RPC infrastructure | Gas payments |
| --------------------------- | -------------------------------------------------------------------------------------- | --------------------------------------------- | --------------------------------------------------------------------- |
| Classic Trading | On-chain: wallet signing popup for each trade | Uses your own wallet's RPC | ETH on Arbitrum and MegaETH, AVAX on Avalanche, BTC on Botanix |
| Express Trading | Off-chain: you sign messages locally; GMX broadcasts on-chain via Gelato Relay | GMX-sponsored premium RPCs (high reliability) | USDC or WETH on Arbitrum, USDC or WAVAX on Avalanche, PBTC on Botanix, USDM or WETH on MegaETH |
| Express + One-Click Trading | Off-chain: auto-signed with a locally stored sub-account key (no manual confirmations) | GMX-sponsored premium RPCs (high reliability) | USDC or WETH on Arbitrum, USDC or WAVAX on Avalanche, PBTC on Botanix, USDM or WETH on MegaETH |
### Enabling One-Click Trading
One-Click Trading can be enabled through the settings menu in the top right of the interface. Enabling this feature lets you trade instantly without a wallet signing popup for each trade.
If you are building a delegated trading or one-click trading integration on top of GMX, see \[Delegated trading integration\](../api/contracts/delegated-trading.md).
#### Safety features
- Funds from decreasing positions, closing positions, or swaps can only be sent back to your wallet.
- Trades executed without signing popups are limited by the maximum number you authorize. For instance, if you authorize 10 actions, after 10 trades, a wallet signing popup appears to re-authorize further trades.
#### Risks
- This feature uses a sub-account key stored locally in your browser. If your browser is compromised, the key could potentially leak, allowing trades to be executed.
- The previously authorized trade limit acts as a safeguard. Even if compromised, a malicious actor can only execute trades up to the authorized limit.
## RPC URLs
GMX uses different RPC URLs for querying (reading data) and submitting transactions (writing data).
- Reading RPCs are set automatically by the GMX interface and selected from a curated list to ensure fast and reliable data loading.
- Writing RPCs:
- Classic Trading: Set by your wallet.
- Express Trading and Express + One-Click Trading: Automatically set to GMX-sponsored premium RPCs (via Gelato) for superior reliability and speed.
If you're experiencing issues while trading in Classic Trading, consider switching to Express or Express + One-Click Trading through the settings menu. Alternatively, you can manually select another RPC URL via your wallet from options provided on \[Chainlist\](https://chainlist.org/).
---
# GetOrdersByAddress | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/gmx-api/get-orders-by-address/#__docusaurus_skipToContent_fallback)
GetOrdersByAddress
==================
GET
/orders
-------
GetOrdersByAddress
Request[](https://docs.gmx.io/docs/api/gmx-api/get-orders-by-address/#request "Direct link to request")
---------------------------------------------------------------------------------------------------------
Responses[](https://docs.gmx.io/docs/api/gmx-api/get-orders-by-address/#responses "Direct link to Responses")
---------------------------------------------------------------------------------------------------------------
* 200
* 400
* 500
Success
Bad Request - Invalid address
Internal Server Error
---
# Archived | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/category/archived/#__docusaurus_skipToContent_fallback)
[📄️ Contracts for V1\
--------------------\
\
Docs for the GMX V1 contracts.](https://docs.gmx.io/docs/archived/contracts-v1/)
[📄️ Liquidity on V1\
-------------------\
\
GLP was the liquidity provider token for V1. Since July 2025, GLP has been phased out and no longer provides liquidity as V1 trading is disabled, so buying GLP tokens is no longer possible. You may only redeem existing GLP via the sell GLP page.](https://docs.gmx.io/docs/archived/liquidity-v1/)
[📄️ Trading on V1\
-----------------\
\
Trading on V1 has been phased out since July 2025. Please close any positions using v1.app.gmx.io.](https://docs.gmx.io/docs/archived/trading-v1/)
---
# Contracts | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/category/contracts/#__docusaurus_skipToContent_fallback)
[📄️ Overview\
------------\
\
Docs for the GMX contracts. This section focuses on the contracts most integrations interact with directly, not an exhaustive page for every deployed contract.](https://docs.gmx.io/docs/api/contracts/overview/)
[📄️ Architecture\
----------------\
\
This page covers the GMX smart contract architecture, execution model, keeper network, and integration considerations. For contract function references, see Reader, ExchangeRouter, and GLV Reader.](https://docs.gmx.io/docs/api/contracts/architecture/)
[📄️ ExchangeRouter\
------------------\
\
The ExchangeRouter contract exposes the main protocol functions for creating orders, deposits, and withdrawals.](https://docs.gmx.io/docs/api/contracts/exchange-router/)
[📄️ Reader\
----------\
\
The Reader contract provides convenience functions for retrieving information such as markets, positions, and pricing data.](https://docs.gmx.io/docs/api/contracts/reader/)
[📄️ GlvReader\
-------------\
\
The GlvReader contract provides read-only functions for querying GMX Liquidity Vault (GLV) data from on-chain storage.](https://docs.gmx.io/docs/api/contracts/glv-reader/)
[📄️ GlvRouter\
-------------\
\
The GlvRouter contract is the main entry point for creating and cancelling GLV (GMX Liquidity Vault) deposits and withdrawals. It works similarly to the ExchangeRouter but targets GLV vaults instead of individual GM markets.](https://docs.gmx.io/docs/api/contracts/glv-router/)
[📄️ Fees\
--------\
\
This page documents fee types, execution fee calculation, and how to retrieve fee parameters from the DataStore.](https://docs.gmx.io/docs/api/contracts/fees/)
[📄️ Simulations\
---------------\
\
The ExchangeRouter and GlvRouter contracts expose public simulation functions that let you dry-run an execution against a set of supplied prices before submitting a real request for keeper execution. Running a simulation catches validation errors — such as price impact limits or insufficient output amounts — without spending gas on a failed transaction.](https://docs.gmx.io/docs/api/contracts/simulations/)
[📄️ Event monitoring\
--------------------\
\
All protocol events are emitted through a single EventEmitter contract. Every event carries an eventName field, so you can monitor any protocol action by filtering on the EventEmitter address plus the eventName value — without needing to track individual logic contract addresses, which may be upgraded over time.](https://docs.gmx.io/docs/api/contracts/events/)
[📄️ Advanced entry points\
-------------------------\
\
This page covers the contract surfaces beyond the core ExchangeRouter / GlvRouter flow: delegated subaccount trading, gasless relay routers, and multichain GMX Account routers. Some of these are end-user or integrator entry points, while others are specialized router or controller surfaces.](https://docs.gmx.io/docs/api/contracts/advanced-entrypoints/)
[📄️ Delegated trading integration\
---------------------------------\
\
This page explains how to build delegated trading flows on GMX V2 using the subaccount and relay surfaces documented in Advanced entry points. It is intended for integrators who need an end-to-end implementation pattern, not just a function reference.](https://docs.gmx.io/docs/api/contracts/delegated-trading/)
[📄️ Contract addresses\
----------------------\
\
This page lists the key contract addresses for each supported chain. For the complete list of all deployed contracts (100+ per chain), see the gmx-synthetics deployments folder. The machine-readable contracts.json in that folder covers mainnet deployments, while testnet deployments are published in the per-network markdown files.](https://docs.gmx.io/docs/api/contracts/addresses/)
[📄️ Known issues\
----------------\
\
This page is based on the known issues section of the gmx-synthetics repository, with corrections and additions. It is intended for integrators, auditors, and developers building on top of the GMX contracts.](https://docs.gmx.io/docs/api/contracts/known-issues/)
---
# GetPairs | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/api/gmx-api/get-pairs/#__docusaurus_skipToContent_fallback)
GetPairs
========
GET
/pairs
------
GetPairs
Request[](https://docs.gmx.io/docs/api/gmx-api/get-pairs/#request "Direct link to request")
---------------------------------------------------------------------------------------------
Responses[](https://docs.gmx.io/docs/api/gmx-api/get-pairs/#responses "Direct link to Responses")
---------------------------------------------------------------------------------------------------
* 200
* 500
Success
Internal Server Error
---
# Tokenomics | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/category/tokenomics/#__docusaurus_skipToContent_fallback)
[📄️ GMX token\
-------------\
\
GMX is the platform's utility and governance token. Staking GMX earns you a share of protocol fees — 27% of fees from leverage trading, liquidations, borrowing fees, and swaps are used to buy back GMX. Distribution of bought-back GMX is currently suspended; see Staking for details. For more on fee distribution, see Fees. GMX also grants voting power in protocol governance.](https://docs.gmx.io/docs/tokenomics/gmx-token/)
[📄️ Rewards\
-----------\
\
Staking GMX earns you a share of protocol fees. 27% of fees from leverage trading, liquidations, borrowing fees, and swaps are used to buy back GMX on the open market — a mechanism approved by the DAO Tally vote. Staking also grants voting power in protocol governance. You can stake and manage rewards on the Earn page. For more on the GMX token, see GMX token.](https://docs.gmx.io/docs/tokenomics/rewards/)
---
# Changelog | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/sdk/changelog/#__docusaurus_skipToContent_fallback)
On this page
1.5.0-alpha-8 — March 11, 2026[](https://docs.gmx.io/docs/sdk/changelog/#150-alpha-8--march-11-2026 "Direct link to 1.5.0-alpha-8 — March 11, 2026")
------------------------------------------------------------------------------------------------------------------------------------------------------
This release expands the `GmxApiSdk` read surface to cover more GMX HTTP endpoints and exports the matching typed response helpers.
* Added `fetchMarkets()`, `fetchMarketsTickers(params)`, `fetchTokens()`, `fetchPairs()`, `fetchRates(params)`, `fetchApy(params)`, `fetchPerformanceAnnualized(params)`, and `fetchPerformanceSnapshots(params)` to `GmxApiSdk` in `@gmx-io/sdk/v2`.
* Added the matching `@gmx-io/sdk/v2` type exports for APY, market tickers, pairs, rates, and performance responses.
1.5.0-alpha-7 — March 9, 2026[](https://docs.gmx.io/docs/sdk/changelog/#150-alpha-7--march-9-2026 "Direct link to 1.5.0-alpha-7 — March 9, 2026")
---------------------------------------------------------------------------------------------------------------------------------------------------
This release improves TypeScript type resolution for projects that consume the SDK in CommonJS mode.
* Added `typesVersions` mappings to `@gmx-io/sdk` so TypeScript resolves subpath types correctly when `moduleResolution` is set to `"node"` or `"node10"` in `tsconfig.json`. Projects using `"bundler"` or `"node16"` module resolution already resolve types through the `exports` field and are unaffected.
* Covers the root client entrypoints (`@gmx-io/sdk`, `@gmx-io/sdk/v1`, `@gmx-io/sdk/v2`) as well as config, ABI, utility, prebuilt, and type-only subpaths.
* No runtime SDK API methods changed in this release. The update is packaging and type-resolution focused.
1.5.0-alpha-6 — March 9, 2026[](https://docs.gmx.io/docs/sdk/changelog/#150-alpha-6--march-9-2026 "Direct link to 1.5.0-alpha-6 — March 9, 2026")
---------------------------------------------------------------------------------------------------------------------------------------------------
This release adds OHLCV reads to `GmxApiSdk` and renames address-filtered API SDK params to match the underlying REST API.
* Added `fetchOhlcv(params)` to `GmxApiSdk` in `@gmx-io/sdk/v2`. This method wraps `fetchApiOhlcv` and returns `OhlcvCandle[]` from `/prices/ohlcv`.
* Renamed `fetchPositionsInfo(params)` and `fetchOrders(params)` params from `account` to `address`. The underlying `fetchApiPositionsInfo` and `fetchApiOrders` helpers now use `address` as well.
* Added `OhlcvCandle` and `OhlcvParams` exports in `@gmx-io/sdk/v2`, plus the `@gmx-io/sdk/types/prices` subpath export for price candle types.
1.5.0-alpha-5 — February 28, 2026[](https://docs.gmx.io/docs/sdk/changelog/#150-alpha-5--february-28-2026 "Direct link to 1.5.0-alpha-5 — February 28, 2026")
---------------------------------------------------------------------------------------------------------------------------------------------------------------
This release fixes a potential negative pool amount edge case in position price impact calculations.
* `getPriceImpactForPosition` in `@gmx-io/sdk/utils/fees` now accepts an optional `fallbackToZero` option. When enabled, negative pool amounts are clamped to zero instead of producing invalid results.
* `getContractPositionDynamicFees` in `@gmx-io/sdk/utils/positions` uses `fallbackToZero: true` when calling `getPriceImpactForPosition` internally, preventing errors from negative pool states.
1.5.0-alpha-4 — February 13, 2026[](https://docs.gmx.io/docs/sdk/changelog/#150-alpha-4--february-13-2026 "Direct link to 1.5.0-alpha-4 — February 13, 2026")
---------------------------------------------------------------------------------------------------------------------------------------------------------------
This release adds five new synthetic markets on Arbitrum and expands the `GmxApiSdk` class with positions and orders support.
* Added `fetchPositionsInfo(params)` and `fetchOrders(params)` methods to `GmxApiSdk` in `@gmx-io/sdk/v2`. These methods wrap `fetchApiPositionsInfo` and `fetchApiOrders` respectively.
* Added five new Arbitrum markets: XAUT/USD \[WBTC-USDC\], LIT/USD \[WETH-USDC\], IP/USD \[WBTC-USDC\], CC/USD \[WBTC-USDC\], and MET/USD \[WBTC-USDC\]. All five index tokens are synthetic.
* Added corresponding token configurations for XAUT, LIT (Lighter), IP (Story), CC (Canton), and MET (Meteora) on Arbitrum.
1.5.0-alpha-3 — February 13, 2026[](https://docs.gmx.io/docs/sdk/changelog/#150-alpha-3--february-13-2026 "Direct link to 1.5.0-alpha-3 — February 13, 2026")
---------------------------------------------------------------------------------------------------------------------------------------------------------------
This release introduces the `GmxApiSdk` client and adds REST API support for positions, orders, and fee utilities.
* Added `GmxApiSdk` class exported from `@gmx-io/sdk/v2`. Instantiate it with a `chainId` to call GMX REST API endpoints directly. Provides `fetchMarketsInfo()` and `fetchTokensData()` methods. Supported on Arbitrum, Avalanche, and Arbitrum Sepolia; throws at construction time for unsupported chains.
* Added `getPositionInfo` utility to `@gmx-io/sdk/utils/positions`. Computes a comprehensive position summary (entry price, PnL, leverage, liquidation price, net value, fees) from a raw position and market data.
* Added `getContractPositionDynamicFees` to `@gmx-io/sdk/utils/positions`. Calculates dynamic fees (borrowing, funding, closing) for a position given the current market fee state.
* Added `fetchApiPositionsInfo` to `@gmx-io/sdk/utils/positions`. Fetches position data from the GMX REST API instead of on-chain multicalls (available on Arbitrum, Avalanche, and Arbitrum Sepolia).
* Added `fetchApiOrders` to `@gmx-io/sdk/utils/orders`. Fetches order data from the GMX REST API.
* Added `isApiSupported(chainId)` to `@gmx-io/sdk/configs/api`. Returns `true` for chains that have a GMX REST API endpoint (Arbitrum, Avalanche, and Arbitrum Sepolia).
* Added `FLOAT_PRECISION_SQRT_DECIMALS` (15) and `FLOAT_PRECISION_SQRT` (`10n ** 15n`) constants to `@gmx-io/sdk/utils/numbers`.
1.5.0-alpha-2 — February 11, 2026[](https://docs.gmx.io/docs/sdk/changelog/#150-alpha-2--february-11-2026 "Direct link to 1.5.0-alpha-2 — February 11, 2026")
---------------------------------------------------------------------------------------------------------------------------------------------------------------
This release adds fee utilities and Solidity error decoding helpers.
* Added `getMaxNegativeImpactBps` to `@gmx-io/sdk/utils/fees`. Converts a market's `maxPositionImpactFactorNegative` to basis points.
* Added `tryDecodeCustomError`, `decodeErrorFromViemError`, and `extractErrorDataFromViemError` to `@gmx-io/sdk/utils/errors`. These functions decode custom Solidity errors from viem error objects using the GMX `CustomErrors` ABI.
1.3.1 — September 15, 2025[](https://docs.gmx.io/docs/sdk/changelog/#131--september-15-2025 "Direct link to 1.3.1 — September 15, 2025")
------------------------------------------------------------------------------------------------------------------------------------------
This release fixes order payload forwarding.
* Fixed `dataList` not being forwarded to the on-chain order payload in `createIncreaseOrder`, `createDecreaseOrder`, and `createSwapOrder`. The `dataList` parameter (optional `string[]`) now defaults to `[]` when omitted.
1.3.0 — September 15, 2025[](https://docs.gmx.io/docs/sdk/changelog/#130--september-15-2025 "Direct link to 1.3.0 — September 15, 2025")
------------------------------------------------------------------------------------------------------------------------------------------
This release adds GMX v2.2 contract support and position impact fields.
* Added support for GMX v2.2 contracts. Updated `SyntheticsReader` and `ClaimHandler` ABIs; added `SmartAccount` ABI.
* Added `pendingImpactUsd` and `closePriceImpactDeltaUsd` fields to `PositionInfo`.
* Added `nextPendingImpactDeltaUsd` and `potentialPriceImpactDiffUsd` fields to `NextPositionValues`.
* Fixed position impact capping logic in `getNextPositionValuesForIncreaseTrade` to use `nextSizeUsd` instead of `sizeDeltaUsd`.
1.2.1 — August 25, 2025[](https://docs.gmx.io/docs/sdk/changelog/#121--august-25-2025 "Direct link to 1.2.1 — August 25, 2025")
---------------------------------------------------------------------------------------------------------------------------------
This release fixes Botanix client initialization.
* Fixed Botanix viem client initialization. Added Botanix to `BATCH_CONFIGS` (it was missing, which caused the default `PublicClient` to fail on Botanix). Changed batch config access to use optional chaining (`?.`) so an unsupported chain ID doesn't throw at client construction time.
1.2.0 — July 17, 2025[](https://docs.gmx.io/docs/sdk/changelog/#120--july-17-2025 "Direct link to 1.2.0 — July 17, 2025")
---------------------------------------------------------------------------------------------------------------------------
This release adds three new markets across Arbitrum and Avalanche.
* Added market and token configurations for three new markets: PUMP/USD \[WBTC-USDC\] and ARB/USD \[ARB-ARB\] on Arbitrum, and PUMP/USD \[WAVAX-USDC\] on Avalanche. PUMP is a synthetic token.
1.1.0 — June 3, 2025[](https://docs.gmx.io/docs/sdk/changelog/#110--june-3-2025 "Direct link to 1.1.0 — June 3, 2025")
------------------------------------------------------------------------------------------------------------------------
This release adds four new synthetic markets on Arbitrum.
* Added market and token configurations for four new markets on Arbitrum: CRV/USD \[WETH-USDC\], XMR/USD \[WBTC-USDC\], MOODENG/USD \[WBTC-USDC\], and PI/USD \[WBTC-USDC\]. All four index tokens are synthetic.
1.0.5 — May 26, 2025[](https://docs.gmx.io/docs/sdk/changelog/#105--may-26-2025 "Direct link to 1.0.5 — May 26, 2025")
------------------------------------------------------------------------------------------------------------------------
This release fixes `uiFeeReceiver` propagation in order creation.
* Fixed `uiFeeReceiver` not being read from `sdk.config.settings.uiFeeReceiverAccount` in `createIncreaseOrder`, `createDecreaseOrder`, and `createSwapOrder`. Previously all three functions passed `zeroAddress` unconditionally.
1.0.3 — May 23, 2025[](https://docs.gmx.io/docs/sdk/changelog/#103--may-23-2025 "Direct link to 1.0.3 — May 23, 2025")
------------------------------------------------------------------------------------------------------------------------
This release adds the `isTrigger` parameter and fixes order type forwarding in `createDecreaseOrder`.
* Added `isTrigger` parameter to `orders.createDecreaseOrder`. When `true`, the order type is taken from `decreaseAmounts.triggerOrderType`; when `false` or omitted, the order type defaults to `Market Decrease`.
* Fixed `orderType` not being forwarded correctly in `orders.createDecreaseOrder`.
1.0.0 — April 30, 2025[](https://docs.gmx.io/docs/sdk/changelog/#100--april-30-2025 "Direct link to 1.0.0 — April 30, 2025")
------------------------------------------------------------------------------------------------------------------------------
This is the initial stable release. It removes the deprecated `subgraphUrl` config key and adds dual ESM/CJS module support.
* Removed `subgraphUrl` from `GmxSdkConfig`. Use `subsquidUrl` instead.
* Added support for both ESM and CJS module formats. The package ships two builds: `build/esm/` and `build/cjs/`.
* Changed the default module format from ESM to CJS. The `main` entry point resolves to `build/cjs/src/index.js`.
* [1.5.0-alpha-8 — March 11, 2026](https://docs.gmx.io/docs/sdk/changelog/#150-alpha-8--march-11-2026)
* [1.5.0-alpha-7 — March 9, 2026](https://docs.gmx.io/docs/sdk/changelog/#150-alpha-7--march-9-2026)
* [1.5.0-alpha-6 — March 9, 2026](https://docs.gmx.io/docs/sdk/changelog/#150-alpha-6--march-9-2026)
* [1.5.0-alpha-5 — February 28, 2026](https://docs.gmx.io/docs/sdk/changelog/#150-alpha-5--february-28-2026)
* [1.5.0-alpha-4 — February 13, 2026](https://docs.gmx.io/docs/sdk/changelog/#150-alpha-4--february-13-2026)
* [1.5.0-alpha-3 — February 13, 2026](https://docs.gmx.io/docs/sdk/changelog/#150-alpha-3--february-13-2026)
* [1.5.0-alpha-2 — February 11, 2026](https://docs.gmx.io/docs/sdk/changelog/#150-alpha-2--february-11-2026)
* [1.3.1 — September 15, 2025](https://docs.gmx.io/docs/sdk/changelog/#131--september-15-2025)
* [1.3.0 — September 15, 2025](https://docs.gmx.io/docs/sdk/changelog/#130--september-15-2025)
* [1.2.1 — August 25, 2025](https://docs.gmx.io/docs/sdk/changelog/#121--august-25-2025)
* [1.2.0 — July 17, 2025](https://docs.gmx.io/docs/sdk/changelog/#120--july-17-2025)
* [1.1.0 — June 3, 2025](https://docs.gmx.io/docs/sdk/changelog/#110--june-3-2025)
* [1.0.5 — May 26, 2025](https://docs.gmx.io/docs/sdk/changelog/#105--may-26-2025)
* [1.0.3 — May 23, 2025](https://docs.gmx.io/docs/sdk/changelog/#103--may-23-2025)
* [1.0.0 — April 30, 2025](https://docs.gmx.io/docs/sdk/changelog/#100--april-30-2025)
---
# Referrals | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/referrals/#__docusaurus_skipToContent_fallback)
On this page
Get fee discounts and earn rewards through the GMX referral program.
How it works[](https://docs.gmx.io/docs/referrals/#how-it-works "Direct link to How it works")
------------------------------------------------------------------------------------------------
The GMX referral program lets you earn rewards when traders you refer open or close positions on GMX V2. To participate as an affiliate, create a referral code and share your referral link.
To create a referral code:
1. Go to the [Referrals](https://app.gmx.io/#/referrals)
page.
2. Select the **Affiliates** tab.
3. Enter a referral code using letters (A–Z, a–z), digits (0–9), or underscores. Codes are case-sensitive and can be up to 20 characters long.
4. Submit the transaction to register the code on-chain.
note
You must create your referral code separately on each network (Arbitrum and Avalanche) to earn rewards on that network.
Once your code is registered, copy your referral link from the Referrals page. The link format is:
https://app.gmx.io/#/trade/?ref=your-code
Share this link on any platform. When a trader opens the link, your referral code is stored in their browser. The code is written permanently to the contract the first time they create an order. From that point on, the trader receives a fee discount and you earn rewards — both are applied automatically.
The referral program is subject to change as determined by GMX token holders. The full [referral terms](https://gmx.io/#/referral-terms)
are available on the GMX website.
Claiming rewards[](https://docs.gmx.io/docs/referrals/#claiming-rewards "Direct link to Claiming rewards")
------------------------------------------------------------------------------------------------------------
Rewards in the referral program work differently depending on whether you're a trader receiving discounts or an affiliate earning rewards.
### V2[](https://docs.gmx.io/docs/referrals/#v2 "Direct link to V2")
Traders receive fee discounts automatically. The discount is deducted from the position fee at trade execution.
Affiliates accumulate rewards on every trade made by their referred traders. Rewards accrue per market in the collateral token of each market. You can claim them at any time from the [Referrals](https://app.gmx.io/#/referrals)
page using the "Claimable rebates" card.
### V1 (historical)[](https://docs.gmx.io/docs/referrals/#v1-historical "Direct link to V1 (historical)")
V1 trading is no longer active. No new V1 referral rewards are earned. Historically, V1 rewards and discounts were distributed as airdrops — ETH on Arbitrum and AVAX on Avalanche — every Wednesday. Your past V1 distribution history remains viewable on the [Referrals](https://app.gmx.io/#/referrals)
page, labeled "V1 airdrop."
Tiers[](https://docs.gmx.io/docs/referrals/#tiers "Direct link to Tiers")
---------------------------------------------------------------------------
The referral program uses a tier system to prevent gaming through self-referrals, ensuring affiliates receive rewards for the traders they brought to the platform.
| Tier | Trader discount | Affiliate reward |
| --- | --- | --- |
| 1 | 5% | 5% |
| 2 | 10% | 10% |
| 3 | 10% | 15% |
Anyone can create a Tier 1 code. To upgrade to Tier 2 or Tier 3, your account must meet the following weekly thresholds:
| Tier | Active users | Combined volume |
| --- | --- | --- |
| 2 | 15+ | $5M+ |
| 3 | 30+ | $25M+ |
If your account meets these criteria, send a DM to [@GMXPartners](https://t.me/GMXPartners)
to request an upgrade. Wallet providers and other protocols are also eligible for Tier 2 and Tier 3 rewards.
Rewards and discounts apply to opening and closing fees for leverage trading. They don't apply to borrow fees or funding fees.
Tier 3 affiliates receive their 15% reward in the market's collateral token.
### esGMX rewards[](https://docs.gmx.io/docs/referrals/#esgmx-rewards "Direct link to esGMX rewards")
Tier 3 affiliates previously received a weekly esGMX bonus via the fee distributor, capped at 5,000 [esGMX tokens](https://docs.gmx.io/docs/tokenomics/rewards/#escrowed-gmx)
per week. This distribution ended on February 4, 2026.
If you received esGMX through the referral program before it ended, you can still vest it using the Affiliate vault. To access it, open the vesting modal from the esGMX card on the [Earn](https://app.gmx.io/#/earn)
page and select the Affiliate vault tab. Unlike standard vesting, the Affiliate vault doesn't require a paired GMX or GLP deposit.
Transferring a referral code[](https://docs.gmx.io/docs/referrals/#transferring-a-referral-code "Direct link to Transferring a referral code")
------------------------------------------------------------------------------------------------------------------------------------------------
To transfer ownership of a referral code to a new address, you interact directly with the `ReferralStorage` contract through a block explorer. There's no frontend UI for this action.
warning
Transferring a referral code is permanent. Once transferred, you lose ownership and only the new owner can transfer it further. There is no way to reclaim the code without the new owner's cooperation. Verify the destination address carefully before submitting.
The `ReferralStorage` contract addresses are:
* **Arbitrum:** [`0xe6fab3F0c7199b0d34d7FbE83394fc0e0D06e99d`](https://arbiscan.io/address/0xe6fab3F0c7199b0d34d7FbE83394fc0e0D06e99d#writeContract)
* **Avalanche:** [`0x827ed045002ecdabeb6e2b0d1604cf5fc3d322f8`](https://snowtrace.io/address/0x827ed045002ecdabeb6e2b0d1604cf5fc3d322f8#writeContract)
To transfer a code on a given network:
1. Convert your referral code to its `bytes32` encoding using a tool like [DEVoven](https://www.devoven.com/string-to-bytes32)
with the "Append Zeros" option checked. For example, the code `code` encodes to `0x636f646500000000000000000000000000000000000000000000000000000000`.
2. Open the `ReferralStorage` contract link for your network from the list above.
3. Go to the "Write Contract" tab.
4. Connect the wallet that currently owns the referral code.
5. Expand the `setCodeOwner` function. Enter the `bytes32` value from step 1 in the `_code` field and the destination wallet address in the `_newAccount` field.
6. Submit the transaction by clicking "Write."
* [How it works](https://docs.gmx.io/docs/referrals/#how-it-works)
* [Claiming rewards](https://docs.gmx.io/docs/referrals/#claiming-rewards)
* [V2](https://docs.gmx.io/docs/referrals/#v2)
* [V1 (historical)](https://docs.gmx.io/docs/referrals/#v1-historical)
* [Tiers](https://docs.gmx.io/docs/referrals/#tiers)
* [esGMX rewards](https://docs.gmx.io/docs/referrals/#esgmx-rewards)
* [Transferring a referral code](https://docs.gmx.io/docs/referrals/#transferring-a-referral-code)
---
# Useful modules | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/sdk/v1/exports/#__docusaurus_skipToContent_fallback)
The GMX SDK exports constants, types, and utility functions that you can import directly without going through the `GmxSdk` class. These exports are organized into three top-level categories:
* **`configs/`** — chain IDs, contract addresses, token metadata, market parameters, oracle keeper URLs, and fee factors
* **`utils/`** — fee calculations, price impact, swap routing, position sizing, number formatting, error parsing, and other computation helpers
* **`types/`** — type-only entrypoints for SDK configs, markets, tokens, orders, positions, fees, price candles, trade flows, referrals, TWAP, trade history, and Subsquid schema types
Use these exports to implement custom logic or to pre-compute values before passing them to SDK methods. Import any export directly from its module path, for example:
import { getOracleKeeperUrl } from "@gmx-io/sdk/configs/oracleKeeper";import { getFundingFactorPerPeriod } from "@gmx-io/sdk/utils/fees";import { formatUsd } from "@gmx-io/sdk/utils/numbers";import type { MarketsInfoData } from "@gmx-io/sdk/types/markets";
See the sub-pages in this section for the full API reference for each module.
---
# Examples | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/sdk/v1/examples/#__docusaurus_skipToContent_fallback)
On this page
Use this page for focused runnable snippets. If you want end-to-end trading flows or operational guidance, start with the [Integration guide](https://docs.gmx.io/docs/sdk/v1/integration-guide/)
.
Get funding fees[](https://docs.gmx.io/docs/sdk/v1/examples/#get-funding-fees "Direct link to Get funding fees")
------------------------------------------------------------------------------------------------------------------
This example shows how to fetch hourly funding fee rates for all markets using the GMX SDK. Funding fees are paid between long and short positions to keep open interest balanced — positive values mean a position receives funding, and negative values mean it pays.
### Prerequisites[](https://docs.gmx.io/docs/sdk/v1/examples/#prerequisites "Direct link to Prerequisites")
Initialize the SDK before running this example:
import { GmxSdk } from "@gmx-io/sdk";const sdk = new GmxSdk({ chainId: 42161, // Arbitrum rpcUrl: "https://arb1.arbitrum.io/rpc", oracleUrl: "https://arbitrum-api.gmxinfra.io", subsquidUrl: "https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql",});
### Fetch and format funding rates[](https://docs.gmx.io/docs/sdk/v1/examples/#fetch-and-format-funding-rates "Direct link to Fetch and format funding rates")
Call `sdk.markets.getMarketsInfo()` to retrieve live market data, then compute the per-period funding factor for each market:
import { getFundingFactorPerPeriod } from "@gmx-io/sdk/utils/fees";import { getMarketFullName } from "@gmx-io/sdk/utils/markets";import { formatRatePercentage } from "@gmx-io/sdk/utils/numbers";const { marketsInfoData } = await sdk.markets.getMarketsInfo();const fundingRates = Object.values(marketsInfoData ?? {}).map((market) => { // 3600n = 1 hour in seconds (BigInt required) const longHourly = getFundingFactorPerPeriod(market, true, 3600n); const shortHourly = getFundingFactorPerPeriod(market, false, 3600n); return { market: getMarketFullName(market), long: formatRatePercentage(longHourly, { displayDecimals: 2 }), short: formatRatePercentage(shortHourly, { displayDecimals: 2 }), };});console.table(fundingRates);// Example output:// [// { market: "BTC/USD [WBTC-USDC]", long: "-0.01%", short: "+0.01%" },// { market: "ETH/USD [WETH-USDC]", long: "+0.00%", short: "-0.00%" },// ]
`getFundingFactorPerPeriod` returns a `bigint` representing the funding factor scaled to 30 decimal places. A negative value for a position side means that side pays funding for the period. `formatRatePercentage` converts the raw factor to a human-readable percentage string.
note
The `periodInSeconds` argument must be a `bigint` (for example, `3600n` for hourly rates). Passing a plain number will cause a TypeScript type error.
### What the result tells you[](https://docs.gmx.io/docs/sdk/v1/examples/#what-the-result-tells-you "Direct link to What the result tells you")
| Field | Type | Description |
| --- | --- | --- |
| `market` | `string` | Market name in `INDEX/USD [LONG-SHORT]` format |
| `long` | `string` | Hourly funding rate for long positions (negative = paying) |
| `short` | `string` | Hourly funding rate for short positions (negative = paying) |
The sign convention is: negative means the position is paying funding to the counterpart side; positive means it is receiving funding.
### Related[](https://docs.gmx.io/docs/sdk/v1/examples/#related "Direct link to Related")
* [`getFundingFactorPerPeriod`](https://docs.gmx.io/docs/sdk/v1/exports/utils/fees/)
— function reference and parameter details
* [`formatRatePercentage`](https://docs.gmx.io/docs/sdk/v1/exports/utils/numbers/)
— number formatting utilities
* [`getMarketFullName`](https://docs.gmx.io/docs/sdk/v1/exports/utils/markets/)
— market name formatting
* [Get funding fees](https://docs.gmx.io/docs/sdk/v1/examples/#get-funding-fees)
* [Prerequisites](https://docs.gmx.io/docs/sdk/v1/examples/#prerequisites)
* [Fetch and format funding rates](https://docs.gmx.io/docs/sdk/v1/examples/#fetch-and-format-funding-rates)
* [What the result tells you](https://docs.gmx.io/docs/sdk/v1/examples/#what-the-result-tells-you)
* [Related](https://docs.gmx.io/docs/sdk/v1/examples/#related)
---
# AI Agents | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/category/ai-agents/#__docusaurus_skipToContent_fallback)
[📄️ AI Agents\
-------------\
\
GMX is built for both humans and AI agents. The protocol's oracle-based pricing, deterministic execution, and comprehensive APIs make it the ideal venue for autonomous on-chain perpetual and spot trading.](https://docs.gmx.io/docs/ai-agents/overview/)
[📄️ Plugins and Skills\
----------------------\
\
The gmx-io/gmx-ai repository provides pre-built agent skills that give AI coding agents the ability to trade perpetuals, provide liquidity, and swap tokens on GMX V2. Skills use a filesystem-based format compatible with a wide range of agents — see Installation for supported clients.](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/)
---
# Trading on V1 | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/archived/trading-v1/#__docusaurus_skipToContent_fallback)
Trading on V1 has been phased out since July 2025. Please close any positions using [v1.app.gmx.io](https://v1.app.gmx.io/#/v1)
.
---
# API v1 (REST API) | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/category/api-v1-rest-api/#__docusaurus_skipToContent_fallback)
[📄️ Oracle Prices\
-----------------\
\
REST endpoints for oracle information.](https://docs.gmx.io/docs/api/rest-api/oracle-prices/)
[📄️ Markets\
-----------\
\
REST endpoints for trading market information.](https://docs.gmx.io/docs/api/rest-api/markets/)
[📄️ Liquidity\
-------------\
\
REST endpoints for APY, performance, and GLV information.](https://docs.gmx.io/docs/api/rest-api/liquidity/)
[📄️ Fallback URLs\
-----------------\
\
When the primary API endpoint is unavailable for a chain, use the corresponding fallback endpoint below.](https://docs.gmx.io/docs/api/rest-api/fallback-urls/)
---
# API | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/category/api/#__docusaurus_skipToContent_fallback)
[📄️ API Overview\
----------------\
\
GMX exposes several integration points for developers, integrators, and AI agents building on the protocol. Start with the integration surface that matches your task instead of trying to use one API for everything.](https://docs.gmx.io/docs/api/overview/)
[📄️ Integration guide\
---------------------\
\
Use this page when you want exact integration steps. The hand-written API pages explain which surfaces exist and how they behave operationally. The API v2 OpenAPI reference is generated and is best used for endpoint schemas and response fields, not for workflow guidance. Use Troubleshooting when reads do not match expected state.](https://docs.gmx.io/docs/api/integration-guide/)
[🗃️ API v1 (REST API)\
---------------------\
\
4 items](https://docs.gmx.io/docs/category/api-v1-rest-api/)
[🗃️ API v2 (OpenAPI Reference)\
------------------------------\
\
15 items](https://docs.gmx.io/docs/category/api-v2-openapi-reference/)
[🗃️ Contracts\
-------------\
\
13 items](https://docs.gmx.io/docs/category/contracts/)
[📄️ Troubleshooting\
-------------------\
\
Use this page when API reads do not match what you expect. Most issues fall into one of four buckets: invalid request parameters, stale snapshots, using the wrong surface for the job, or expecting immediate read-after-write consistency.](https://docs.gmx.io/docs/api/troubleshooting/)
[📄️ GraphQL\
-----------\
\
GMX provides GraphQL endpoints powered by Subsquid for querying indexed on-chain data.](https://docs.gmx.io/docs/api/graphql/)
[📄️ Frontend Integration\
------------------------\
\
The GMX protocol consists of smart contracts deployed on blockchains.](https://docs.gmx.io/docs/api/frontend-integration/)
[📄️ Updates and Support\
-----------------------\
\
For contract and API updates, subscribe to the @GMXTechnicalAnnouncements Telegram channel.](https://docs.gmx.io/docs/api/updates-support/)
---
# Governance | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/category/governance/#__docusaurus_skipToContent_fallback)
[📄️ Voting power\
----------------\
\
Overview](https://docs.gmx.io/docs/governance/voting-power/)
[📄️ Proposal Process\
--------------------\
\
Submitting a proposal to the GMX DAO follows a structured process, outlined below:](https://docs.gmx.io/docs/governance/proposal-process/)
---
# SDK | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/category/sdk/#__docusaurus_skipToContent_fallback)
[📄️ SDK Overview\
----------------\
\
The GMX SDK (@gmx-io/sdk) is a TypeScript library for integrating GMX perpetuals and spot trading into your application. It wraps the GMX smart contracts and data APIs into a typed interface, letting you read market data, compute fees, and submit orders without managing low-level contract calls directly.](https://docs.gmx.io/docs/sdk/overview/)
[🗃️ SDK v1\
----------\
\
4 items](https://docs.gmx.io/docs/sdk/v1/)
[📄️ SDK v2\
----------\
\
If you only need read-only HTTP data without RPC calls, use the read-only API client:](https://docs.gmx.io/docs/sdk/v2/)
[📄️ Changelog\
-------------\
\
1.5.0-alpha-8 — March 11, 2026](https://docs.gmx.io/docs/sdk/changelog/)
---
# API v2 (OpenAPI Reference) | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/category/api-v2-openapi-reference/#__docusaurus_skipToContent_fallback)
[📄️ Introduction\
----------------\
\
GMX public API overview, Swagger spec links, and base URLs.](https://docs.gmx.io/docs/api/gmx-api/gmx-io-gmx-public-api/)
[📄️ GetAnnualized\
-----------------\
\
GetAnnualized](https://docs.gmx.io/docs/api/gmx-api/get-annualized/)
[📄️ GetApy\
----------\
\
GetApy](https://docs.gmx.io/docs/api/gmx-api/get-apy/)
[📄️ GetLiquidityInfo\
--------------------\
\
GetLiquidityInfo](https://docs.gmx.io/docs/api/gmx-api/get-liquidity-info/)
[📄️ GetMarketsInfo\
------------------\
\
GetMarketsInfo](https://docs.gmx.io/docs/api/gmx-api/get-markets-info/)
[📄️ GetMarketsTickers\
---------------------\
\
GetMarketsTickers](https://docs.gmx.io/docs/api/gmx-api/get-markets-tickers/)
[📄️ GetMarkets\
--------------\
\
GetMarkets](https://docs.gmx.io/docs/api/gmx-api/get-markets/)
[📄️ GetOhlcv\
------------\
\
GetOhlcv](https://docs.gmx.io/docs/api/gmx-api/get-ohlcv/)
[📄️ GetOrdersByAddress\
----------------------\
\
GetOrdersByAddress](https://docs.gmx.io/docs/api/gmx-api/get-orders-by-address/)
[📄️ GetPairs\
------------\
\
GetPairs](https://docs.gmx.io/docs/api/gmx-api/get-pairs/)
[📄️ GetPositionsInfo\
--------------------\
\
GetPositionsInfo](https://docs.gmx.io/docs/api/gmx-api/get-positions-info/)
[📄️ GetRates\
------------\
\
GetRates](https://docs.gmx.io/docs/api/gmx-api/get-rates/)
[📄️ GetSnapshots\
----------------\
\
GetSnapshots](https://docs.gmx.io/docs/api/gmx-api/get-snapshots/)
[📄️ GetTokensInfo\
-----------------\
\
GetTokensInfo](https://docs.gmx.io/docs/api/gmx-api/get-tokens-info/)
[📄️ GetTokens\
-------------\
\
GetTokens](https://docs.gmx.io/docs/api/gmx-api/get-tokens/)
---
# Trading | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/category/trading/#__docusaurus_skipToContent_fallback)
[📄️ Trading overview\
--------------------\
\
GMX is a decentralized exchange that lets you trade without a username or password. The platform uses oracle-based pricing sourced from aggregated exchange data, which reduces the risk of liquidations from temporary wicks. For details on how pricing works, see Pricing on GMX.](https://docs.gmx.io/docs/trading/overview/)
[📄️ Positions and order types\
-----------------------------\
\
This page covers how pricing works on GMX, how to open and manage positions, the available order types, and swaps.](https://docs.gmx.io/docs/trading/order-types/)
[📄️ Fees\
--------\
\
This page covers all fees on GMX, including trading fees, swap fees, price impact, funding, borrowing, and network fees.](https://docs.gmx.io/docs/trading/fees/)
[📄️ Liquidations and ADL\
------------------------\
\
This page covers liquidation mechanics, Auto-Deleveraging (ADL), and trading risks.](https://docs.gmx.io/docs/trading/liquidations/)
[📄️ Direct URLs\
---------------\
\
The GMX frontend supports direct URLs that pre-fill trade parameters, letting you share specific trading configurations or deep-link users into a particular state.](https://docs.gmx.io/docs/trading/direct-urls/)
---
# Community | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/community/#__docusaurus_skipToContent_fallback)
On this page
Stay up to date with GMX news and connect with the community across the channels listed below.
Official channels[](https://docs.gmx.io/docs/community/#official-channels "Direct link to Official channels")
---------------------------------------------------------------------------------------------------------------
The following channels carry announcements and updates from the GMX team.
* [Telegram announcements](https://t.me/GMX_Announcements)
* [Telegram technical announcements](https://t.me/GMX_Technical_Announcements)
* [Discord](https://discord.com/invite/H5PeQru3Aa)
* [Twitter](https://twitter.com/GMX_IO)
* [Substack](https://gmxio.substack.com/)
* [Telegram (English)](https://t.me/GMX_IO)
* [GitHub](https://github.com/gmx-io)
Community groups[](https://docs.gmx.io/docs/community/#community-groups "Direct link to Community groups")
------------------------------------------------------------------------------------------------------------
The following are spaces for discussion and support.
* [Telegram (Portuguese)](https://t.me/GMX_Portuguese)
* [Telegram (Chinese)](https://t.me/gmxch)
* [Telegram trading chat](https://t.me/gambittradingchat)
Media kit[](https://docs.gmx.io/docs/community/#media-kit "Direct link to Media kit")
---------------------------------------------------------------------------------------
The [GMX assets repository](https://github.com/gmx-io/gmx-assets)
contains logos for GMX and its liquidity products — including GM pools and GLV vaults — in SVG and PNG formats.
Courses[](https://docs.gmx.io/docs/community/#courses "Direct link to Courses")
---------------------------------------------------------------------------------
The [Cyfrin GMX course](https://updraft.cyfrin.io/courses/gmx-perpetuals-trading)
covers GMX protocol mechanics, token pricing, fees, and advanced features. It is sponsored by GMX and Arbitrum DAO.
* [Official channels](https://docs.gmx.io/docs/community/#official-channels)
* [Community groups](https://docs.gmx.io/docs/community/#community-groups)
* [Media kit](https://docs.gmx.io/docs/community/#media-kit)
* [Courses](https://docs.gmx.io/docs/community/#courses)
---
# Proposal Process | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/governance/proposal-process/#__docusaurus_skipToContent_fallback)
On this page
Submitting a proposal to the GMX DAO follows a structured process, outlined below:
Phase 1: Ideation[](https://docs.gmx.io/docs/governance/proposal-process/#phase-1-ideation "Direct link to Phase 1: Ideation")
--------------------------------------------------------------------------------------------------------------------------------
Phase 1 is where a proposal begins. You share your concept with the community to gather early feedback before committing to a formal document.
Post your idea on [the GMX governance forum](https://gov.gmx.io/)
using the `#idea` tag. This creates a dedicated discussion thread where community members can weigh in. Many ideas also take shape informally in Discord or Telegram before a forum post is created.
If your idea gains traction, you may use Telegram polls to gauge community endorsement for the specifications you plan to include in a future Request for Comment (RFC). This soft consensus helps you understand whether your concept is ready to advance to Phase 2.
**Duration:** Open
Phase 2: Request for Comment[](https://docs.gmx.io/docs/governance/proposal-process/#phase-2-request-for-comment "Direct link to Phase 2: Request for Comment")
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
In Phase 2, you shape your idea into a formal Request for Comment (RFC) and post it to the governance forum using the RFC template (link pending DAO approval). This invites structured community input and marks the start of the formal review process.
As you draft your RFC, incorporate community feedback and revise the proposal iteratively. The goal is to build enough endorsement to establish soft consensus, reducing the risk of rejection when the proposal advances to a formal vote.
Your RFC must follow this structure:
* Summary
* Motivation
* Rationale
* Specifications
* Conclusion
Once your RFC has addressed the community's questions and feedback, it can advance to Phase 3.
**Duration:** Open
Phase 3: Snapshot Voting[](https://docs.gmx.io/docs/governance/proposal-process/#phase-3-snapshot-voting "Direct link to Phase 3: Snapshot Voting")
-----------------------------------------------------------------------------------------------------------------------------------------------------
Once your RFC has built sufficient community support, it advances to a formal off-chain vote on [Snapshot](https://snapshot.org/#/gmx.eth/)
. Voting power is based on token balance, which gives the broader GMX community a direct voice in the outcome.
The following parameters apply:
* **Voting mechanism:** Simple majority (50% + 1 of the smallest token unit)
* **Minimum tokens to submit a proposal:** 10,000
* **Quorum:** 50,000
* **Voting window:** 5 days
If a vote passes on Snapshot but a GMX DAO delegate opposes the result, the delegate must initiate a veto proposal on Tally promptly.
Phase 4: Tally (Optional)[](https://docs.gmx.io/docs/governance/proposal-process/#phase-4-tally-optional "Direct link to Phase 4: Tally (Optional)")
------------------------------------------------------------------------------------------------------------------------------------------------------
Create a Tally proposal only when an on-chain transaction is required from the GMX DAO. Submit your proposal to [the GMX DAO on Tally](https://www.tally.xyz/gov/gmx)
for on-chain execution.
Your proposal must include a title and a clear description of its proposed actions. The following parameters apply:
* **Voting mechanism:** Qualified majority (65% + 1 of the smallest token unit)
* **Quorum:** [View current quorum on Tally](https://www.tally.xyz/gov/gmx/delegates)
* **Minimum tokens to submit a proposal:** 30,000
* **Voting delay:** 24 hours
* **Voting window:** 5 days
* **Execution delay:** 24 hours
The minimum token threshold for proposing a GIP may increase depending on voter turnout and the DAO’s total voting power.
Follow-up implementations of proposals already approved on Snapshot don’t require a new Snapshot vote.
GMX DAO delegates on Tally are expected to vote “For” proposals that have already passed the Snapshot vote, unless there is a veto proposal or a particularly strong reason to vote against.
* [Phase 1: Ideation](https://docs.gmx.io/docs/governance/proposal-process/#phase-1-ideation)
* [Phase 2: Request for Comment](https://docs.gmx.io/docs/governance/proposal-process/#phase-2-request-for-comment)
* [Phase 3: Snapshot Voting](https://docs.gmx.io/docs/governance/proposal-process/#phase-3-snapshot-voting)
* [Phase 4: Tally (Optional)](https://docs.gmx.io/docs/governance/proposal-process/#phase-4-tally-optional)
---
# Voting power | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/governance/voting-power/#__docusaurus_skipToContent_fallback)
On this page
Overview[](https://docs.gmx.io/docs/governance/voting-power/#overview "Direct link to Overview")
--------------------------------------------------------------------------------------------------
The `GMX_DAO` token is the governance token of the GMX DAO. It lets you participate directly in protocol governance through on-chain voting and delegation.
The governance system is built on three interconnected contracts: `GovToken` (an ERC-20 with on-chain vote checkpointing via ERC20Votes), `ProtocolGovernor` (an OpenZeppelin Governor contract with compatibility for the Bravo governance interface and a 3% quorum requirement), and `GovTimelockController` (a TimelockController that enforces a mandatory delay before approved proposals are executed). Together, these contracts decentralize protocol decision-making and strengthen community involvement in the GMX ecosystem.
Staking and voting power[](https://docs.gmx.io/docs/governance/voting-power/#staking-and-voting-power "Direct link to Staking and voting power")
--------------------------------------------------------------------------------------------------------------------------------------------------
To participate in GMX DAO governance, you must stake your GMX (or esGMX) tokens in the Earn section of the [GMX App](https://app.gmx.io/#/earn)
. When you stake, the `RewardRouterV2` contract mints `GMX_DAO` tokens to your address at a 1:1 ratio. These tokens carry your voting power and let you vote on proposals directly or delegate your votes to a representative.
`GMX_DAO` is a non-transferable governance token. Only the staking contract (which holds the `GOV_TOKEN_CONTROLLER` role) can mint, burn, or move `GMX_DAO` tokens — you can't transfer them freely between wallets. When you unstake your GMX or esGMX, the contract burns the corresponding `GMX_DAO` balance and you lose the associated voting power immediately.
warning
On Arbitrum, if you hold `GMX_DAO` tokens but haven't delegated them — either to yourself or to another address — the GMX App disables the Stake and Claim buttons. To restore access, delegate your tokens on [Tally](https://www.tally.xyz/gov/gmx)
before attempting these actions. This enforcement applies to Arbitrum only; the Avalanche frontend does not apply the same restriction.
note
Unstaked GMX and esGMX tokens carry no voting power. You must stake first to receive `GMX_DAO` tokens and become eligible to vote or delegate.
Nominating yourself as a delegate[](https://docs.gmx.io/docs/governance/voting-power/#nominating-yourself-as-a-delegate "Direct link to Nominating yourself as a delegate")
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
To nominate yourself as a GMX DAO delegate, complete the following steps.
1. Write a delegate statement on the [GMX Governance forum](https://gov.gmx.io/)
. Your statement serves as your application to the community — describe your experience, areas of expertise, and how you intend to contribute to the protocol.
2. Navigate to [Tally](https://www.tally.xyz/gov/gmx)
and connect your wallet. Ensure your wallet is connected to the Arbitrum network.
3. Click **My Voting Power** on the right side of the screen to open the delegation page.
4. Click **Delegate**. You'll see two options:
* **Myself** — delegates voting power to the currently connected wallet. Select this to nominate yourself as a delegate.
* **Someone else** — delegates voting power to a different wallet address. Enter the target wallet address to proceed.
5. Confirm the transaction. Once confirmed, your name appears on the GMX DAO landing page alongside other delegates.
Delegating your voting power[](https://docs.gmx.io/docs/governance/voting-power/#delegating-your-voting-power "Direct link to Delegating your voting power")
--------------------------------------------------------------------------------------------------------------------------------------------------------------
If you hold GMX tokens but can't actively participate in governance, you can delegate your voting power to a community member who votes on your behalf.
warning
When you delegate your voting power, you're entrusting another party to vote on your behalf. Choose a delegate whose values align with yours and who you trust to act in the best interest of the GMX DAO and its community.
To delegate your voting power, complete the following steps.
1. Open the [GMX App](https://app.gmx.io/#/)
and click **Earn** in the navigation menu.
2. Click **Stake** to open the staking dialog and stake your GMX tokens. Once staked, your voting power is reflected as `GMX_DAO` tokens.
3. Click **Delegate** to open the [My Voting Power page on Tally](https://www.tally.xyz/gov/gmx/my-voting-power)
.
4. Connect your wallet to Tally and ensure it's connected to the Arbitrum network.
5. Browse for a delegate: review the **Rising Delegates** section, or click **Explore all delegates** to see all available delegates.
6. Click **Delegate** next to your chosen representative to assign your voting power.
* Alternatively, click **My Voting Power** to manage delegation directly. From that page, click **Delegate** and choose **Myself** or **Someone else**. If you choose **Someone else**, enter the wallet address of your intended delegate.
7. Wait for the transaction to be confirmed on the blockchain. Delegation is complete once the transaction is confirmed.
You can update your delegation on Tally at any time.
Next steps[](https://docs.gmx.io/docs/governance/voting-power/#next-steps "Direct link to Next steps")
--------------------------------------------------------------------------------------------------------
* [Proposal process](https://docs.gmx.io/docs/governance/proposal-process/)
— learn how proposals move from ideation to on-chain vote and execution.
* [Overview](https://docs.gmx.io/docs/governance/voting-power/#overview)
* [Staking and voting power](https://docs.gmx.io/docs/governance/voting-power/#staking-and-voting-power)
* [Nominating yourself as a delegate](https://docs.gmx.io/docs/governance/voting-power/#nominating-yourself-as-a-delegate)
* [Delegating your voting power](https://docs.gmx.io/docs/governance/voting-power/#delegating-your-voting-power)
* [Next steps](https://docs.gmx.io/docs/governance/voting-power/#next-steps)
---
# GMX | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/intro/#__docusaurus_skipToContent_fallback)
On this page
GMX is a decentralized spot and perpetual exchange on Arbitrum, Avalanche, Botanix, and MegaETH. It supports perpetual trades with up to 100x leverage and token swaps with low price impact. The [GMX Account](https://docs.gmx.io/docs/trading/overview/#gmx-account-multichain)
lets you trade on GMX from any supported chain, including Ethereum, Base, and BNB. GMX uses Chainlink Data Stream oracles for accurate pricing, so liquidations occur only at fair market prices — not at momentary spread spikes.
Trading is powered by GM and GLV liquidity pools. GMX routes every order against these pools and quotes the oracle index price rather than relying on an order book or external market makers. Liquidity providers earn 63% of the fees generated from trading, liquidations, borrowing fees, and swaps on Arbitrum and Avalanche, and 50% on Botanix.
This documentation is structured for both humans and AI agents. Oracle-based pricing, deterministic execution, and comprehensive APIs support a range of use cases — whether you are a trader using the app, a developer building an integration, or an AI agent executing autonomous strategies.
Get started[](https://docs.gmx.io/docs/intro/#get-started "Direct link to Get started")
-----------------------------------------------------------------------------------------
Choose your role to find the right starting point.
* **Traders:** [Trading on GMX](https://docs.gmx.io/docs/trading/overview/)
— Open leveraged positions, place limit orders, and swap tokens.
* **Liquidity providers:** [Providing liquidity](https://docs.gmx.io/docs/providing-liquidity/)
— Earn yield by depositing into GM or GLV pools.
* **Token holders:** [GMX token](https://docs.gmx.io/docs/tokenomics/gmx-token/)
— Stake GMX to earn rewards. See also [Rewards](https://docs.gmx.io/docs/tokenomics/rewards/)
.
* **Governance:** [Voting power](https://docs.gmx.io/docs/governance/voting-power/)
— Participate in protocol governance.
* **Developers:** [API](https://docs.gmx.io/docs/api/overview/)
— Integrate with GMX contracts, REST endpoints, and the [TypeScript SDK](https://docs.gmx.io/docs/sdk/overview/)
.
* **AI agents:** [AI Agents](https://docs.gmx.io/docs/ai-agents/overview/)
— Agent [plugins, skills](https://docs.gmx.io/docs/ai-agents/plugins-and-skills/)
, and LLM-optimized documentation for building on GMX.
* [Get started](https://docs.gmx.io/docs/intro/#get-started)
---
# Providing liquidity | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/providing-liquidity/#__docusaurus_skipToContent_fallback)
On this page
GMX lets you earn yield by depositing tokens into liquidity pools. These pools back leverage trading and swaps on the platform, and liquidity providers earn the majority of the fees generated from trading, liquidations, borrow fees, and swaps (63% on Arbitrum and Avalanche, 50% on Botanix). There are two types of pools: automated GLV pools and individual GM pools.
GLV pools[](https://docs.gmx.io/docs/providing-liquidity/#glv-pools "Direct link to GLV pools")
-------------------------------------------------------------------------------------------------
A GLV (GMX Liquidity Vault) pool consists of:
* **Supported markets:** The markets in which liquidity is provided.
* **Long token:** The token that backs long positions.
* **Short token:** The token that backs short positions.
For example, a GLV \[WETH-USDC\] pool uses WETH to back long positions and USDC to back short positions. The supported markets and allowed liquidity in each market are recommended by [Chaos Labs](https://snapshot.org/#/gmx.eth/proposal/0xe5631173e5f81906e0497b6fe209ef2c72b4b8d882a0250ce0feeafb8278fb72)
.
Liquidity is automatically shifted between supported markets based on utilization and Chaos Labs recommendations. The list of supported markets displayed for each GLV can change as additional markets are approved and added.
GM pools[](https://docs.gmx.io/docs/providing-liquidity/#gm-pools "Direct link to GM pools")
----------------------------------------------------------------------------------------------
A GM (GMX Market) pool consists of:
* **Index price feed:** Positions are opened and closed based on this price feed.
* **Long token:** The token that backs long positions.
* **Short token:** The token that backs short positions.
For example, an ETH/USD \[WETH-USDC\] market uses the ETH/USD price feed, with WETH backing long positions and USDC backing short positions.
If a market is labeled as SWAP-ONLY or SPOT-ONLY, it only supports swaps and does not support leverage trading.
For single-token backed pools, both the long and short token are the same. For example, a single-token WETH pool uses WETH for both.
### Single-token vs multi-token pools[](https://docs.gmx.io/docs/providing-liquidity/#single-token-vs-multi-token-pools "Direct link to Single-token vs multi-token pools")
Single-token pools differ from multi-token pools in how they handle swaps, price impact, and asset exposure. The differences affect both liquidity providers and traders.
**For liquidity providers:**
* **Zero swap price impact on deposits and withdrawals.** In multi-token pools, depositing a single token shifts the balance between the long and short token pools, incurring swap price impact. In single-token pools, both sides of the pool are the same token, so the swap price impact factor is set to zero — deposits and withdrawals have no price impact regardless of size.
* **Single-asset exposure.** You hold one token instead of two. There is no rebalancing between different assets, so your position tracks the price of a single token rather than a mix.
* **No swaps.** Single-token pools do not support swap operations — they are used for leverage trading only.
**For traders:**
* **No swap fees on position operations.** In multi-token pools, opening or closing a position may require a swap between the collateral token and the PnL token, incurring swap fees and swap price impact. In single-token pools, collateral, PnL, and pool backing all use the same token — no token conversion is needed, so there are no swap fees or swap price impact on any position operation.
* **Reduced or zero position price impact.** The [net price impact](https://docs.gmx.io/docs/trading/fees/#price-impact-and-price-impact-rebates)
based on open interest imbalance is configured per market. The major single-token markets (BTC/USD \[WBTC.e-WBTC.e\], ETH/USD \[WETH-WETH\]) have position impact factors set to zero — meaning no position price impact at all. Smaller single-token markets may have non-zero position impact factors configured based on their liquidity depth.
Each GM pool is risk-isolated — liquidity providers are only exposed to the markets they deposit into. Profits and losses of traders in one market do not affect pools in other markets.
Market types[](https://docs.gmx.io/docs/providing-liquidity/#market-types "Direct link to Market types")
----------------------------------------------------------------------------------------------------------
GM pools back two types of markets, which differ in how the pool's tokens cover trader PnL.
### Fully backed markets[](https://docs.gmx.io/docs/providing-liquidity/#fully-backed-markets "Direct link to Fully backed markets")
In a fully backed market, the index token and the long collateral token are the same asset. For example, an ETH/USD perp market backed by an ETH-USDC pool uses ETH as both the index token and the long collateral token.
Because long position profits are paid out in ETH and the pool holds ETH directly, the pool's ETH balance can always cover the pending PnL of long positions — as long as open interest caps are respected. The protocol enforces these caps via the `MAX_OPEN_INTEREST` parameter, which is configured per market and per side.
For example, a pool holds 1,000 ETH and 1,000,000 USDC. The max long open interest is capped at 900 ETH and the max short open interest at 900,000 USDC. Under these constraints, all profits can be paid regardless of how the price of ETH moves, because the pool holds the same asset that backs the positions.
### Synthetic markets[](https://docs.gmx.io/docs/providing-liquidity/#synthetic-markets "Direct link to Synthetic markets")
In a synthetic market, the index token differs from the long collateral token. For example, a DOGE/USD perp market backed by an ETH-USDC pool uses DOGE as the index token but ETH as the long collateral. This means long position profits are denominated in DOGE price terms but paid out from the pool's ETH balance.
If DOGE's price rises faster than ETH's price, the pending profits of DOGE long positions — measured in USD — can grow faster than the USD value of ETH in the pool. In extreme cases, pending profits may exceed the pool's capacity to pay them out.
For example, a pool holds 1,000 ETH and 1,000,000 USDC. The max DOGE long open interest is capped at 300 ETH worth. If DOGE increases 10x while ETH increases only 2x, the pending USD profits of DOGE longs outpace the USD value of the ETH backing them, and the pool may not be able to cover all profits.
Buying GLV / GM tokens[](https://docs.gmx.io/docs/providing-liquidity/#buying-glv--gm-tokens "Direct link to Buying GLV / GM tokens")
---------------------------------------------------------------------------------------------------------------------------------------
You can buy GLV / GM tokens on the [GLV / GM pools](https://app.gmx.io/#/pools)
page. ETH or AVAX is required to send the buy transaction. If you need to bridge funds, you can use [Jumper Exchange](https://jumper.exchange/)
.
To buy tokens:
1. Select the "Market" and "Pool" of the GLV / GM token you want to purchase.
2. Review the price impact displayed in the "Buy GLV / GM" box. Your purchase has a positive or negative price impact depending on whether it improves or reduces the balance of tokens in the pool.
3. If the pool is mostly balanced, a large purchase may result in a significant negative price impact. To avoid this, select the "Pair" option to buy with an equal USD amount of long and short tokens.
Selling GLV / GM tokens[](https://docs.gmx.io/docs/providing-liquidity/#selling-glv--gm-tokens "Direct link to Selling GLV / GM tokens")
------------------------------------------------------------------------------------------------------------------------------------------
You can sell GLV / GM tokens on the [GLV / GM pools](https://app.gmx.io/#/pools)
page.
Tokens in a market are reserved based on the total open interest. The reserve factor determines how much of the pool can be committed to backing positions:
available liquidity = (pool tokens × reserve factor) − reserved tokens
Where **reserved tokens** are tokens already committed to cover open positions. The reserve factor is a per-market parameter (typically between 0.5 and 0.95) that prevents the pool from being fully drained by trader positions.
Additionally, each market has `MAX_OPEN_INTEREST` caps per side (long/short) and `MAX_POOL_AMOUNT` caps that limit total deposits. These parameters ensure the pool can always cover trader profits under normal conditions.
If the available liquidity for redemption reaches zero, you need to wait for positions to close or for other providers to deposit liquidity before you can sell. The borrow fee rate is also higher in this case, which helps incentivize new deposits.
Shifting GM tokens[](https://docs.gmx.io/docs/providing-liquidity/#shifting-gm-tokens "Direct link to Shifting GM tokens")
----------------------------------------------------------------------------------------------------------------------------
You can shift GM tokens on the [GM pools](https://app.gmx.io/#/pools)
page.
GM tokens can only be shifted to another pool that has the same backing tokens, which lets you move liquidity without incurring buy or sell fees. Price impact still applies to shifts, but for balanced pools it is minimal. Price impact costs are displayed on the interface as usual.
Token pricing[](https://docs.gmx.io/docs/providing-liquidity/#token-pricing "Direct link to Token pricing")
-------------------------------------------------------------------------------------------------------------
The price of a GM token is:
GM token price = (pool value + net pending PnL) / GM totalSupply
Where **pool value** includes the USD worth of deposited long and short tokens plus accumulated borrowing fees, and **net pending PnL** is the aggregate unrealized profit/loss of all open trader positions in the market.
The pending PnL component is capped using the `MAX_PNL_FACTOR` parameter, which has separate values for deposits, withdrawals, and trader position closures. This capping prevents extreme trader profits from fully draining pool value during a single deposit or withdrawal. GLV token prices follow the same principle, aggregated across all underlying GM markets in the vault.
Fees from trading, swaps, borrowing, and liquidations flow directly into the pool, increasing pool value and therefore the GM token price over time. There is no separate claim or distribution step — holding GM tokens is enough to earn fees. On Arbitrum and Avalanche, 63% of collected fees go to the pool and 37% go to the protocol. On Botanix the split is 50/50. You can check the current annualized performance for each pool on the [Pools](https://app.gmx.io/#/pools)
page.
Some long and short tokens may have a spread, which results in a corresponding spread when buying or selling GLV / GM tokens.
GLV / GM pools aim to maintain an equal worth of long and short tokens. When the price of a long token increases, there may be a positive price impact to incentivize selling long tokens for short tokens, rebalancing the pool. While this balancing is incentivized, pools may not always be perfectly balanced. If a pool maintains its balance, its pricing (excluding PnL) mimics a portfolio that is 50% long token and 50% short token, rebalancing as prices change.
Performance APY calculation[](https://docs.gmx.io/docs/providing-liquidity/#performance-apy-calculation "Direct link to Performance APY calculation")
-------------------------------------------------------------------------------------------------------------------------------------------------------
The annualized performance APY for GM and GLV tokens measures the excess return compared to a benchmark strategy of holding the underlying tokens in a geometric mean portfolio.
### Variable definitions[](https://docs.gmx.io/docs/providing-liquidity/#variable-definitions "Direct link to Variable definitions")
| Variable | Definition |
| --- | --- |
| `TokenA_S` | Token A starting price |
| `TokenB_S` | Token B starting price |
| `TokenA_E` | Token A ending price |
| `TokenB_E` | Token B ending price |
| `GM_S` | GM token starting price |
| `GM_E` | GM token ending price |
| `Benchmark_S` | Benchmark investment starting price (equals `GM_S`) |
| `Benchmark_E` | Benchmark investment ending price |
| `duration` | Number of days in the measurement period |
### Calculation steps[](https://docs.gmx.io/docs/providing-liquidity/#calculation-steps "Direct link to Calculation steps")
**Step 1: Calculate benchmark ending price**
The benchmark represents a geometric mean portfolio of the underlying tokens:
Benchmark_E = GM_S × √((TokenA_E × TokenB_E) / (TokenA_S × TokenB_S))
**Step 2: Calculate annualized performance**
The annualized performance APY is the excess return of GM compared to the benchmark, annualized:
Annualized Performance (%) = ((GM_E - Benchmark_E) / GM_S) × 100 × (365 / duration)
Worked example
Given:
* `TokenA_S` = $100, `TokenA_E` = $110
* `TokenB_S` = $200, `TokenB_E` = $190
* `GM_S` = $141.42, `GM_E` = $144.57
* `duration` = 30 days
**Benchmark calculation:**
Benchmark_E = 141.42 × √((110 × 190) / (100 × 200)) = 141.42 × √(20,900 / 20,000) = 141.42 × √1.045 = 141.42 × 1.0222 = 144.56
**Performance calculation:**
Annualized Performance = ((144.57 - 144.56) / 141.42) × 100 × (365 / 30) = (0.01 / 141.42) × 100 × 12.167 = 0.000071 × 100 × 12.167 = 0.086%
Protocol protections[](https://docs.gmx.io/docs/providing-liquidity/#protocol-protections "Direct link to Protocol protections")
----------------------------------------------------------------------------------------------------------------------------------
GMX uses multiple layered mechanisms to keep pools solvent and markets balanced. Each is documented in detail on its respective page.
* **[Price impact](https://docs.gmx.io/docs/trading/fees/#price-impact-and-price-impact-rebates)
** — Trades that increase the open interest imbalance pay a price impact fee; trades that reduce it receive a better price. Per-market caps limit the maximum impact.
* **[Adaptive funding](https://docs.gmx.io/docs/trading/fees/#adaptive-funding)
** — The dominant side (longs or shorts) pays the minority side. The rate increases over time while the imbalance persists and decreases as it resolves.
* **[Borrow fees](https://docs.gmx.io/docs/trading/fees/#borrow-fees)
** — Only the side with larger open interest pays. Uses a kink rate model — the rate increases linearly up to an optimal utilization threshold, then rises steeply above it.
* **[Open interest caps](https://docs.gmx.io/docs/providing-liquidity/#selling-glv--gm-tokens)
** — Each market has per-side `MAX_OPEN_INTEREST` limits that prevent any single market from over-committing pool liquidity.
* **[Reserve factor](https://docs.gmx.io/docs/providing-liquidity/#selling-glv--gm-tokens)
** — Limits how much of the pool can be committed to backing positions, ensuring liquidity remains available for redemptions.
* **[PnL factor caps](https://docs.gmx.io/docs/providing-liquidity/#token-pricing)
** — `MAX_PNL_FACTOR` limits how much pending trader PnL can affect pool value during deposits, withdrawals, and position closures.
* **[Auto-Deleveraging (ADL)](https://docs.gmx.io/docs/trading/liquidations/#auto-deleveraging-adl)
** — Automatically reduces profitable positions when the PnL-to-pool ratio exceeds the market's configured threshold, protecting pool solvency.
* **[Two-phase execution](https://docs.gmx.io/docs/api/contracts/architecture/#execution-model)
** — Orders are committed on-chain before oracle prices are included, preventing frontrunning and sandwich attacks.
* **[Virtual inventory](https://docs.gmx.io/docs/api/contracts/known-issues/#virtual-inventory)
** — Tracks impact across correlated markets to prevent users from reducing their net price impact by opening opposing positions in different markets.
* **[Price impact rebates](https://docs.gmx.io/docs/trading/fees/#price-impact-and-price-impact-rebates)
** — Excess negative price impact beyond a market's cap is claimable as a rebate after a five-day delay, protecting traders from outsized impact during volatile periods.
Risks[](https://docs.gmx.io/docs/providing-liquidity/#risks "Direct link to Risks")
-------------------------------------------------------------------------------------
warning
Smart contracts carry inherent risk. The team mitigates risks through testing, audits, and bug bounties, but vulnerabilities in smart contract code are always possible. For details on contract operation, see [Contracts](https://docs.gmx.io/docs/api/contracts/overview/)
.
A non-exhaustive list of risks:
* **Smart contract risks:** Vulnerabilities in smart contract code despite testing and audits.
* **Counterparty risks:** The GLV / GM pool is the counterparty to traders. If traders profit, that profit comes from the value of the GLV / GM pool.
* **Token risks:** Bridged tokens depend on the security of the bridge, and pegged tokens carry the risk of depegging.
* **Open interest imbalance:** While funding fees and price impact incentivize balanced long and short open interest, positions may not always be balanced. For example, if long positions are balanced against high-leverage short positions and a sudden price spike occurs, the short positions could be liquidated, temporarily creating an imbalance.
* **GLV shift exploitation:** The GLV shift feature rebalances liquidity between markets based on utilization. An attacker could temporarily inflate utilization in a low-utilization market to trigger a shift, then reverse the position. Position fees and price impact are configured to make this costly.
* **GLV illiquid GM tokens:** GM tokens in a GLV can become illiquid due to high PnL factor or high reserved USD. Users could deposit illiquid GM tokens into a GLV and withdraw liquidity from a different market, leaving the GLV holding illiquid tokens. The `glvMaxMarketTokenBalanceUsd` and `glvMaxMarketTokenBalanceAmount` parameters limit exposure to risky markets.
* **GLV negative market value:** If the value of a GM market within a GLV becomes negative, the GLV may be unusable until that market's value recovers.
### Hedging open interest imbalance[](https://docs.gmx.io/docs/providing-liquidity/#hedging-open-interest-imbalance "Direct link to Hedging open interest imbalance")
For liquidity providers that hedge the difference between long and short open interest, the relevant difference is between the long and short `openInterestInTokens` values multiplied by the current index token price (notional value), not the difference in `openInterest` USD values recorded at position entry. Funding rates and borrow fees use this same notional-based comparison to incentivize balanced long and short open interest.
Next steps[](https://docs.gmx.io/docs/providing-liquidity/#next-steps "Direct link to Next steps")
----------------------------------------------------------------------------------------------------
* [Trade on GMX](https://docs.gmx.io/docs/trading/overview/)
— Open leveraged positions using pool liquidity.
* [Contracts](https://docs.gmx.io/docs/api/contracts/overview/)
— Review smart contract details.
* [GLV / GM pools app](https://app.gmx.io/#/pools)
— Start providing liquidity.
* [GLV pools](https://docs.gmx.io/docs/providing-liquidity/#glv-pools)
* [GM pools](https://docs.gmx.io/docs/providing-liquidity/#gm-pools)
* [Single-token vs multi-token pools](https://docs.gmx.io/docs/providing-liquidity/#single-token-vs-multi-token-pools)
* [Market types](https://docs.gmx.io/docs/providing-liquidity/#market-types)
* [Fully backed markets](https://docs.gmx.io/docs/providing-liquidity/#fully-backed-markets)
* [Synthetic markets](https://docs.gmx.io/docs/providing-liquidity/#synthetic-markets)
* [Buying GLV / GM tokens](https://docs.gmx.io/docs/providing-liquidity/#buying-glv--gm-tokens)
* [Selling GLV / GM tokens](https://docs.gmx.io/docs/providing-liquidity/#selling-glv--gm-tokens)
* [Shifting GM tokens](https://docs.gmx.io/docs/providing-liquidity/#shifting-gm-tokens)
* [Token pricing](https://docs.gmx.io/docs/providing-liquidity/#token-pricing)
* [Performance APY calculation](https://docs.gmx.io/docs/providing-liquidity/#performance-apy-calculation)
* [Variable definitions](https://docs.gmx.io/docs/providing-liquidity/#variable-definitions)
* [Calculation steps](https://docs.gmx.io/docs/providing-liquidity/#calculation-steps)
* [Protocol protections](https://docs.gmx.io/docs/providing-liquidity/#protocol-protections)
* [Risks](https://docs.gmx.io/docs/providing-liquidity/#risks)
* [Hedging open interest imbalance](https://docs.gmx.io/docs/providing-liquidity/#hedging-open-interest-imbalance)
* [Next steps](https://docs.gmx.io/docs/providing-liquidity/#next-steps)
---
# SDK Overview | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/sdk/overview/#__docusaurus_skipToContent_fallback)
On this page
The GMX SDK (`@gmx-io/sdk`) is a TypeScript library for integrating GMX perpetuals and spot trading into your application. It wraps the GMX smart contracts and data APIs into a typed interface, letting you read market data, compute fees, and submit orders without managing low-level contract calls directly.
The SDK runs in Node.js (>=18) and browser environments.
SDK v1 and v2[](https://docs.gmx.io/docs/sdk/overview/#sdk-v1-and-v2 "Direct link to SDK v1 and v2")
------------------------------------------------------------------------------------------------------
The SDK ships two clients. Choose based on your integration needs:
Install both clients from the same package: `npm install @gmx-io/sdk`. The SDK v2 import path is `@gmx-io/sdk/v2`, but `@gmx-io/sdk/v2` is not a separate npm package.
| | SDK v1 — `GmxSdk` | SDK v2 — `GmxApiSdk` |
| --- | --- | --- |
| **Import** | `import { GmxSdk } from "@gmx-io/sdk"` | `import { GmxApiSdk } from "@gmx-io/sdk/v2"` |
| **Requires** | RPC + Oracle URL + Subsquid URL | Chain ID only |
| **Capabilities** | Full (read + write) | Read-only HTTP client (markets, tickers, tokens, pairs, rates, APY, performance, positions, orders, OHLCV, buyback, staking) |
| **Status** | Current full client | Expanding to cover the full SDK surface |
note
SDK v2 (`GmxApiSdk`) is under active development and will expand over time, replacing the need for direct RPC, oracle, and Subsquid connections. It wraps the [API v2 (OpenAPI Reference)](https://docs.gmx.io/docs/category/api-v2-openapi-reference/)
.
* **[SDK v1 — Getting Started](https://docs.gmx.io/docs/sdk/v1/)
** — Full client for read and write operations
* **[SDK v1 — Integration guide](https://docs.gmx.io/docs/sdk/v1/integration-guide/)
** — End-to-end workflows and operational guidance
* **[SDK v1 — Troubleshooting](https://docs.gmx.io/docs/sdk/v1/troubleshooting/)
** — Receipt handling, duplicate-submit protection, stale reads, and simulation caveats
* **[SDK v2 — Getting Started](https://docs.gmx.io/docs/sdk/v2/)
** — Read-only API client for TypeScript integrations
If you are starting a new integration, read the workflow page before the reference pages. Use SDK v1 when you need writes or direct RPC-backed reads. Use SDK v2 when you only need read-only HTTP access.
Operational differences[](https://docs.gmx.io/docs/sdk/overview/#operational-differences "Direct link to Operational differences")
------------------------------------------------------------------------------------------------------------------------------------
| Topic | SDK v1 — `GmxSdk` | SDK v2 — `GmxApiSdk` |
| --- | --- | --- |
| Data sources | RPC, oracle, and Subsquid | GMX HTTP API |
| Trade history | ✅ | ❌ |
| Order submission and cancellation | ✅ | ❌ |
| Built-in HTTP retries | ❌ Default viem transports use `retryCount: 0` | ❌ Current HTTP client does not add retry or fallback logic |
| Built-in transaction receipt waiting | ❌ | Not applicable |
| Idempotency keys | ❌ | Not applicable |
Available now[](https://docs.gmx.io/docs/sdk/overview/#available-now "Direct link to Available now")
------------------------------------------------------------------------------------------------------
* SDK v1 is the current full client.
* SDK v2 exposes `fetchMarketsInfo`, `fetchMarkets`, `fetchMarketsTickers`, `fetchTokensData`, `fetchTokens`, `fetchPairs`, `fetchRates`, `fetchApy`, `fetchPerformanceAnnualized`, `fetchPerformanceSnapshots`, `fetchPositionsInfo`, `fetchOrders`, `fetchOhlcv`, `fetchBuybackWeeklyStats`, and `fetchStakingPower`.
* Use SDK v1 if your integration needs writes or trade history today.
Supported networks[](https://docs.gmx.io/docs/sdk/overview/#supported-networks "Direct link to Supported networks")
---------------------------------------------------------------------------------------------------------------------
The SDK supports the following production networks:
| Network | Chain ID |
| --- | --- |
| Arbitrum | 42161 |
| Avalanche | 43114 |
| Botanix | 3637 |
| MegaETH | 4326 |
**Repository:** [github.com/gmx-io/gmx-interface/sdk](https://github.com/gmx-io/gmx-interface/tree/master/sdk)
Installation[](https://docs.gmx.io/docs/sdk/overview/#installation "Direct link to Installation")
---------------------------------------------------------------------------------------------------
Install the SDK using your preferred package manager:
# npmnpm install @gmx-io/sdk# yarnyarn add @gmx-io/sdk
Both SDK clients ship in this package. Import `GmxSdk` from `@gmx-io/sdk` and `GmxApiSdk` from `@gmx-io/sdk/v2`.
The package supports both ESM and CommonJS. CommonJS consumers can use `require("@gmx-io/sdk")` for v1 and `require("@gmx-io/sdk/v2")` for v2. TypeScript subpath resolution is supported for the SDK's root, client, utility, config, ABI, and type-only entrypoints.
note
The current release is `1.5.0-alpha-8`. The API may change before a stable release.
The SDK requires Node.js 18 or later.
* [SDK v1 and v2](https://docs.gmx.io/docs/sdk/overview/#sdk-v1-and-v2)
* [Operational differences](https://docs.gmx.io/docs/sdk/overview/#operational-differences)
* [Available now](https://docs.gmx.io/docs/sdk/overview/#available-now)
* [Supported networks](https://docs.gmx.io/docs/sdk/overview/#supported-networks)
* [Installation](https://docs.gmx.io/docs/sdk/overview/#installation)
---
# Getting Started | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/sdk/v2/#__docusaurus_skipToContent_fallback)
On this page
If you only need read-only HTTP data without RPC calls, use the read-only API client:
Install the shared SDK package first:
npm install @gmx-io/sdk
Then import the read-only client from the `v2` subpath:
import { GmxApiSdk } from "@gmx-io/sdk/v2";const apiSdk = new GmxApiSdk({ chainId: 42161 }); // Arbitrumconst markets = await apiSdk.fetchMarkets();const marketsInfo = await apiSdk.fetchMarketsInfo();const tickers = await apiSdk.fetchMarketsTickers({ symbols: ["BTC/USD"],});const tokens = await apiSdk.fetchTokens();const tokensData = await apiSdk.fetchTokensData();const pairs = await apiSdk.fetchPairs();const rates = await apiSdk.fetchRates({ period: "7d" });const apy = await apiSdk.fetchApy({ period: "7d" });const annualized = await apiSdk.fetchPerformanceAnnualized({ period: "30d",});const snapshots = await apiSdk.fetchPerformanceSnapshots({ period: "30d",});const positions = await apiSdk.fetchPositionsInfo({ address: "0x9f7198eb1b9Ccc0Eb7A07eD228d8FbC12963ea33", includeRelatedOrders: true,});const orders = await apiSdk.fetchOrders({ address: "0x9f7198eb1b9Ccc0Eb7A07eD228d8FbC12963ea33",});const candles = await apiSdk.fetchOhlcv({ symbol: "BTC/USD", timeframe: "1h", limit: 100,});
`GmxApiSdk` calls the GMX REST API directly — no RPC endpoint, oracle URL, or Subsquid URL required. It supports Arbitrum, Avalanche, and Arbitrum Sepolia. The constructor throws for unsupported chains.
`@gmx-io/sdk/v2` is an import path inside the `@gmx-io/sdk` package, not a separate npm package.
If you're using CommonJS, require the v2 client from the `v2` subpath:
const { GmxApiSdk } = require("@gmx-io/sdk/v2");const apiSdk = new GmxApiSdk({ chainId: 42161 });
TypeScript subpath resolution is supported for `@gmx-io/sdk/v2` and the SDK's utility, config, ABI, and type-only entrypoints.
What SDK v2 covers today[](https://docs.gmx.io/docs/sdk/v2/#what-sdk-v2-covers-today "Direct link to What SDK v2 covers today")
---------------------------------------------------------------------------------------------------------------------------------
| Workflow | Status | Notes |
| --- | --- | --- |
| Read market catalogs, tickers, and token data over HTTP | ✅ | Available through `fetchMarkets()`, `fetchMarketsInfo()`, `fetchMarketsTickers()`, `fetchTokens()`, and `fetchTokensData()` |
| Read pairs, rates, APY, and performance analytics over HTTP | ✅ | Available through `fetchPairs()`, `fetchRates()`, `fetchApy()`, `fetchPerformanceAnnualized()`, and `fetchPerformanceSnapshots()` |
| Read one account's positions and orders over HTTP | ✅ | Available through `fetchPositionsInfo()` and `fetchOrders()` |
| Read OHLCV candles over HTTP | ✅ | Available through `fetchOhlcv()` |
| Read protocol buyback stats over HTTP | ✅ | Available through `fetchBuybackWeeklyStats()` |
| Read staking power over HTTP | ✅ | Available through `fetchStakingPower()` |
| Submit or cancel orders | ❌ | Use [SDK v1](https://docs.gmx.io/docs/sdk/v1/)
or direct contracts |
| Trade history reads | ❌ | Use [SDK v1](https://docs.gmx.io/docs/sdk/v1/)
or [GraphQL](https://docs.gmx.io/docs/api/graphql/) |
Use [SDK Overview](https://docs.gmx.io/docs/sdk/overview/)
if you want a quick capability comparison before wiring an integration.
Methods[](https://docs.gmx.io/docs/sdk/v2/#methods "Direct link to Methods")
------------------------------------------------------------------------------
`GmxApiSdk` exposes the following methods. All of them call the GMX REST API directly -- no RPC, oracle, or Subsquid connection is required.
| Method | Parameters | Returns | Notes |
| --- | --- | --- | --- |
| `fetchMarkets()` | \-- | `MarketWithTiers[]` | Market catalog data from `/markets` |
| `fetchMarketsInfo()` | \-- | `RawMarketInfo[]` | Market definitions and pricing from `/markets/info` |
| `fetchMarketsTickers(params?)` | `addresses?: string[]`, `symbols?: string[]` | `MarketTicker[]` | Filterable market tickers from `/markets/tickers` |
| `fetchTokens()` | \-- | `Token[]` | Static token catalog from `/tokens` |
| `fetchTokensData()` | \-- | `TokenData[]` | Token metadata and current prices from `/tokens/info` |
| `fetchPairs()` | \-- | `Pair[]` | Pair-level summary data from `/pairs` |
| `fetchRates(params?)` | `period?: ApiParameterPeriod`, \`averageBy?: "1d" | "7d" | "30d"`,` address?: string\` |
| `fetchApy(params?)` | `period?: ApiParameterPeriod` | `ApyResponse` | Market and GLV APY data from `/apy` |
| `fetchPerformanceAnnualized(params?)` | `period?: ApiParameterPeriod`, `address?: string` | `PerformanceAnnualized[]` | Annualized performance summaries from `/performance/annualized` |
| `fetchPerformanceSnapshots(params?)` | `period?: ApiParameterPeriod`, `address?: string` | `PerformanceSnapshots[]` | Historical performance snapshot series from `/performance/snapshots` |
| `fetchPositionsInfo(params)` | `address: string`, `includeRelatedOrders?: boolean` | `ApiPositionInfo[]` | Position objects for an address; optionally includes related orders |
| `fetchOrders(params)` | `address: string` | `ApiOrderInfo[]` | Active order objects for an address |
| `fetchOhlcv(params)` | `symbol: string`, `timeframe: string`, `limit?: number`, `since?: number` | `OhlcvCandle[]` | OHLCV candle data from `/prices/ohlcv` |
| `fetchBuybackWeeklyStats()` | \-- | `BuybackWeeklyStatsResponse` | Weekly buyback accrual data and cumulative summary from `/buyback/weekly-stats` |
| `fetchStakingPower(params)` | `address: string` | `StakingPowerResponse` | Staking power, loyalty ratio, and reward share data for an address from `/staking/power` |
### Staking power timestamps[](https://docs.gmx.io/docs/sdk/v2/#staking-power-timestamps "Direct link to Staking power timestamps")
`StakingPowerResponse` includes two protocol-level timestamps that are constant across all addresses:
| Field | Type | Description |
| --- | --- | --- |
| `powerAccrualStart` | unix seconds | The moment power began accumulating for staked GMX. Set to `1772582400` (March 4, 2026 00:00:00 UTC). |
| `loyaltyTrackingStart` | unix seconds | The moment loyalty tracking became active. Before this time, unstaking did not affect the historical peak used for loyalty enforcement. Set to `1774396800` (March 25, 2026 00:00:00 UTC). |
After `loyaltyTrackingStart`, if an account's staked balance drops below 80% of its historical peak, accumulated power resets to zero. See [Rewards](https://docs.gmx.io/docs/tokenomics/rewards/#loyalty-threshold)
for the user-facing description of how the loyalty threshold works.
When to use SDK v2[](https://docs.gmx.io/docs/sdk/v2/#when-to-use-sdk-v2 "Direct link to When to use SDK v2")
---------------------------------------------------------------------------------------------------------------
Use `GmxApiSdk` for read-only API integrations that need market, ticker, token, pair, rate, APY, performance, position, order, OHLCV, buyback, or staking-power data without requiring RPC or oracle connections. Use the full [`GmxSdk` (SDK v1)](https://docs.gmx.io/docs/sdk/v1/)
when you need trade history or write operations such as submitting or cancelling orders.
note
`GmxApiSdk` is under active development and will expand to cover the full SDK surface over time, replacing the need for direct RPC, oracle, and Subsquid connections. The [OpenAPI Reference](https://docs.gmx.io/docs/category/api-v2-openapi-reference/)
documents most of the underlying REST API that `GmxApiSdk` wraps, but the checked-in generated reference does not yet list the staking or buyback endpoints exposed through `fetchStakingPower()` and `fetchBuybackWeeklyStats()`.
* [What SDK v2 covers today](https://docs.gmx.io/docs/sdk/v2/#what-sdk-v2-covers-today)
* [Methods](https://docs.gmx.io/docs/sdk/v2/#methods)
* [Staking power timestamps](https://docs.gmx.io/docs/sdk/v2/#staking-power-timestamps)
* [When to use SDK v2](https://docs.gmx.io/docs/sdk/v2/#when-to-use-sdk-v2)
---
# Security | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/security/#__docusaurus_skipToContent_fallback)
On this page
This page covers general safety practices, audit reports, and the bug bounty program.
General safety[](https://docs.gmx.io/docs/security/#general-safety "Direct link to General safety")
-----------------------------------------------------------------------------------------------------
Exercise caution when interacting with any smart contract or blockchain application. Although the GMX team mitigates risk through rigorous testing, independent audits, and an active bug bounty program, smart contract code can contain vulnerabilities that remain undetected even after review.
Keep the following points in mind:
* [Phishing](https://en.wikipedia.org/wiki/Phishing)
attacks and scams are prevalent in both traditional and blockchain contexts.
* Blockchain-specific phishing techniques include tricking users into revealing private keys or seed phrases, or into signing malicious transactions.
* Consider maintaining two separate wallets — one to store the majority of your holdings (a "cold" wallet with minimal dApp exposure), and a separate wallet for interacting with new or unfamiliar websites.
* Before signing any transaction, verify the target contract address and review the operation being signed. Most wallets display the operation name and contract details to assist with this.
* Only interact with the official GMX interface and verified contract addresses listed in the [contracts](https://docs.gmx.io/docs/api/contracts/overview/)
page.
Audits[](https://docs.gmx.io/docs/security/#audits "Direct link to Audits")
-----------------------------------------------------------------------------
Audit reports for GMX V2 contracts are available in the [gmx-synthetics repository](https://github.com/gmx-io/gmx-synthetics/tree/updates/audits)
. The following firms have conducted audits:
* **Guardian** — Primary auditor for GMX. Conducted 8 engagements between October 2022 and September 2023, totalling 88 person-weeks and resulting in the remediation or acknowledgement of 365 findings across the full severity range. Guardian continues to audit all smart contract updates, with additional engagements through 2024, 2025, and 2026 covering GLV, buybacks, pro tiers, gasless calls, cross-chain V2.2, fee automations, and subsequent protocol changes.
* **ABDK** — Audited the GMX Synthetics contracts at a specific commit.
* **Certora** — Audited GMX Synthetics (November 2023).
* **Dedaub** — Audited GMX Synthetics.
* **Sherlock** — Audited GMX Synthetics updates.
Bug bounty[](https://docs.gmx.io/docs/security/#bug-bounty "Direct link to Bug bounty")
-----------------------------------------------------------------------------------------
GMX maintains an active bug bounty program covering all repositories under [github.com/gmx-io](https://github.com/gmx-io)
. Full program details, scope, and reward tiers are available on the [GMX Immunefi](https://immunefi.com/bounty/gmx/)
page.
* [General safety](https://docs.gmx.io/docs/security/#general-safety)
* [Audits](https://docs.gmx.io/docs/security/#audits)
* [Bug bounty](https://docs.gmx.io/docs/security/#bug-bounty)
---
# Troubleshooting | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/sdk/v1/troubleshooting/#__docusaurus_skipToContent_fallback)
On this page
Use this page when SDK v1 reads or writes do not behave the way you expect. Most production issues fall into one of five buckets: missing receipt handling, stale follow-up reads, duplicate submits, transport failures, or workflow assumptions that belong to SDK v2 or GraphQL instead.
The SDK returned a transaction hash, but my UI is still pending[](https://docs.gmx.io/docs/sdk/v1/troubleshooting/#the-sdk-returned-a-transaction-hash-but-my-ui-is-still-pending "Direct link to The SDK returned a transaction hash, but my UI is still pending")
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
That is expected. SDK v1 order methods submit the transaction and return the hash. They do not wait for the receipt for you.
Recommended pattern:
1. Persist the transaction hash as soon as you receive it.
2. Wait for the receipt with `sdk.publicClient.waitForTransactionReceipt`.
3. Only after the receipt succeeds should you start polling positions, orders, or trade history.
If the client reloads before confirmation, recover from the saved transaction hash instead of resubmitting.
The transaction succeeded, but the order or position is not visible yet[](https://docs.gmx.io/docs/sdk/v1/troubleshooting/#the-transaction-succeeded-but-the-order-or-position-is-not-visible-yet "Direct link to The transaction succeeded, but the order or position is not visible yet")
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Treat follow-up reads as eventually consistent.
* Transaction inclusion, order creation, keeper execution, and indexed history do not complete at the same time.
* `orders.getOrders()` shows active on-chain orders, but trade history comes from Subsquid and can lag behind live chain state.
* If you need a coherent account snapshot, refresh one `marketsInfoData` and `tokensData` snapshot and reuse it across position and order reads.
I accidentally submitted the same action twice[](https://docs.gmx.io/docs/sdk/v1/troubleshooting/#i-accidentally-submitted-the-same-action-twice "Direct link to I accidentally submitted the same action twice")
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SDK v1 does not support idempotency keys or client order IDs.
Recommended client behavior:
1. Disable repeat submit actions while a transaction is pending.
2. Persist the last in-flight transaction hash per user action.
3. Require an explicit retry action after a failure instead of auto-resubmitting writes.
Cancel or replace shows unexpected order state[](https://docs.gmx.io/docs/sdk/v1/troubleshooting/#cancel-or-replace-shows-unexpected-order-state "Direct link to Cancel or replace shows unexpected order state")
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
This is usually a race between an old UI snapshot and current on-chain order keys.
* Refetch active orders immediately before calling `cancelOrders`.
* Cancel by the latest on-chain order keys, not by cached UI state from an earlier poll.
* After cancel or replace, refetch orders again instead of assuming the previous list is still valid.
Read calls fail with timeouts or transient RPC errors[](https://docs.gmx.io/docs/sdk/v1/troubleshooting/#read-calls-fail-with-timeouts-or-transient-rpc-errors "Direct link to Read calls fail with timeouts or transient RPC errors")
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
The default SDK-created viem transports set `retryCount: 0`, and SDK multicalls use a `40000` ms timeout.
Recommended client behavior:
1. Add retry and backoff around safe read paths.
2. Keep write submission separate from read retries so you do not duplicate transactions.
3. Consider supplying your own viem clients if you need a custom transport strategy.
If you inject a custom viem `publicClient`, make sure it includes `BATCH_CONFIGS` from `@gmx-io/sdk/configs/batch`. The SDK-created default clients already do this for you, but custom clients do not inherit it automatically.
Without the SDK batch config, large GMX multicalls may be fragmented into many smaller requests instead of one client-side multicall. Common symptoms include unexpectedly high RPC request counts, public RPC rate limits, and browser-side transport failures during otherwise normal read or order-helper flows.
A limit order did not simulate before submit[](https://docs.gmx.io/docs/sdk/v1/troubleshooting/#a-limit-order-did-not-simulate-before-submit "Direct link to A limit order did not simulate before submit")
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
That can be current behavior, not necessarily a bug.
* Market increases simulate by default unless you opt out.
* Limit increases skip simulation in the current implementation.
* Market swaps simulate by default, while `Limit Swap` orders do not.
* `createDecreaseOrder()` currently skips simulation.
If your UI exposes these flows, validate inputs before submission and surface chain-level errors clearly.
Next steps[](https://docs.gmx.io/docs/sdk/v1/troubleshooting/#next-steps "Direct link to Next steps")
-------------------------------------------------------------------------------------------------------
* Use the [Integration guide](https://docs.gmx.io/docs/sdk/v1/integration-guide/)
for exact SDK v1 workflows.
* Use [Getting Started](https://docs.gmx.io/docs/sdk/v1/)
for constructor and module reference.
* Use [SDK Overview](https://docs.gmx.io/docs/sdk/overview/)
when you need to choose between SDK v1 and SDK v2.
* [The SDK returned a transaction hash, but my UI is still pending](https://docs.gmx.io/docs/sdk/v1/troubleshooting/#the-sdk-returned-a-transaction-hash-but-my-ui-is-still-pending)
* [The transaction succeeded, but the order or position is not visible yet](https://docs.gmx.io/docs/sdk/v1/troubleshooting/#the-transaction-succeeded-but-the-order-or-position-is-not-visible-yet)
* [I accidentally submitted the same action twice](https://docs.gmx.io/docs/sdk/v1/troubleshooting/#i-accidentally-submitted-the-same-action-twice)
* [Cancel or replace shows unexpected order state](https://docs.gmx.io/docs/sdk/v1/troubleshooting/#cancel-or-replace-shows-unexpected-order-state)
* [Read calls fail with timeouts or transient RPC errors](https://docs.gmx.io/docs/sdk/v1/troubleshooting/#read-calls-fail-with-timeouts-or-transient-rpc-errors)
* [A limit order did not simulate before submit](https://docs.gmx.io/docs/sdk/v1/troubleshooting/#a-limit-order-did-not-simulate-before-submit)
* [Next steps](https://docs.gmx.io/docs/sdk/v1/troubleshooting/#next-steps)
---
# GMX token | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/tokenomics/gmx-token/#__docusaurus_skipToContent_fallback)
On this page
GMX is the platform's utility and governance token. Staking GMX earns you a share of protocol fees — 27% of fees from leverage trading, liquidations, borrowing fees, and swaps are used to buy back GMX. Distribution of bought-back GMX is currently suspended; see [Staking](https://docs.gmx.io/docs/tokenomics/gmx-token/#staking)
for details. For more on fee distribution, see [Fees](https://docs.gmx.io/docs/trading/fees/)
. GMX also grants [voting power](https://docs.gmx.io/docs/governance/voting-power/)
in protocol governance.
Escrowed GMX (esGMX) has historically been distributed as a staking and referral incentive. Learn more about esGMX on the [Rewards](https://docs.gmx.io/docs/tokenomics/rewards/)
page.
Token addresses[](https://docs.gmx.io/docs/tokenomics/gmx-token/#token-addresses "Direct link to Token addresses")
--------------------------------------------------------------------------------------------------------------------
* Arbitrum: [0xfc5A1A6EB076a2C7aD06eD22C90d7E710E35ad0a](https://arbiscan.io/token/0xfc5A1A6EB076a2C7aD06eD22C90d7E710E35ad0a)
* Avalanche: [0x62edc0692BD897D2295872a9FFCac5425011c661](https://snowtrace.io/address/0x62edc0692BD897D2295872a9FFCac5425011c661)
* Solana: [9wX6Qz1Y5YQe71dfnFYFfZYXZhKqjYKQwdqfrRkmYUSX](https://solscan.io/token/9wX6Qz1Y5YQe71dfnFYFfZYXZhKqjYKQwdqfrRkmYUSX)
GMX can be bridged between Arbitrum and Avalanche using [Stargate](https://stargate.finance/bridge?srcChain=arbitrum&srcToken=0xfc5A1A6EB076a2C7aD06eD22C90d7E710E35ad0a&dstChain=avalanche&dstToken=0x62edc0692BD897D2295872a9FFCac5425011c661)
. For bridging between other chains, you can use [Jumper Exchange](https://jumper.exchange/)
.
Buying GMX[](https://docs.gmx.io/docs/tokenomics/gmx-token/#buying-gmx "Direct link to Buying GMX")
-----------------------------------------------------------------------------------------------------
You can buy GMX on the [Buy](https://app.gmx.io/#/buy)
page.
Staking[](https://docs.gmx.io/docs/tokenomics/gmx-token/#staking "Direct link to Staking")
--------------------------------------------------------------------------------------------
Staking GMX earns you a share of protocol fee buybacks. 27% of protocol fees are used to buy back GMX on the open market through a mechanism approved by the DAO [Tally vote](https://www.tally.xyz/gov/gmx/proposal/81921330482579592877925554009800798217173652653143694483196169672340561914053)
.
note
GMX staking rewards are suspended. Bought-back GMX accumulates in the Treasury and will be distributed to stakers when GMX reaches $90. Your share is based on [staking power](https://docs.gmx.io/docs/tokenomics/rewards/#staking-power)
, which accrues continuously based on the amount staked and the duration of staking.
You can stake GMX on the [Earn](https://app.gmx.io/#/earn)
page. For programmatic access to staking power data, use the [`fetchStakingPower()`](https://docs.gmx.io/docs/sdk/v2/#methods)
method in SDK v2 or the `/staking/power` REST endpoint.
### Staked GMX token addresses[](https://docs.gmx.io/docs/tokenomics/gmx-token/#staked-gmx-token-addresses "Direct link to Staked GMX token addresses")
After staking GMX, you receive a Staked GMX token. The balance of this token reflects your total staked amount, including any esGMX tokens.
* Arbitrum: [0xd2D1162512F927a7e282Ef43a362659E4F2a728F](https://arbiscan.io/token/0xd2D1162512F927a7e282Ef43a362659E4F2a728F)
* Avalanche: [0x4d268a7d4C16ceB5a606c173Bd974984343fea13](https://snowtrace.io/address/0x4d268a7d4C16ceB5a606c173Bd974984343fea13)
Treasury[](https://docs.gmx.io/docs/tokenomics/gmx-token/#treasury "Direct link to Treasury")
-----------------------------------------------------------------------------------------------
The GMX treasury is funded by:
* Fees from the GMX/ETH protocol-owned liquidity
* 8.8% of V2 fees (10% is allocated to Chainlink, the treasury, and keeper costs, of which 1.2% goes to Chainlink)
The treasury is held in multiple contracts:
* DAO Treasury: [0x4bd1cdAab4254fC43ef6424653cA2375b4C94C0E](https://www.tally.xyz/gov/gmx/treasury)
* POL Multisig: [0xc6378ddf536410c14666dc59bc92b5ebc0f2f79e](https://debank.com/profile/0xc6378ddf536410c14666dc59bc92b5ebc0f2f79e)
* Governance Committee: [0x0263ad94023a5Df6d64f54BFEF089F1FBF8A4CA0](https://debank.com/profile/0x0263ad94023a5Df6d64f54BFEF089F1FBF8A4CA0)
* Bond Protocol: [0xea8a734db4c7EA50C32B5db8a0Cb811707e8ACE3](https://debank.com/profile/0xea8a734db4c7EA50C32B5db8a0Cb811707e8ACE3)
* GM Holdings: [0xe1f7c5209938780625e354dc546e28397f6ce174](https://debank.com/profile/0xe1f7c5209938780625e354dc546e28397f6ce174)
* [0x68863dDE14303BcED249cA8ec6AF85d4694dea6A](https://debank.com/profile/0x68863dDE14303BcED249cA8ec6AF85d4694dea6A)
* [0x0339740d92fb8BAf73bAB0E9eb9494bc0Df1CaFD](https://debank.com/profile/0x0339740d92fb8BAf73bAB0E9eb9494bc0Df1CaFD)
* [0x2c247a44928d66041d9f7b11a69d7a84d25207ba](https://debank.com/profile/0x2c247a44928d66041d9f7b11a69d7a84d25207ba)
The GMX DAO owns protocol-owned liquidity in the form of Uniswap V3 NFT LP tokens:
* [0x4bd1cdAab4254fC43ef6424653cA2375b4C94C0E](https://arbiscan.io/token/0xc36442b4a4522e871399cd717abdd847ab11fe88?a=0x4bd1cdAab4254fC43ef6424653cA2375b4C94C0E#inventory)
If required, the treasury may be used to pay for issues submitted through the [bug bounty](https://docs.gmx.io/docs/security/#bug-bounty)
.
Token supply[](https://docs.gmx.io/docs/tokenomics/gmx-token/#token-supply "Direct link to Token supply")
-----------------------------------------------------------------------------------------------------------
The supply of GMX can be viewed on the [Dashboard](https://app.gmx.io/#/dashboard)
. The increase in circulating supply varies depending on the number of tokens that are vested.
The forecasted max supply is 13.25 million GMX tokens. Minting beyond this cap requires a governance vote approved by GMX token holders.
### Supply allocation[](https://docs.gmx.io/docs/tokenomics/gmx-token/#supply-allocation "Direct link to Supply allocation")
* 6 million GMX: [XVIX](https://xvix.finance/)
and [Gambit](https://gambit.financial/)
migration. GMX was formed by a merger of the XVIX and Gambit communities.
* 2 million GMX: Paired with ETH for liquidity on [Uniswap](https://app.uniswap.org/#/swap?inputCurrency=ETH&outputCurrency=0xfc5A1A6EB076a2C7aD06eD22C90d7E710E35ad0a)
.
* 2 million GMX: Reserved for vesting of [escrowed GMX](https://docs.gmx.io/docs/tokenomics/rewards/#escrowed-gmx)
tokens.
* 2 million GMX: For the treasury.
* 1 million GMX: For integration incentives and community developers.
* 250,000 GMX: Distributed to contributors linearly over 2 years.
Circulating supply calculation
The supply displayed on the dashboard is the [total minted GMX tokens](https://arbiscan.io/token/0xfc5A1A6EB076a2C7aD06eD22C90d7E710E35ad0a)
minus the tokens held in [vesting](https://docs.gmx.io/docs/tokenomics/rewards/#escrowed-gmx)
, bonding, and treasury contracts:
* GMX Bonds (Arbitrum): [0xea8a734db4c7EA50C32B5db8a0Cb811707e8ACE3](https://arbiscan.io/address/0xea8a734db4c7EA50C32B5db8a0Cb811707e8ACE3)
* GMX Vester (Arbitrum): [0x199070DDfd1CFb69173aa2F7e20906F26B363004](https://arbiscan.io/address/0x199070DDfd1CFb69173aa2F7e20906F26B363004)
* GLP Vester (Arbitrum): [0xA75287d2f8b217273E7FCD7E86eF07D33972042E](https://arbiscan.io/address/0xA75287d2f8b217273E7FCD7E86eF07D33972042E)
* Affiliate Vester (Arbitrum): [0x7c100c0F55A15221A4c1C5a25Db8C98A81df49B2](https://arbiscan.io/address/0x7c100c0F55A15221A4c1C5a25Db8C98A81df49B2)
* Treasury (Arbitrum): [0x68863dDE14303BcED249cA8ec6AF85d4694dea6A](https://arbiscan.io/address/0x68863dDE14303BcED249cA8ec6AF85d4694dea6A)
* GMX Vester (Avalanche): [0x472361d3cA5F49c8E633FB50385BfaD1e018b445](https://snowtrace.io/address/0x472361d3cA5F49c8E633FB50385BfaD1e018b445)
* GLP Vester (Avalanche): [0x62331A7Bd1dfB3A7642B7db50B5509E57CA3154A](https://snowtrace.io/address/0x62331A7Bd1dfB3A7642B7db50B5509E57CA3154A)
* Affiliate Vester (Avalanche): [0x754eC029EF9926184b4CFDeA7756FbBAE7f326f7](https://snowtrace.io/address/0x754eC029EF9926184b4CFDeA7756FbBAE7f326f7)
Ethereum bridging[](https://docs.gmx.io/docs/tokenomics/gmx-token/#ethereum-bridging "Direct link to Ethereum bridging")
--------------------------------------------------------------------------------------------------------------------------
GMX tokens can be bridged between Ethereum and Arbitrum using the Arbitrum bridge. Bridging from Arbitrum to Ethereum has a 7-day waiting period during which you don't have access to your tokens. All GMX features are on Arbitrum, so there is rarely a reason to bridge to Ethereum.
For step-by-step instructions, see [this bridging guide](https://gist.github.com/xvi10/6125b5fbd73f12a2bfce9b729a52255a)
.
Next steps[](https://docs.gmx.io/docs/tokenomics/gmx-token/#next-steps "Direct link to Next steps")
-----------------------------------------------------------------------------------------------------
* [Rewards](https://docs.gmx.io/docs/tokenomics/rewards/)
— Learn about esGMX, vesting, and managing rewards.
* [Voting power](https://docs.gmx.io/docs/governance/voting-power/)
— Participate in protocol governance.
* [Fees](https://docs.gmx.io/docs/trading/fees/)
— Understand how trading fees are generated and distributed.
* [Earn page](https://app.gmx.io/#/earn)
— Start staking GMX.
* [Token addresses](https://docs.gmx.io/docs/tokenomics/gmx-token/#token-addresses)
* [Buying GMX](https://docs.gmx.io/docs/tokenomics/gmx-token/#buying-gmx)
* [Staking](https://docs.gmx.io/docs/tokenomics/gmx-token/#staking)
* [Staked GMX token addresses](https://docs.gmx.io/docs/tokenomics/gmx-token/#staked-gmx-token-addresses)
* [Treasury](https://docs.gmx.io/docs/tokenomics/gmx-token/#treasury)
* [Token supply](https://docs.gmx.io/docs/tokenomics/gmx-token/#token-supply)
* [Supply allocation](https://docs.gmx.io/docs/tokenomics/gmx-token/#supply-allocation)
* [Ethereum bridging](https://docs.gmx.io/docs/tokenomics/gmx-token/#ethereum-bridging)
* [Next steps](https://docs.gmx.io/docs/tokenomics/gmx-token/#next-steps)
---
# Getting Started | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/sdk/v1/#__docusaurus_skipToContent_fallback)
On this page
The full SDK v1 client (`GmxSdk`) exposes these top-level modules:
* **`markets`** — fetch market definitions, pricing, and daily volumes
* **`tokens`** — fetch token metadata and balances
* **`positions`** — read open positions for an account
* **`orders`** — read active orders and submit new ones (long, short, swap, cancel)
* **`trades`** — fetch historical trade activity
* **`accounts`** — read governance delegate data
* **`oracle`** — read raw oracle markets, tokens, and tickers from the configured oracle URL
* **`utils`** — fee estimation, price impact, and other calculation helpers
Before you start[](https://docs.gmx.io/docs/sdk/v1/#before-you-start "Direct link to Before you start")
---------------------------------------------------------------------------------------------------------
To use `GmxSdk`, you need the following:
* An RPC endpoint for your target chain
* A GMX oracle keeper URL — see [Oracle Prices](https://docs.gmx.io/docs/api/rest-api/oracle-prices/)
* A Subsquid GraphQL URL — see [GraphQL](https://docs.gmx.io/docs/api/graphql/)
* A viem `WalletClient` for write operations. For read-only use, you can omit the wallet client, but you still configure the RPC, oracle, and Subsquid URLs.
Initialization[](https://docs.gmx.io/docs/sdk/v1/#initialization "Direct link to Initialization")
---------------------------------------------------------------------------------------------------
The following example shows the minimum setup to initialize the SDK and fetch positions for an account on Arbitrum mainnet.
import { GmxSdk } from "@gmx-io/sdk";// 1. Create the SDK instanceconst sdk = new GmxSdk({ chainId: 42161, // Arbitrum rpcUrl: "https://arb1.arbitrum.io/rpc", oracleUrl: "https://arbitrum-api.gmxinfra.io", subsquidUrl: "https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql",});// 2. Set the account you want to querysdk.setAccount("0x9f7198eb1b9Ccc0Eb7A07eD228d8FbC12963ea33");// 3. Fetch market and token data (required for most queries)const { marketsInfoData, tokensData } = await sdk.markets.getMarketsInfo();// 4. Fetch open positions for the accountconst { positionsData } = await sdk.positions.getPositions({ marketsData: marketsInfoData, tokensData,});console.log(positionsData);
The SDK doesn't require a wallet client for read-only operations. To submit orders, pass a viem `WalletClient`:
import { GmxSdk } from "@gmx-io/sdk";import { createWalletClient, http } from "viem";import { privateKeyToAccount } from "viem/accounts";import { arbitrum } from "viem/chains";const account = privateKeyToAccount("0x...your-private-key");const walletClient = createWalletClient({ account, chain: arbitrum, transport: http("https://arb1.arbitrum.io/rpc"),});const sdk = new GmxSdk({ chainId: 42161, rpcUrl: "https://arb1.arbitrum.io/rpc", oracleUrl: "https://arbitrum-api.gmxinfra.io", subsquidUrl: "https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql", walletClient,});
If you're using CommonJS, require the v1 client from the package root:
const { GmxSdk } = require("@gmx-io/sdk");const sdk = new GmxSdk({ chainId: 42161, rpcUrl: "https://arb1.arbitrum.io/rpc", oracleUrl: "https://arbitrum-api.gmxinfra.io", subsquidUrl: "https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql",});
tip
If you're using wagmi in a React application, pass `useWalletClient().data` as the `walletClient` parameter after the wallet connects.
Common workflows[](https://docs.gmx.io/docs/sdk/v1/#common-workflows "Direct link to Common workflows")
---------------------------------------------------------------------------------------------------------
If you want exact "I want to do X" steps, start with the [Integration guide](https://docs.gmx.io/docs/sdk/v1/integration-guide/)
:
* Read positions, active orders, and recent trades for one account
* Submit a `Market Increase` order with `orders.long()`
* Cancel active orders by on-chain order key
* Understand the SDK's simulation, retry, timeout, and eventual-consistency behavior
* Debug duplicate submits, missing receipts, stale reads, and cancel/replace races in [Troubleshooting](https://docs.gmx.io/docs/sdk/v1/troubleshooting/)
API Reference[](https://docs.gmx.io/docs/sdk/v1/#api-reference "Direct link to API Reference")
------------------------------------------------------------------------------------------------
The SDK groups methods into modules, each accessed as a property on the `GmxSdk` instance. All methods are async.
### Read methods[](https://docs.gmx.io/docs/sdk/v1/#read-methods "Direct link to Read methods")
#### `sdk.markets`[](https://docs.gmx.io/docs/sdk/v1/#sdkmarkets "Direct link to sdkmarkets")
| Method | Parameters | Returns | Notes |
| --- | --- | --- | --- |
| `getMarkets(offset?, limit?)` | `offset: bigint = 0n`, `limit: bigint = 300n` | `{ marketsData?, marketsAddresses?, error? }` | Builds the listed market set from oracle market configs plus on-chain reader data |
| `getMarketsInfo()` | — | `{ marketsInfoData?, tokensData?, pricesUpdatedAt? }` | Fetches full market details including token prices; use this for most workflows |
| `getDailyVolumes()` | — | `Record \| undefined` | Returns a map of market address → daily volume in USD (30-decimal precision) |
#### `sdk.tokens`[](https://docs.gmx.io/docs/sdk/v1/#sdktokens "Direct link to sdktokens")
| Method | Parameters | Returns | Notes |
| --- | --- | --- | --- |
| `getTokensData()` | — | `{ tokensData, pricesUpdatedAt }` | Fetches token metadata and current prices for all tokens on the configured chain |
#### `sdk.positions`[](https://docs.gmx.io/docs/sdk/v1/#sdkpositions "Direct link to sdkpositions")
| Method | Parameters | Returns | Notes |
| --- | --- | --- | --- |
| `getPositions(p)` | `marketsData`, `tokensData`, `start?: number`, `end?: number` | `{ positionsData? }` | Requires an account set via `sdk.setAccount()`. `start`/`end` are pagination offsets (default 0/1000) |
#### `sdk.orders`[](https://docs.gmx.io/docs/sdk/v1/#sdkorders "Direct link to sdkorders")
| Method | Parameters | Returns | Notes |
| --- | --- | --- | --- |
| `getOrders(p)` | `marketsInfoData`, `tokensData`, `account?`, `orderTypesFilter?`, `marketsDirectionsFilter?` | `{ count, ordersInfoData }` | Returns all active orders for the account; supports filtering by order type and market direction |
#### `sdk.trades`[](https://docs.gmx.io/docs/sdk/v1/#sdktrades "Direct link to sdktrades")
| Method | Parameters | Returns | Notes |
| --- | --- | --- | --- |
| `getTradeHistory(p)` | `pageSize`, `pageIndex`, `marketsInfoData?`, `tokensData?`, `fromTxTimestamp?`, `toTxTimestamp?`, `marketsDirectionsFilter?`, `orderEventCombinations?`, `forAllAccounts?` | `Promise` | Fetches paginated trade history from the Subsquid indexer |
#### `sdk.accounts`[](https://docs.gmx.io/docs/sdk/v1/#sdkaccounts "Direct link to sdkaccounts")
| Method | Parameters | Returns | Notes |
| --- | --- | --- | --- |
| `getGovTokenDelegates(account?)` | `account?: string` | `string[]` | Returns the governance token delegates for the given account address; on chains without a configured GovToken it resolves to `[]` |
#### `sdk.oracle`[](https://docs.gmx.io/docs/sdk/v1/#sdkoracle "Direct link to sdkoracle")
| Method | Parameters | Returns | Notes |
| --- | --- | --- | --- |
| `getMarkets()` | — | `Promise` | Fetches raw market configs from the configured oracle URL |
| `getTokens()` | — | `Promise` | Fetches raw token configs from the configured oracle URL |
| `getTickers()` | — | `Promise` | Fetches current oracle ticker data from `/prices/tickers` |
### Write methods[](https://docs.gmx.io/docs/sdk/v1/#write-methods "Direct link to Write methods")
Write methods submit transactions on-chain and require a `walletClient` and an account set via `sdk.setAccount()`.
#### Quick order helpers (`sdk.orders`)[](https://docs.gmx.io/docs/sdk/v1/#quick-order-helpers-sdkorders "Direct link to quick-order-helpers-sdkorders")
The quick helpers automatically calculate swap paths, amounts, and fees from the current market state. You don't need to pre-fetch `marketsInfoData` or `tokensData` — the helpers fetch what they need unless you pass them directly.
| Method | Key parameters | Notes |
| --- | --- | --- |
| `long(p)` | `payAmount` or `sizeAmount`, `marketAddress`, `payTokenAddress`, `collateralTokenAddress`, `allowedSlippageBps?`, `leverage?`, `limitPrice?` | Opens a long position; see [Usage Examples](https://docs.gmx.io/docs/sdk/v1/#usage-examples) |
| `short(p)` | Same as `long` | Opens a short position |
| `swap(p)` | `fromAmount` or `toAmount`, `fromTokenAddress`, `toTokenAddress`, `allowedSlippageBps?`, `triggerPrice?` | Executes a token swap; set `triggerPrice` for a Limit Swap |
#### Full order methods (`sdk.orders`)[](https://docs.gmx.io/docs/sdk/v1/#full-order-methods-sdkorders "Direct link to full-order-methods-sdkorders")
Full methods require pre-computed amounts (use the `utils` module or the calculation helpers in `@gmx-io/sdk/utils/trade`).
| Method | Notes |
| --- | --- |
| `createIncreaseOrder(p)` | Creates a Market Increase or Limit Increase order; see [Usage Examples](https://docs.gmx.io/docs/sdk/v1/#usage-examples) |
| `createDecreaseOrder(p)` | Creates a Market Decrease, Stop-Loss, or Take-Profit order |
| `createSwapOrder(p)` | Creates a Market Swap or Limit Swap order |
| `cancelOrders(orderKeys: string[])` | Cancels one or more orders by their on-chain keys |
Configuration Options[](https://docs.gmx.io/docs/sdk/v1/#configuration-options "Direct link to Configuration Options")
------------------------------------------------------------------------------------------------------------------------
Pass a `GmxSdkConfig` object to the `GmxSdk` constructor. The full interface is:
interface GmxSdkConfig { // Required chainId: number; // 42161 (Arbitrum), 43114 (Avalanche), 3637 (Botanix), 43113 (Avalanche Fuji), or 421614 (Arbitrum Sepolia) rpcUrl: string; // RPC endpoint for the chain oracleUrl: string; // GMX oracle keeper URL subsquidUrl: string; // GMX Subsquid GraphQL URL // Optional — connection account?: string; // Wallet address; can also be set via sdk.setAccount() publicClient?: PublicClient; // Custom viem PublicClient; auto-created from rpcUrl if omitted walletClient?: WalletClient; // Viem WalletClient; required for write operations // Optional — overrides tokens?: Record>; // Override token metadata by address markets?: Record>; // Override market config by address // Optional — fees settings?: { uiFeeReceiverAccount?: string; // Address that receives UI fees on orders you submit };}
### Network URLs[](https://docs.gmx.io/docs/sdk/v1/#network-urls "Direct link to Network URLs")
Use the following endpoints for each production network:
| Network | Oracle URL | Chain ID |
| --- | --- | --- |
| Arbitrum | `https://arbitrum-api.gmxinfra.io` | 42161 |
| Avalanche | `https://avalanche-api.gmxinfra.io` | 43114 |
| Botanix | `https://botanix-api.gmxinfra.io` | 3637 |
For Subsquid GraphQL endpoints per network, see [GraphQL](https://docs.gmx.io/docs/api/graphql/)
. The Arbitrum endpoint is `https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql`.
The table above lists production endpoints. Alpha-5 also accepts Arbitrum Sepolia (`421614`) and Avalanche Fuji (`43113`) in `chainId` where you provide matching RPC, oracle, and Subsquid endpoints for those environments.
For the underlying contract ABIs and parameters the SDK wraps, see [Contracts](https://docs.gmx.io/docs/category/contracts/)
.
tip
The SDK source exports `getOracleKeeperUrl(chainId)` from `@gmx-io/sdk/configs/oracleKeeper` if you want to look up the URL programmatically.
### Setting up custom viem clients[](https://docs.gmx.io/docs/sdk/v1/#setting-up-custom-viem-clients "Direct link to Setting up custom viem clients")
By default, the SDK creates its own viem `PublicClient` from `rpcUrl`. If you create your own client, include the batching configuration to optimize multicall performance:
warning
If you inject a custom viem `publicClient` without `BATCH_CONFIGS`, large GMX multicalls may be split into many smaller requests. The SDK's batch config sets the client-side multicall calldata limit to `1024 * 1024` bytes; omitting it can cause unexpected request fan-out, rate limits, or browser-side transport failures on public RPC endpoints.
import { createPublicClient, http } from "viem";import { arbitrum } from "viem/chains";import { BATCH_CONFIGS } from "@gmx-io/sdk/configs/batch";const publicClient = createPublicClient({ chain: arbitrum, transport: http("https://arb1.arbitrum.io/rpc", { batch: BATCH_CONFIGS[42161].http, }), batch: BATCH_CONFIGS[42161].client,});const sdk = new GmxSdk({ chainId: 42161, rpcUrl: "https://arb1.arbitrum.io/rpc", oracleUrl: "https://arbitrum-api.gmxinfra.io", subsquidUrl: "https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql", publicClient,});
If you supply your own transport as well, carry over both parts of the batch config:
* `BATCH_CONFIGS[chainId].http` for the viem HTTP transport
* `BATCH_CONFIGS[chainId].client` for client-side multicall batching
### Customizing token data[](https://docs.gmx.io/docs/sdk/v1/#customizing-token-data "Direct link to Customizing token data")
To override default token properties, pass a `tokens` map keyed by token address:
const sdk = new GmxSdk({ chainId: 42161, rpcUrl: "https://arb1.arbitrum.io/rpc", oracleUrl: "https://arbitrum-api.gmxinfra.io", subsquidUrl: "https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql", tokens: { "0x912CE59144191C1204E64559FE8253a0e49E6548": { name: "My Custom Name for ARB", }, },});
The `name` field for this token address uses your custom value throughout the SDK.
### Customizing market availability[](https://docs.gmx.io/docs/sdk/v1/#customizing-market-availability "Direct link to Customizing market availability")
To hide specific markets from the SDK, set `isListed: false` in the `markets` override map:
const sdk = new GmxSdk({ chainId: 42161, rpcUrl: "https://arb1.arbitrum.io/rpc", oracleUrl: "https://arbitrum-api.gmxinfra.io", subsquidUrl: "https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql", markets: { "0x47c031236e19d024b42f8AE6780E44A573170703": { isListed: false, }, },});
Usage Examples[](https://docs.gmx.io/docs/sdk/v1/#usage-examples "Direct link to Usage Examples")
---------------------------------------------------------------------------------------------------
These examples show the most common integration workflows. All examples assume you've initialized `sdk` and called `sdk.setAccount()` as shown in [Initialization](https://docs.gmx.io/docs/sdk/v1/#initialization)
.
### Quick order helpers[](https://docs.gmx.io/docs/sdk/v1/#quick-order-helpers "Direct link to Quick order helpers")
For most use cases, use the quick helper methods. They automatically calculate swap paths, amounts, and execution fees from the current market state. You can optionally pass `marketsInfoData` and `tokensData` yourself to reduce API calls if you've already fetched them.
**Open a long position on ETH/USD (WETH-USDC) using WETH as collateral:**
await sdk.orders.long({ payAmount: 100031302n, // Raw pay-token amount in the token's native decimals marketAddress: "0x70d95587d40A2caf56bd97485aB3Eec10Bee6336", // ETH/USD [WETH-USDC] payTokenAddress: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", // WETH collateralTokenAddress: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC allowedSlippageBps: 125, // 1.25% slippage tolerance leverage: 50000n, // 5x leverage (basis points, 10000 = 1x)});
**Swap ARB to LINK:**
await sdk.orders.swap({ fromAmount: 1000n, fromTokenAddress: "0x912CE59144191C1204E64559FE8253a0e49E6548", // ARB toTokenAddress: "0xf97f4df75117a78c1A5a0DBb814Af92458539FB4", // LINK allowedSlippageBps: 125,});
tip
Pass `payAmount` to specify your input amount. Pass `sizeAmount` instead to target a specific position size. The helper calculates the other value automatically.
#### Synthetic token addresses[](https://docs.gmx.io/docs/sdk/v1/#synthetic-token-addresses "Direct link to Synthetic token addresses")
The `payTokenAddress` is the token you're depositing. The `collateralTokenAddress` is the token held as margin. Some markets use synthetic index tokens — for example, the BTC/USD \[WBTC-USDC\] market's index token is a synthetic BTC, so you pass the WBTC address (`0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f`) as `collateralTokenAddress`, not the synthetic address.
### Full order method[](https://docs.gmx.io/docs/sdk/v1/#full-order-method "Direct link to Full order method")
Use `createIncreaseOrder` when you need precise control over order amounts, for example in automated strategies where you compute `increaseAmounts` yourself using `getIncreasePositionAmounts` from `@gmx-io/sdk/utils/trade`.
import type { IncreasePositionAmounts } from "@gmx-io/sdk/types/trade";const { marketsInfoData, tokensData } = await sdk.markets.getMarketsInfo();if (!marketsInfoData || !tokensData) { throw new Error("Failed to fetch market data");}// ETH/USD [WETH-USDC] on Arbitrumconst marketInfo = marketsInfoData["0x70d95587d40A2caf56bd97485aB3Eec10Bee6336"];// USDC as collateralconst collateralToken = tokensData["0xaf88d065e77c8cC2239327C5EDb3A432268e5831"];// Compute increaseAmounts with getIncreasePositionAmounts().// That helper needs the full IncreasePositionParams input shown in:// /docs/sdk/v1/exports/utils/trade/increaseconst increaseAmounts: IncreasePositionAmounts = /* precomputed */;await sdk.orders.createIncreaseOrder({ marketsInfoData, tokensData, isLimit: false, isLong: true, marketAddress: marketInfo.marketTokenAddress, allowedSlippage: 50, collateralToken, collateralTokenAddress: collateralToken.address, receiveTokenAddress: collateralToken.address, fromToken: collateralToken, marketInfo, indexToken: marketInfo.indexToken, increaseAmounts,});
note
The `increaseAmounts` object has a complex structure including `swapStrategy`, price impact data, and fee components. Use `getIncreasePositionAmounts` from `@gmx-io/sdk/utils/trade` to compute it rather than constructing it manually. The complete low-level input shape is documented in [trade/increase](https://docs.gmx.io/docs/sdk/v1/exports/utils/trade/increase/)
.
Operational notes[](https://docs.gmx.io/docs/sdk/v1/#operational-notes "Direct link to Operational notes")
------------------------------------------------------------------------------------------------------------
Keep these behaviors in mind when you integrate SDK v1 into a production app:
* Write methods return a transaction hash after submission. They do not wait for keeper execution or refetch the resulting order state for you.
* The default viem HTTP clients created by `GmxSdk` disable transport retries. Add your own retry and backoff policy around safe read paths.
* The SDK does not provide idempotency keys or client order IDs. Prevent duplicate submits in your UI while a transaction is pending.
* Market increases and market swaps simulate before submit by default. Some non-market flows skip simulation in the current implementation. See the [Integration guide](https://docs.gmx.io/docs/sdk/v1/integration-guide/#simulation-behavior)
for the exact behavior.
### Next steps[](https://docs.gmx.io/docs/sdk/v1/#next-steps "Direct link to Next steps")
* Start with the [Integration guide](https://docs.gmx.io/docs/sdk/v1/integration-guide/)
for scenario-based walkthroughs
* See [SDK Examples](https://docs.gmx.io/docs/sdk/v1/examples/)
for more complete integration patterns
* See [Exports](https://docs.gmx.io/docs/sdk/v1/exports/)
for utility functions available in the SDK
* [Before you start](https://docs.gmx.io/docs/sdk/v1/#before-you-start)
* [Initialization](https://docs.gmx.io/docs/sdk/v1/#initialization)
* [Common workflows](https://docs.gmx.io/docs/sdk/v1/#common-workflows)
* [API Reference](https://docs.gmx.io/docs/sdk/v1/#api-reference)
* [Read methods](https://docs.gmx.io/docs/sdk/v1/#read-methods)
* [Write methods](https://docs.gmx.io/docs/sdk/v1/#write-methods)
* [Configuration Options](https://docs.gmx.io/docs/sdk/v1/#configuration-options)
* [Network URLs](https://docs.gmx.io/docs/sdk/v1/#network-urls)
* [Setting up custom viem clients](https://docs.gmx.io/docs/sdk/v1/#setting-up-custom-viem-clients)
* [Customizing token data](https://docs.gmx.io/docs/sdk/v1/#customizing-token-data)
* [Customizing market availability](https://docs.gmx.io/docs/sdk/v1/#customizing-market-availability)
* [Usage Examples](https://docs.gmx.io/docs/sdk/v1/#usage-examples)
* [Quick order helpers](https://docs.gmx.io/docs/sdk/v1/#quick-order-helpers)
* [Full order method](https://docs.gmx.io/docs/sdk/v1/#full-order-method)
* [Operational notes](https://docs.gmx.io/docs/sdk/v1/#operational-notes)
* [Next steps](https://docs.gmx.io/docs/sdk/v1/#next-steps)
---
# Direct URLs | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/trading/direct-urls/#__docusaurus_skipToContent_fallback)
On this page
The GMX frontend supports direct URLs that pre-fill trade parameters, letting you share specific trading configurations or deep-link users into a particular state.
Trade parameters[](https://docs.gmx.io/docs/trading/direct-urls/#trade-parameters "Direct link to Trade parameters")
----------------------------------------------------------------------------------------------------------------------
Use the `/trade/:tradeType` path to open the trade page with pre-selected settings. The trade type is a URL path segment, not a query parameter. All query parameters are removed from the URL after two seconds.
| Parameter | Location | Description | Accepted values |
| --- | --- | --- | --- |
| `tradeType` | Path segment | The type of trade | `long`, `short`, `swap` (case-insensitive) |
| `mode` | Query parameter | The order mode | `market`, `limit`, `stopmarket`, `trigger`, `twap` (case-insensitive); `tpsl` is an alias for `trigger` |
| `from` | Query parameter | The token used for payment | Token symbol such as `eth`, `btc`, `usdc` (case-insensitive) |
| `to` or `market` | Query parameter | The asset to long, short, or swap to | Token symbol such as `eth`, `btc`, `uni` (case-insensitive); `to` and `market` are interchangeable |
| `collateral` | Query parameter | The collateral asset | Token symbol such as `eth`, `usdc`, `usdt` (case-insensitive) |
| `pool` | Query parameter | The liquidity pool for the trade | Pool name such as `weth-usdc`, `btc-usdc` (case-insensitive) |
| `chainId` | Query parameter | Triggers a network switch on load | Numeric chain ID such as `42161` (Arbitrum) |
note
Not all order modes are available for every trade type. `Stop Market` is only available for long and short positions. `TWAP` is available for long, short, and swap trades. Swaps do not support `Stop Market`.
### Examples[](https://docs.gmx.io/docs/trading/direct-urls/#examples "Direct link to Examples")
* `https://app.gmx.io/#/trade/long?mode=limit&from=eth&market=sol`
* `https://app.gmx.io/#/trade/short?mode=limit&from=eth&to=btc`
* `https://app.gmx.io/#/trade/short?mode=market&from=eth&to=btc&collateral=usdc`
* `https://app.gmx.io/#/trade/short?mode=market&from=eth&to=sol&collateral=usdc&pool=sol-usdc`
GM pools parameters[](https://docs.gmx.io/docs/trading/direct-urls/#gm-pools-parameters "Direct link to GM pools parameters")
-------------------------------------------------------------------------------------------------------------------------------
Use the `/pools/details` path to open a specific GM pool with a pre-selected operation and mode. The `market` parameter must be the pool's contract address, not a token symbol.
| Parameter | Description | Accepted values |
| --- | --- | --- |
| `market` | The GM or GLV pool to open | Contract address (hex) of the market or GLV token |
| `operation` | The deposit or withdrawal direction | `Deposit`, `Withdrawal`, `Shift` (case-sensitive) |
| `mode` | The deposit or withdrawal mode | `Single`, `Pair` (case-sensitive) |
warning
The `operation` and `mode` values are case-sensitive. `Deposit`, `Withdrawal`, `Shift`, `Single`, and `Pair` must be capitalized exactly as shown. Values in any other case are ignored and the page opens with its default state.
### Examples[](https://docs.gmx.io/docs/trading/direct-urls/#examples-1 "Direct link to Examples")
* `https://app.gmx.io/#/pools/details?market=0x450bb6774Dd8a756274E0ab4107953259d2ac541&operation=Deposit&mode=Single`
* `https://app.gmx.io/#/pools/details?market=0x450bb6774Dd8a756274E0ab4107953259d2ac541&operation=Withdrawal&mode=Pair`
* `https://app.gmx.io/#/pools/details?market=0x450bb6774Dd8a756274E0ab4107953259d2ac541&operation=Deposit&mode=Pair`
* [Trade parameters](https://docs.gmx.io/docs/trading/direct-urls/#trade-parameters)
* [Examples](https://docs.gmx.io/docs/trading/direct-urls/#examples)
* [GM pools parameters](https://docs.gmx.io/docs/trading/direct-urls/#gm-pools-parameters)
* [Examples](https://docs.gmx.io/docs/trading/direct-urls/#examples-1)
---
# Rewards | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/tokenomics/rewards/#__docusaurus_skipToContent_fallback)
On this page
Staking GMX earns you a share of protocol fees. 27% of fees from leverage trading, liquidations, borrowing fees, and swaps are used to buy back GMX on the open market — a mechanism approved by the DAO [Tally vote](https://www.tally.xyz/gov/gmx/proposal/81921330482579592877925554009800798217173652653143694483196169672340561914053)
. Staking also grants [voting power](https://docs.gmx.io/docs/governance/voting-power/)
in protocol governance. You can stake and manage rewards on the [Earn](https://app.gmx.io/#/earn)
page. For more on the GMX token, see [GMX token](https://docs.gmx.io/docs/tokenomics/gmx-token/)
.
note
GMX staking rewards are accumulating in the Treasury. Bought-back GMX will be distributed to stakers when GMX reaches $90. Your share of accumulated rewards is based on [staking power](https://docs.gmx.io/docs/tokenomics/rewards/#staking-power)
. The APR display on the Earn page shows "Accumulating" while distribution is suspended.
Staking Power[](https://docs.gmx.io/docs/tokenomics/rewards/#staking-power "Direct link to Staking Power")
------------------------------------------------------------------------------------------------------------
Staking power determines each staker's share of accumulated Treasury rewards. It accrues continuously based on the amount staked and the duration of staking. You can query staking power data programmatically through the [REST API](https://docs.gmx.io/docs/api/overview/)
(`GET /staking/power`) or [GraphQL](https://docs.gmx.io/docs/api/graphql/)
.
### How Power Accrues[](https://docs.gmx.io/docs/tokenomics/rewards/#how-power-accrues "Direct link to How Power Accrues")
The system computes staking power as a continuous time-weighted integral of your staked balance (both GMX and esGMX in the StakedGmxTracker). Power accrues every second rather than through periodic snapshots.
On each stake or unstake event, the system updates your accumulated power:
accumulatedPower += currentBalance × (eventTimestamp − lastUpdateTimestamp)
A user who stakes 1,000 GMX for 90 days without changes accumulates power equal to `1,000 × 90 days` of staking. Your share of Treasury rewards equals your cumulative power divided by the total network power across all stakers.
Power accrual began on March 4, 2026, when the last bought-back GMX reward distribution ended.
### Loyalty Threshold[](https://docs.gmx.io/docs/tokenomics/rewards/#loyalty-threshold "Direct link to Loyalty Threshold")
A loyalty system protects against large unstaking events. Loyalty tracking started on March 25, 2026, at which point the system began tracking each address's peak staked balance. If the staked balance drops below 80% of this peak, all accumulated power resets to zero. The address's historical peak is then reset to its new staked balance, and power begins accruing again from zero from that point.
Key details:
* After a reset, previous accumulation is lost and is not restored. This means the address loses the previously accumulated share of the GMX-at-$90 distribution and starts rebuilding from zero
* Forfeited power is removed from the total network power. Because each staker's share equals their own power divided by the total, reducing the total automatically increases every remaining staker's share proportionally — there is no separate redistribution step
* After a reset, the address's current balance becomes its new historical peak
* Staking additional tokens raises the historical peak and the 80% threshold accordingly
* Unstaking esGMX to deposit it into a vesting vault lowers the tracked staked balance. If that drop puts the address below 80% of its historical peak, accumulated power resets to zero
* Staking power and loyalty tracking are independent per address; accumulated power and historical peak do not carry across wallets
* Vesting completion (esGMX converting to GMX within a single transaction) does not trigger false resets
Escrowed GMX[](https://docs.gmx.io/docs/tokenomics/rewards/#escrowed-gmx "Direct link to Escrowed GMX")
---------------------------------------------------------------------------------------------------------
Escrowed GMX (esGMX) is a non-transferable token that was historically awarded as an incentive for GMX staking, GLP, referrals, and other programs. Stakers now receive GMX directly through the buyback mechanism rather than esGMX. Existing esGMX can be used in two ways:
* Staked for staking power — each staked esGMX token contributes to [staking power](https://docs.gmx.io/docs/tokenomics/rewards/#staking-power)
the same way as a staked GMX token
* Vested to become GMX tokens over a period of one year (365 days)
esGMX is not transferrable unless you are doing a [full account transfer](https://app.gmx.io/#/begin_account_transfer)
. The amount of GMX or GLP required to vest esGMX is unique per account, and the maximum amount of esGMX that can be vested is capped to the esGMX rewards received by that account.
note
GLP is a legacy liquidity token that preceded GM and GLV pools. While GLP is no longer available for new minting, GLP vesting vaults remain active for users with existing esGMX earned through GLP staking.
Vesting[](https://docs.gmx.io/docs/tokenomics/rewards/#vesting "Direct link to Vesting")
------------------------------------------------------------------------------------------
Escrowed GMX (esGMX) tokens can be converted into GMX tokens through vesting on the [Earn](https://app.gmx.io/#/earn)
page. There are two separate vesting vaults — one for esGMX earned from GMX staking (GMX Vault) and one for esGMX earned from GLP staking (GLP Vault). Each vault tracks its own balances, reserved tokens, and vesting progress independently. The [v1 Earn page](https://v1.app.gmx.io/#/earn)
displays both vaults as separate cards, so you can see the breakdown of your esGMX by source.
When vesting is initiated, the average amount of GMX or GLP tokens used to earn the esGMX rewards is reserved. For example, if you staked 1,000 GMX and earned 100 esGMX tokens, then to vest 100 esGMX tokens, 1,000 GMX tokens are reserved. To vest 50 esGMX, 500 GMX tokens are reserved. The actual ratio depends on the average staked amount and rewards earned for your account.
Key details:
* esGMX tokens that have been unstaked and deposited for vesting stop counting toward staking power. Staked GMX or esGMX tokens that are reserved for vesting remain in the staked balance and continue to count toward staking power and the GMX-at-$90 Treasury distribution.
* If you unstake esGMX to start vesting it, those unstaked tokens stop counting toward staking power. If that drop puts the address below 80% of its historical peak staked balance, accumulated power resets to zero.
* After initiating vesting, esGMX tokens are converted into GMX every second and fully vest over 365 days. Vested GMX tokens are claimable at any time.
* If you sell GMX or GLP tokens and want to vest your esGMX rewards later, you need to re-buy the GMX or GLP tokens.
* GMX and esGMX can be used interchangeably for the required reserve amount.
* Depositing into the vesting vault while existing vesting is ongoing is supported.
### Withdrawing from vesting[](https://docs.gmx.io/docs/tokenomics/rewards/#withdrawing-from-vesting "Direct link to Withdrawing from vesting")
Tokens reserved for vesting can't be unstaked or sold. To unreserve them, use the "Withdraw" button on the [Earn](https://app.gmx.io/#/earn)
page. Partial withdrawals are not supported — withdrawing unreserves all tokens and pauses vesting. Any esGMX tokens that had already vested into GMX remain as GMX tokens.
Next steps[](https://docs.gmx.io/docs/tokenomics/rewards/#next-steps "Direct link to Next steps")
---------------------------------------------------------------------------------------------------
* [GMX token](https://docs.gmx.io/docs/tokenomics/gmx-token/)
— Token addresses, supply, and staking details.
* [Voting power](https://docs.gmx.io/docs/governance/voting-power/)
— Participate in protocol governance.
* [Earn page](https://app.gmx.io/#/earn)
— Stake GMX and manage rewards.
* [Staking Power](https://docs.gmx.io/docs/tokenomics/rewards/#staking-power)
* [How Power Accrues](https://docs.gmx.io/docs/tokenomics/rewards/#how-power-accrues)
* [Loyalty Threshold](https://docs.gmx.io/docs/tokenomics/rewards/#loyalty-threshold)
* [Escrowed GMX](https://docs.gmx.io/docs/tokenomics/rewards/#escrowed-gmx)
* [Vesting](https://docs.gmx.io/docs/tokenomics/rewards/#vesting)
* [Withdrawing from vesting](https://docs.gmx.io/docs/tokenomics/rewards/#withdrawing-from-vesting)
* [Next steps](https://docs.gmx.io/docs/tokenomics/rewards/#next-steps)
---
# Integration guide | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/sdk/v1/integration-guide/#__docusaurus_skipToContent_fallback)
On this page
Use this page when you want exact steps instead of a function-by-function reference. The [Getting Started](https://docs.gmx.io/docs/sdk/v1/)
page explains the SDK surface area, and the [Exports](https://docs.gmx.io/docs/sdk/v1/exports/)
pages document individual helpers. This page focuses on common workflows and the operational details that matter in production.
What SDK v1 covers today[](https://docs.gmx.io/docs/sdk/v1/integration-guide/#what-sdk-v1-covers-today "Direct link to What SDK v1 covers today")
---------------------------------------------------------------------------------------------------------------------------------------------------
SDK v1 (`GmxSdk`) is the full client. It reads markets, tokens, positions, orders, trades, and account delegates, and it submits or cancels orders through a connected wallet.
| Workflow | Status | Notes |
| --- | --- | --- |
| Read market, token, position, order, and trade data | ✅ | Available through `markets`, `tokens`, `positions`, `orders`, `trades`, and `accounts` |
| Submit and cancel orders | ✅ | Available through `orders.long`, `orders.short`, `orders.swap`, `create*Order`, and `cancelOrders` |
| Built-in transaction receipt polling | ❌ | Order methods return a transaction hash; your app must wait for receipts and refetch state |
| Built-in idempotency keys or client order IDs | ❌ | Prevent duplicate submits in your app layer |
| Automatic retry and backoff for RPC reads | ⚠️ | Default viem HTTP clients are created with `retryCount: 0` |
If you are designing delegated trader, subaccount, or one-click trading flows, use [Delegated trading integration](https://docs.gmx.io/docs/api/contracts/delegated-trading/)
together with this SDK guide. The delegated trading architecture spans contracts, optional relay routers, and your own signer/session model.
Read account state for one wallet[](https://docs.gmx.io/docs/sdk/v1/integration-guide/#read-account-state-for-one-wallet "Direct link to Read account state for one wallet")
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Use one market and token snapshot across the whole read flow. This avoids mixing data from different polls when you render positions, active orders, and recent trades together.
import { GmxSdk } from "@gmx-io/sdk";const sdk = new GmxSdk({ chainId: 42161, rpcUrl: "https://arb1.arbitrum.io/rpc", oracleUrl: "https://arbitrum-api.gmxinfra.io", subsquidUrl: "https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql",});sdk.setAccount("0x9f7198eb1b9Ccc0Eb7A07eD228d8FbC12963ea33");const { marketsInfoData, tokensData } = await sdk.markets.getMarketsInfo();if (!marketsInfoData || !tokensData) { throw new Error("Failed to load market snapshot");}const [{ positionsData }, { ordersInfoData }, trades] = await Promise.all([ sdk.positions.getPositions({ marketsData: marketsInfoData, tokensData, }), sdk.orders.getOrders({ marketsInfoData, tokensData, }), sdk.trades.getTradeHistory({ pageSize: 25, pageIndex: 0, marketsInfoData, tokensData, }),]);console.log({ positions: Object.values(positionsData ?? {}), orders: Object.values(ordersInfoData ?? {}), recentTrades: trades,});
Open a Market Increase order[](https://docs.gmx.io/docs/sdk/v1/integration-guide/#open-a-market-increase-order "Direct link to Open a Market Increase order")
---------------------------------------------------------------------------------------------------------------------------------------------------------------
If you want the SDK to calculate swap paths, fees, and order amounts for you, start with the quick helper methods. The helper returns a transaction hash after submission. After that, you still need to wait for the receipt and refetch positions or orders.
import { GmxSdk } from "@gmx-io/sdk";import { createWalletClient, http } from "viem";import { privateKeyToAccount } from "viem/accounts";import { arbitrum } from "viem/chains";const account = privateKeyToAccount("0x...your-private-key");const walletClient = createWalletClient({ account, chain: arbitrum, transport: http("https://arb1.arbitrum.io/rpc"),});const sdk = new GmxSdk({ chainId: 42161, rpcUrl: "https://arb1.arbitrum.io/rpc", oracleUrl: "https://arbitrum-api.gmxinfra.io", subsquidUrl: "https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql", walletClient, account: account.address,});const txHash = await sdk.orders.long({ payAmount: 100031302n, marketAddress: "0x70d95587d40A2caf56bd97485aB3Eec10Bee6336", payTokenAddress: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", collateralTokenAddress: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", allowedSlippageBps: 125, leverage: 50000n,});const receipt = await sdk.publicClient.waitForTransactionReceipt({ hash: txHash });if (receipt.status !== "success") { throw new Error("Order transaction reverted");}const { marketsInfoData, tokensData } = await sdk.markets.getMarketsInfo();const { ordersInfoData } = await sdk.orders.getOrders({ marketsInfoData: marketsInfoData!, tokensData: tokensData!,});console.log("Submitted tx:", txHash);console.log("Active orders:", Object.keys(ordersInfoData));
Cancel active orders[](https://docs.gmx.io/docs/sdk/v1/integration-guide/#cancel-active-orders "Direct link to Cancel active orders")
---------------------------------------------------------------------------------------------------------------------------------------
Fetch the latest active orders first, then cancel by on-chain order key. This matters if your UI lets the user cancel and replace orders quickly.
const { marketsInfoData, tokensData } = await sdk.markets.getMarketsInfo();if (!marketsInfoData || !tokensData) { throw new Error("Failed to load market snapshot");}const { ordersInfoData } = await sdk.orders.getOrders({ marketsInfoData, tokensData,});const orderKeys = Object.keys(ordersInfoData);if (orderKeys.length === 0) { throw new Error("No active orders to cancel");}const txHash = await sdk.orders.cancelOrders(orderKeys);await sdk.publicClient.waitForTransactionReceipt({ hash: txHash });const refreshed = await sdk.orders.getOrders({ marketsInfoData, tokensData,});console.log("Remaining orders:", Object.keys(refreshed.ordersInfoData));
Operational notes[](https://docs.gmx.io/docs/sdk/v1/integration-guide/#operational-notes "Direct link to Operational notes")
------------------------------------------------------------------------------------------------------------------------------
### Data freshness and consistency[](https://docs.gmx.io/docs/sdk/v1/integration-guide/#data-freshness-and-consistency "Direct link to Data freshness and consistency")
* Quick helpers fetch `marketsInfoData` and `tokensData` for you when you do not pass them in.
* If your app already has a fresh snapshot, pass the same `marketsInfoData` and `tokensData` through the whole flow. This gives you a more consistent view than mixing independent reads.
* After a write, treat reads as eventually consistent. Transaction submission, order creation, keeper execution, and indexed reads do not complete at the same time.
### Simulation behavior[](https://docs.gmx.io/docs/sdk/v1/integration-guide/#simulation-behavior "Direct link to Simulation behavior")
* Market increases simulate before submit unless you pass `skipSimulation: true`.
* Limit increases skip simulation in the current implementation.
* Market swaps simulate before submit. `Limit Swap` orders do not.
* `createDecreaseOrder()` currently sets `skipSimulation: true`. If you expose that flow, validate inputs before submit and handle chain-level failures explicitly.
### Retries and timeouts[](https://docs.gmx.io/docs/sdk/v1/integration-guide/#retries-and-timeouts "Direct link to Retries and timeouts")
* The default viem HTTP clients created by `GmxSdk` disable transport retries with `retryCount: 0`.
* SDK multicalls use a `40000` ms timeout.
* Add your own retry and backoff policy around read paths that can be repeated safely. Persist transaction hashes from write paths so you can recover after client restarts.
### Idempotency and race conditions[](https://docs.gmx.io/docs/sdk/v1/integration-guide/#idempotency-and-race-conditions "Direct link to Idempotency and race conditions")
* SDK v1 order methods do not take idempotency keys or client-generated order IDs.
* Disable duplicate submit actions in your UI while a transaction is pending.
* When you cancel or replace orders, refetch active orders just before choosing `orderKeys`.
Next steps[](https://docs.gmx.io/docs/sdk/v1/integration-guide/#next-steps "Direct link to Next steps")
---------------------------------------------------------------------------------------------------------
* Go back to [Getting Started](https://docs.gmx.io/docs/sdk/v1/)
for constructor options and module reference.
* See [Examples](https://docs.gmx.io/docs/sdk/v1/examples/)
for smaller focused snippets.
* Use [Exports](https://docs.gmx.io/docs/sdk/v1/exports/)
when you need lower-level helpers such as fee estimation, price impact, or custom trade amount calculation.
* [What SDK v1 covers today](https://docs.gmx.io/docs/sdk/v1/integration-guide/#what-sdk-v1-covers-today)
* [Read account state for one wallet](https://docs.gmx.io/docs/sdk/v1/integration-guide/#read-account-state-for-one-wallet)
* [Open a Market Increase order](https://docs.gmx.io/docs/sdk/v1/integration-guide/#open-a-market-increase-order)
* [Cancel active orders](https://docs.gmx.io/docs/sdk/v1/integration-guide/#cancel-active-orders)
* [Operational notes](https://docs.gmx.io/docs/sdk/v1/integration-guide/#operational-notes)
* [Data freshness and consistency](https://docs.gmx.io/docs/sdk/v1/integration-guide/#data-freshness-and-consistency)
* [Simulation behavior](https://docs.gmx.io/docs/sdk/v1/integration-guide/#simulation-behavior)
* [Retries and timeouts](https://docs.gmx.io/docs/sdk/v1/integration-guide/#retries-and-timeouts)
* [Idempotency and race conditions](https://docs.gmx.io/docs/sdk/v1/integration-guide/#idempotency-and-race-conditions)
* [Next steps](https://docs.gmx.io/docs/sdk/v1/integration-guide/#next-steps)
---
# Liquidations and ADL | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/trading/liquidations/#__docusaurus_skipToContent_fallback)
On this page
This page covers liquidation mechanics, Auto-Deleveraging (ADL), and trading risks.
Liquidations[](https://docs.gmx.io/docs/trading/liquidations/#liquidations "Direct link to Liquidations")
-----------------------------------------------------------------------------------------------------------
A position is liquidated when its remaining collateral, after accounting for unrealized losses, accrued fees, and capped negative price impact, falls below the market's minimum collateral threshold. This threshold ranges from 0.25% to 1% of position size, depending on market configuration. The protocol uses the minimum index price (`minPrice`) to calculate PnL for long positions and the maximum index price (`maxPrice`) for short positions. Collateral value always uses the minimum collateral token price (`collateralTokenPrice.min`), regardless of position side.
warning
Your liquidation price is not static. Borrow fees and funding fees accumulate over time, moving it closer. You can deposit additional collateral using the "Edit" button to improve your liquidation price.
note
When a position is liquidated, any remaining collateral after deducting losses and fees is returned to your wallet.
### Minimum collateral floor[](https://docs.gmx.io/docs/trading/liquidations/#minimum-collateral-floor "Direct link to Minimum collateral floor")
In addition to the percentage-based threshold, the protocol enforces an absolute minimum collateral amount (`MIN_COLLATERAL_USD`). The effective liquidation threshold is whichever value is greater: the market's percentage of position size or this absolute floor.
For larger positions, the percentage-based threshold exceeds the floor and the floor has no effect. For small positions, the floor can dominate — reserving most of the collateral as the required minimum and leaving very little buffer before liquidation triggers.
For example, with a $1.00 floor and a 0.5% minimum collateral factor, two 1x short positions behave very differently:
| Position size | Collateral (1x) | Factor threshold | Effective threshold | Usable buffer | Liquidation distance |
| --- | --- | --- | --- | --- | --- |
| $1,000 | $1,000 | $5.00 | $5.00 (factor) | $995 | ~100% from entry |
| $1.15 | $1.15 | ~$0.006 | $1.00 (floor) | $0.15 | ~12% from entry |
The $1.15 position must maintain at least $1.00 in remaining collateral, leaving only $0.15 as buffer against price movement and accumulated fees. This is why small positions can have liquidation prices much closer to entry than their leverage alone would suggest.
### Liquidation fees[](https://docs.gmx.io/docs/trading/liquidations/#liquidation-fees "Direct link to Liquidation fees")
The liquidation fee is a percentage of the position's notional size (not the collateral). The applicable rate depends on the market type:
| Market type | Liquidation fee |
| --- | --- |
| Standard (non-synthetic) | 0.20% of position size |
| Single-token (BTC/BTC, ETH/ETH) | 0.30% of position size |
| Synthetic (SOL, ARB, LINK, and similar) | 0.30% of position size |
| High-volatility (newly listed markets) | 0.45% of position size |
The liquidation fee is not factored into the protocol's liquidatability check — it is deducted only when the position is actually closed.
### Price impact in liquidations[](https://docs.gmx.io/docs/trading/liquidations/#price-impact-in-liquidations "Direct link to Price impact in liquidations")
Negative price impact is included in the liquidation check, capped by the `MAX_POSITION_IMPACT_FACTOR_FOR_LIQUIDATIONS` parameter. Positive price impact is zeroed out for the purpose of the liquidation check. The same capped negative price impact is used in the frontend's liquidation price calculation.
### Stop-Loss orders and liquidations[](https://docs.gmx.io/docs/trading/liquidations/#stop-loss-orders-and-liquidations "Direct link to Stop-Loss orders and liquidations")
When a position becomes liquidatable, keepers attempt to execute any associated Stop-Loss orders before proceeding with liquidation. If a Stop-Loss order successfully closes the position, the liquidation is skipped. When multiple Stop-Loss orders exist, they are processed in descending order by size — the largest is attempted first.
Stop-Loss execution before liquidation can fail when:
* The trigger price condition is not satisfied at the current oracle prices
* Valid signed prices are unavailable for the order's tokens
* The order fails on-chain validation (for example, insufficient liquidity or max leverage exceeded)
* The execution transaction reverts
If all associated Stop-Loss orders fail to close the position, the keeper proceeds with liquidation. Any remaining orders on the position that were created with auto-cancel enabled are then auto-cancelled (see [auto-cancel TP/SL](https://docs.gmx.io/docs/trading/order-types/#auto-cancel-tpsl)
).
warning
Only Stop-Loss orders (`StopLossDecrease`) are attempted before liquidation. Take-Profit orders (`LimitDecrease`), Limit Increase, and other order types are not. Setting a Stop-Loss above your liquidation price reduces your risk but does not guarantee you avoid liquidation — rapid price movements can cause both the Stop-Loss trigger and the liquidation threshold to be breached in the same oracle update.
Unlike resting limit orders on a centralized exchange, GMX orders don't fill passively as price moves through them. They're executed by keepers against oracle prices. While the liquidation keeper does attempt your Stop-Loss before submitting a liquidation transaction, a separate order-execution keeper runs concurrently — so there's no on-chain guarantee that your Stop-Loss executes before a liquidation check reaches your position.
Auto-Deleveraging (ADL)[](https://docs.gmx.io/docs/trading/liquidations/#auto-deleveraging-adl "Direct link to Auto-Deleveraging (ADL)")
------------------------------------------------------------------------------------------------------------------------------------------
Auto-Deleveraging (ADL) protects pool solvency by automatically reducing profitable positions when the ratio of pending PnL to pool value exceeds the market's configured `MAX_PNL_FACTOR_FOR_ADL` threshold. When this threshold is exceeded, profitable positions may be partially or fully closed to bring the ratio back within bounds.
ADL is most likely to occur in [synthetic markets](https://docs.gmx.io/docs/providing-liquidity/#synthetic-markets)
, where the index token differs from the pool's long collateral token. In these markets, the index token's price can rise faster than the collateral token's price, causing pending profits to outpace the pool's capacity to pay them. For background on how market types affect pool solvency, see [Market types](https://docs.gmx.io/docs/providing-liquidity/#market-types)
.
warning
If ADL is triggered on your position, it's partially or fully closed without your action.
Trading risks[](https://docs.gmx.io/docs/trading/liquidations/#trading-risks "Direct link to Trading risks")
--------------------------------------------------------------------------------------------------------------
GMX mitigates risks through testing, audits, and bug bounties, but trading on any smart contract protocol carries inherent risks.
warning
Use caution when interacting with any smart contract or blockchain application. The list below is non-exhaustive.
* **Smart contract risks:** Vulnerabilities in the protocol code could lead to loss of funds, despite audits and bug bounties.
* **Liquidations:** Positions can be liquidated if collateral falls below the required threshold, resulting in a loss of most or all of the position's collateral.
* **ADL:** In synthetic markets, profitable positions may be automatically deleveraged if pending PnL exceeds the market's configured threshold. See [Auto-Deleveraging (ADL)](https://docs.gmx.io/docs/trading/liquidations/#auto-deleveraging-adl)
for details.
* **Stablecoin pricing:** If a stablecoin depegs from 1 USD, the price used to settle your position may differ from the peg value. There may be a spread from the Chainlink price to 1 USD, and if [Chainlink Data Stream](https://docs.chain.link/data-streams)
prices are used, the spread comes from the bid/ask in the data stream report and may not be anchored to 1 USD.
Additionally, collateral and profits may be backed by bridged or pegged tokens that may not be guaranteed to maintain their peg.
* [Liquidations](https://docs.gmx.io/docs/trading/liquidations/#liquidations)
* [Minimum collateral floor](https://docs.gmx.io/docs/trading/liquidations/#minimum-collateral-floor)
* [Liquidation fees](https://docs.gmx.io/docs/trading/liquidations/#liquidation-fees)
* [Price impact in liquidations](https://docs.gmx.io/docs/trading/liquidations/#price-impact-in-liquidations)
* [Stop-Loss orders and liquidations](https://docs.gmx.io/docs/trading/liquidations/#stop-loss-orders-and-liquidations)
* [Auto-Deleveraging (ADL)](https://docs.gmx.io/docs/trading/liquidations/#auto-deleveraging-adl)
* [Trading risks](https://docs.gmx.io/docs/trading/liquidations/#trading-risks)
---
# Trading overview | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/trading/overview/#__docusaurus_skipToContent_fallback)
On this page
GMX is a decentralized exchange that lets you trade without a username or password. The platform uses oracle-based pricing sourced from aggregated exchange data, which reduces the risk of liquidations from temporary wicks. For details on how pricing works, see [Pricing on GMX](https://docs.gmx.io/docs/trading/order-types/#pricing-on-gmx)
.
GMX V2 uses linear, USD-based PnL with flexible collateral, so your overall exposure can differ from a standard stablecoin-margined linear perp. For a practical explanation, see [Are GMX perps linear or inverse?](https://docs.gmx.io/docs/trading/order-types/#are-gmx-perps-linear-or-inverse)
.
Adding a wallet[](https://docs.gmx.io/docs/trading/overview/#adding-a-wallet "Direct link to Adding a wallet")
----------------------------------------------------------------------------------------------------------------
If you don't have a wallet yet, you can use [Rabby](https://rabby.io/)
.
Connecting and funding your wallet[](https://docs.gmx.io/docs/trading/overview/#connecting-and-funding-your-wallet "Direct link to Connecting and funding your wallet")
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
After you have a wallet, connect it by pressing the "Connect wallet" button on the [Trade](https://app.gmx.io/#/trade)
page.
To fund your wallet with the required gas tokens, refer to your wallet onboarding experience, which offers options for buying, bridging, and on-ramping. If you don't have the required gas token for the network, you can still trade using [Express Trading](https://docs.gmx.io/docs/trading/overview/#express-trading-and-one-click-trading)
.
Multichain trading[](https://docs.gmx.io/docs/trading/overview/#multichain-trading "Direct link to Multichain trading")
-------------------------------------------------------------------------------------------------------------------------
GMX lets you trade from multiple blockchain networks. The method you use depends on which chain your wallet is connected to: direct wallet trading on chains where GMX markets are deployed, or the GMX Account for cross-chain access from other supported networks.
| Connected network | Wallet funds | GMX Account funds |
| --- | --- | --- |
| Arbitrum | ✅ Arbitrum markets | ✅ Arbitrum markets |
| Avalanche | ✅ Avalanche markets | ❌ Not available |
| Botanix | ✅ Botanix markets | ❌ Not available |
| MegaETH | ✅ MegaETH markets | ❌ Not available |
| Other chains (Ethereum, Base, BNB) | ❌ No GMX markets | ✅ Arbitrum markets |
### Direct wallet trading[](https://docs.gmx.io/docs/trading/overview/#direct-wallet-trading "Direct link to Direct wallet trading")
GMX markets are deployed on Arbitrum, Avalanche, Botanix, and MegaETH. When your wallet is connected to any of these chains, you can trade directly using the funds in your wallet — no additional setup required.
### GMX Account (multichain)[](https://docs.gmx.io/docs/trading/overview/#gmx-account-multichain "Direct link to GMX Account (multichain)")
The GMX Account lets you trade on GMX from chains that don't have GMX markets deployed, such as Ethereum, Base, or BNB. You can also use it when connected to Arbitrum. Arbitrum is the only supported settlement chain — all trades through the GMX Account execute on Arbitrum markets.
Here's how it works:
* Your GMX Account balance lives on Arbitrum.
* Deposit from any supported source chain — funds are automatically bridged using Stargate (token transfers) and LayerZero (cross-chain messaging).
* Trade on Arbitrum markets using your GMX Account balance.
* Withdraw to any supported chain, regardless of where you originally deposited.
Think of the GMX Account as a trading wallet on Arbitrum that you can fund and withdraw to from anywhere.
note
The GMX Account is not available on Avalanche, Botanix, or MegaETH. On these chains, only direct wallet trading is supported.
#### Supported deposits and withdrawals[](https://docs.gmx.io/docs/trading/overview/#supported-deposits-and-withdrawals "Direct link to Supported deposits and withdrawals")
The following chains and tokens are available for deposits into and withdrawals from your GMX Account on Arbitrum.
| Chain | Deposit tokens | Withdrawal tokens |
| --- | --- | --- |
| Ethereum | USDC, USDT, ETH | USDC, USDT, ETH |
| Base | USDC, ETH | USDC, ETH |
| BNB | USDC, USDT | USDC, USDT |
note
Bridging for GMX Account deposits and withdrawals is limited by Stargate liquidity caps.
Express Trading and One-Click Trading[](https://docs.gmx.io/docs/trading/overview/#express-trading-and-one-click-trading "Direct link to Express Trading and One-Click Trading")
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
GMX provides different modes to suit trader preferences: Classic Trading, Express Trading, and Express + One-Click Trading. We recommend using Express or Express + One-Click, as they provide the best experience, and trading fees are the same on all modes.
| Mode | Signing method | RPC infrastructure | Gas payments |
| --- | --- | --- | --- |
| Classic Trading | On-chain: wallet signing popup for each trade | Uses your own wallet's RPC | ETH on Arbitrum and MegaETH, AVAX on Avalanche, BTC on Botanix |
| Express Trading | Off-chain: you sign messages locally; GMX broadcasts on-chain via Gelato Relay | GMX-sponsored premium RPCs (high reliability) | USDC or WETH on Arbitrum, USDC or WAVAX on Avalanche, PBTC on Botanix, USDM or WETH on MegaETH |
| Express + One-Click Trading | Off-chain: auto-signed with a locally stored sub-account key (no manual confirmations) | GMX-sponsored premium RPCs (high reliability) | USDC or WETH on Arbitrum, USDC or WAVAX on Avalanche, PBTC on Botanix, USDM or WETH on MegaETH |
### Enabling One-Click Trading[](https://docs.gmx.io/docs/trading/overview/#enabling-one-click-trading "Direct link to Enabling One-Click Trading")
One-Click Trading can be enabled through the settings menu in the top right of the interface. Enabling this feature lets you trade instantly without a wallet signing popup for each trade.
If you are building a delegated trading or one-click trading integration on top of GMX, see [Delegated trading integration](https://docs.gmx.io/docs/api/contracts/delegated-trading/)
.
#### Safety features[](https://docs.gmx.io/docs/trading/overview/#safety-features "Direct link to Safety features")
* Funds from decreasing positions, closing positions, or swaps can only be sent back to your wallet.
* Trades executed without signing popups are limited by the maximum number you authorize. For instance, if you authorize 10 actions, after 10 trades, a wallet signing popup appears to re-authorize further trades.
#### Risks[](https://docs.gmx.io/docs/trading/overview/#risks "Direct link to Risks")
* This feature uses a sub-account key stored locally in your browser. If your browser is compromised, the key could potentially leak, allowing trades to be executed.
* The previously authorized trade limit acts as a safeguard. Even if compromised, a malicious actor can only execute trades up to the authorized limit.
RPC URLs[](https://docs.gmx.io/docs/trading/overview/#rpc-urls "Direct link to RPC URLs")
-------------------------------------------------------------------------------------------
GMX uses different RPC URLs for querying (reading data) and submitting transactions (writing data).
* Reading RPCs are set automatically by the GMX interface and selected from a curated list to ensure fast and reliable data loading.
* Writing RPCs:
* Classic Trading: Set by your wallet.
* Express Trading and Express + One-Click Trading: Automatically set to GMX-sponsored premium RPCs (via Gelato) for superior reliability and speed.
If you're experiencing issues while trading in Classic Trading, consider switching to Express or Express + One-Click Trading through the settings menu. Alternatively, you can manually select another RPC URL via your wallet from options provided on [Chainlist](https://chainlist.org/)
.
* [Adding a wallet](https://docs.gmx.io/docs/trading/overview/#adding-a-wallet)
* [Connecting and funding your wallet](https://docs.gmx.io/docs/trading/overview/#connecting-and-funding-your-wallet)
* [Multichain trading](https://docs.gmx.io/docs/trading/overview/#multichain-trading)
* [Direct wallet trading](https://docs.gmx.io/docs/trading/overview/#direct-wallet-trading)
* [GMX Account (multichain)](https://docs.gmx.io/docs/trading/overview/#gmx-account-multichain)
* [Express Trading and One-Click Trading](https://docs.gmx.io/docs/trading/overview/#express-trading-and-one-click-trading)
* [Enabling One-Click Trading](https://docs.gmx.io/docs/trading/overview/#enabling-one-click-trading)
* [RPC URLs](https://docs.gmx.io/docs/trading/overview/#rpc-urls)
---
# Fees | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/trading/fees/#__docusaurus_skipToContent_fallback)
On this page
This page covers all fees on GMX, including trading fees, swap fees, price impact, funding, borrowing, and network fees.
Open / close fees[](https://docs.gmx.io/docs/trading/fees/#open--close-fees "Direct link to Open / close fees")
-----------------------------------------------------------------------------------------------------------------
The position fee is 0.04% or 0.06% of the position size. It applies when opening, closing, increasing, or partially decreasing a position.
The rate depends on whether your trade improves the balance between long and short open interest:
* 0.04% — your trade reduces the absolute difference between long and short open interest
* 0.06% — your trade increases the absolute difference between long and short open interest
For example, if there is more long open interest than short open interest, opening a short position reduces the imbalance and qualifies for the 0.04% fee. Opening another long position increases the imbalance and incurs the 0.06% fee.
All markets currently use these same rates — there are no per-market overrides.
Swap fees[](https://docs.gmx.io/docs/trading/fees/#swap-fees "Direct link to Swap fees")
------------------------------------------------------------------------------------------
Swap fees on GMX vary by market type — standard or stablecoin — and whether your swap improves or worsens the pool's balance. All fees are calculated on the swap input amount.
### Standard swap fees[](https://docs.gmx.io/docs/trading/fees/#standard-swap-fees "Direct link to Standard swap fees")
For a standard swap, the fee is either 0.05% or 0.07% of the swap amount:
* **0.05%** — if the swap decreases the USD imbalance between the long and short token pools (balance improved)
* **0.07%** — if the swap increases that imbalance (balance not improved)
The pool balance check compares the absolute USD difference between the long and short token pool values before and after your swap. If the post-swap difference is smaller, the lower fee applies.
### Stablecoin swap fees[](https://docs.gmx.io/docs/trading/fees/#stablecoin-swap-fees "Direct link to Stablecoin swap fees")
Stablecoin swap markets use significantly lower fees than standard markets. Rates differ by chain:
| Chain | Fee (balance improved) | Fee (balance not improved) |
| --- | --- | --- |
| Arbitrum (USDC/USDC.e, USDC/USDT, USDC/DAI) | 0.005% | 0.02% |
| Avalanche (USDC/USDT.e, USDC/USDC.e, USDT/USDT.e, USDC/DAI.e) | 0.01% | 0.01% |
### Atomic swap fees[](https://docs.gmx.io/docs/trading/fees/#atomic-swap-fees "Direct link to Atomic swap fees")
Atomic swaps use a separate fee of 3.75% on standard markets. An atomic swap executes in a single transaction and uses a separate fee factor.
tip
Single-token pools (where both the long and short token are the same) have no swap fees on any position operation, because collateral, PnL, and pool backing all use the same token — no token conversion is needed. The BTC/USD \[WBTC.e-WBTC.e\] and ETH/USD \[WETH-WETH\] pools also have position impact factors set to zero, meaning no price impact of any kind on these markets. For a full comparison, see [Single-token vs multi-token pools](https://docs.gmx.io/docs/providing-liquidity/#single-token-vs-multi-token-pools)
.
Slippage[](https://docs.gmx.io/docs/trading/fees/#slippage "Direct link to Slippage")
---------------------------------------------------------------------------------------
Slippage is the difference between the expected execution price when you submit an order and the actual price when the order executes, caused by price movement during the brief window while the order is processing. The default allowed slippage is 1% and can be adjusted in settings or directly in the trade box. Slippage applies to market orders only — limit and trigger orders use a fixed acceptable price you set at order creation.
When you submit a market order, the interface computes an `acceptablePrice` by applying your slippage setting to the mark price. At execution, the contract checks whether the actual execution price satisfies that `acceptablePrice`, and reverts if it doesn't.
For example, consider a Market Increase on ETH/USD:
* Expected execution price: $4,000 (long position).
* Actual price at execution: $4,080 (2% higher) due to volatility.
* Since the price moved against you (higher entry for a long), this is unfavorable slippage.
* The order won't execute unless your allowed slippage was set to 2% or higher.
You can set slippage up to a maximum of 5%. The interface shows a warning when slippage exceeds 2%.
Slippage is separate from price impact. Price impact is an additional positive or negative adjustment based on open interest imbalances, applied independently of slippage. See [Price impact and price impact rebates](https://docs.gmx.io/docs/trading/fees/#price-impact-and-price-impact-rebates)
for details.
Slippage on GMX vs. other platforms
On most trading venues — AMMs, DEX aggregators, and some centralized exchanges — "slippage" refers to the total difference between the quoted price and the execution price, which includes the effect of your trade on market liquidity (what GMX calls price impact).
On GMX, these are two distinct mechanisms:
* **Slippage** protects only against oracle price movement between the time you submit an order and when a keeper executes it.
* **Price impact** is a separate adjustment based on pool imbalance, calculated and applied independently at execution time.
The expected output shown in the interface already accounts for estimated fees and price impact. Your slippage setting adds an additional buffer on top of that estimate to cover oracle price movement during the execution window. This means setting 1% slippage on GMX is not equivalent to setting 1% slippage on a DEX aggregator — on a DEX aggregator, that 1% must cover both price impact and price movement, while on GMX it only needs to cover price movement.
Price impact and price impact rebates[](https://docs.gmx.io/docs/trading/fees/#price-impact-and-price-impact-rebates "Direct link to Price impact and price impact rebates")
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
On GMX, opening a position incurs no price impact at entry. The entry price is determined by the oracle price (`maxPrice` for longs, `minPrice` for shorts). See [Pricing on GMX](https://docs.gmx.io/docs/trading/order-types/#pricing-on-gmx)
for details. Price impact is calculated based on the net open interest imbalance caused by both opens and closes, but it is only applied (charged or credited) when you close or decrease a position — hence the name "net price impact."
Net price impact can be positive or negative, up to a market-specific cap. Unlike orderbook models, GMX caps price impact, so you don't have to worry about orderbook depth. Also unlike orderbooks, a positive price impact means you can be paid rather than penalized.
### Price impact formula[](https://docs.gmx.io/docs/trading/fees/#price-impact-formula "Direct link to Price impact formula")
Price impact is calculated from the change in pool imbalance caused by a trade:
priceImpact = (initialImbalance ^ exponent × factor) − (finalImbalance ^ exponent × factor)
Where:
* **initialImbalance** — the absolute difference between long and short values before the trade
* **finalImbalance** — the absolute difference after the trade
* **factor** and **exponent** — per-market configuration parameters (separate values for positive and negative impact paths)
For **positions**, the imbalance is the difference between long and short open interest. For **swaps**, the imbalance is the difference between the USD values of the long and short token pools.
When a trade reduces the imbalance (final < initial), the result is positive — the trader receives a better price. When it increases the imbalance, the result is negative — the trader receives a worse price. If a trade crosses the balance point (the larger side becomes the smaller side), the calculation splits: the portion toward balance uses the positive factor and the portion past balance uses the negative factor.
For position operations, price impact adjusts the entry or exit price rather than deducting from collateral, which preserves the intended leverage ratio. The protocol also maintains a virtual inventory that tracks impact across correlated markets to prevent users from reducing their net impact by opening opposing positions in different markets.
For the SDK implementation of this formula, see [`getPriceImpactUsd`](https://docs.gmx.io/docs/sdk/v1/exports/utils/fees/priceImpact/#getpriceimpactusd)
and related functions in the price impact module.
The prices shown in the trade history — for both opens and closes — are the mark prices (oracle prices) at which the orders executed. For closing, the net price impact is a separate value not included in the displayed mark price. Instead, price impact adjusts your collateral received independently. For example, if the close price is $1,900 and the net price impact is +$1, the mark price remains $1,900 but you receive an additional $1 in collateral, making your effective value $1,901. Conversely, a -$1 net price impact means $1 is deducted from your collateral received.
You can view net price impact in the net value tooltip on the positions list or close modal. The claimable rebate amount is also included in the net value calculation, so your position's net value reflects any rebate you're owed. For a detailed breakdown, enable **"Break down net price impact"** in the display settings — this shows the price impact stored when you opened the position, the price impact from closing, and how they combine into the net amount.
### Price impact caps by market[](https://docs.gmx.io/docs/trading/fees/#price-impact-caps-by-market "Direct link to Price impact caps by market")
Negative and positive price impact have separate caps. The max negative price impact varies per market based on liquidity depth (see table below), while the max positive price impact is 40 bps (0.4%) for most markets. This creates an asymmetry — for example, a market with a 500 bps negative cap still has only a 40 bps positive cap.
Negative price impact caps by market:
* Major markets (BCH, BNB, BTC, ETH, PEPE, SOL): 50 bps (0.5%) cap
* Lower-liquidity markets: 75–1000 bps (0.75%–10%) cap, depending on the market's liquidity depth
For example, if the cap is 50 bps, you never pay more than 50 bps in price impact, regardless of order size. Markets with less liquidity have higher caps to better reflect execution conditions.
| Cap | Markets |
| --- | --- |
| 50 bps | BCH, BNB, BTC, ETH, PEPE, SOL, XAUT |
| 75 bps | BONK, LTC |
| 100 bps | ASTER, AVAX, CRO, CRV, DOGE, ENA, FLOKI, HYPE, LINK, NEAR, SHIB, TRX, XPL, ZEC |
| 150 bps | 0G, AAVE, ADA, APE, APT, ARB, ATOM, FARTCOIN, INJ, OP, PENGU, PUMP, TON, TRUMP, UNI, WLD, XLM |
| 200 bps | AR, DASH, DYDX, EIGEN, FIL, ICP, ONDO, SUI, VIRTUAL, XMR, XRP |
| 250 bps | DOT, HBAR, IP, KTA, LDO, MOODENG, ORDI, S, SEI, TAO, TIA |
| 300 bps | AERO, AIXBT, ANIME, AVNT, BERA, BOME, CAKE, FET, JUP, KAS, LINEA, OM, PENDLE, POL, SYRUP, WIF, ZORA |
| 400 bps | WLFI |
| 500 bps | ALGO, BRETT, CHZ, CVX, DOLO, GMX, JTO, LIT, MEME, MEW, MNT, MON, OKB, PI, RENDER, SKY, SPX6900, STX, WELL, ZRO |
| 700 bps | SATS |
| 1000 bps | CC, MELANIA, MET, MORPHO, VVV |
You can view the current price impact cap for each market on the [Monitor](https://app.gmx.io/#/monitor)
page under the Config column.
For large orders (typically $1,000,000 or more with negative price impact exceeding 0.2%), consider using TWAP to reduce price impact by executing in smaller parts over time. For swaps, positive price impact increases the tokens you receive, while negative price impact decreases them.
note
Capped negative price impact is factored into liquidation price calculations. Positive price impact is excluded. For details, see [Price impact in liquidations](https://docs.gmx.io/docs/trading/liquidations/#price-impact-in-liquidations)
.
Long and short open interest in markets is typically balanced, leading to minimal net price impact. During high volatility, imbalances can cause higher net price impacts. Price impact rebates help mitigate this. If a decrease order has a negative net price impact exceeding the market's cap, the excess becomes claimable as a rebate after a five-day delay.
tip
You can claim rebates in the claims section on the trade page. The delay protects against manipulation, and rebates are reviewed before being granted.
Price impact cap configurations are adjusted per market based on recommendations from Chaos Labs to align with current liquidity conditions.
Funding fees[](https://docs.gmx.io/docs/trading/fees/#funding-fees "Direct link to Funding fees")
---------------------------------------------------------------------------------------------------
Funding fees may be a cost or a credit while a position is open. The funding fee rate is visible on the interface when you open or review a trade. The rate changes over time based on the balance of longs and shorts in the market.
If you receive positive funding fees, you can claim them using the "Claim" button in the "Claimable Funding" box of the [Trade](https://app.gmx.io/#/v2)
page.
### Adaptive funding[](https://docs.gmx.io/docs/trading/fees/#adaptive-funding "Direct link to Adaptive funding")
Funding rates gradually adjust over time based on the ratio of long to short open interest. A sudden shift in the OI balance does not immediately reverse the funding direction — the previously larger side may continue to receive funding until the rate adjusts.
Which side pays and at what rate is governed by a signed state variable, `savedFundingFactorPerSecond`, that the contract updates on every market transaction. A positive value means longs pay shorts; a negative value means shorts pay longs.
The imbalance ratio used for threshold comparisons and rate adjustments is:
longShortImbalance = [abs(longOpenInterest - shortOpenInterest) / totalOpenInterest] ^ fundingExponentFactor
The rate adjusts according to three zones defined by this imbalance relative to two thresholds, `thresholdForStableFunding` and `thresholdForDecreaseFunding`:
* **Above `thresholdForStableFunding`:** The imbalance is large. The rate increases by `longShortImbalance × fundingIncreaseFactorPerSecond` per second until the imbalance falls or the rate reaches its maximum cap.
* **Between the two thresholds:** The rate remains constant.
* **Below `thresholdForDecreaseFunding`:** The imbalance is small. The rate decreases by `fundingDecreaseFactorPerSecond` per second toward zero.
If the imbalance reverses direction (for example, longs were dominant and shorts become dominant), the rate immediately starts increasing in the opposite direction, regardless of which threshold zone it was in.
For example, suppose longs exceed shorts and the rate is increasing with longs paying shorts. If shorts are opened or longs are closed so that shorts now exceed longs, the rate begins increasing in the opposite direction — toward shorts paying longs — until a threshold is reached or the maximum cap is hit.
### Accrual and settlement[](https://docs.gmx.io/docs/trading/fees/#accrual-and-settlement "Direct link to Accrual and settlement")
Funding fees accrue continuously using per-second arithmetic. Each market stores `savedFundingFactorPerSecond` (the signed adaptive rate) and a `fundingUpdatedAt` timestamp on-chain. The unsigned `fundingFactorPerSecond` for the paying side is derived on-demand inside `getNextFundingAmountPerSize` and is never stored persistently. The total funding accrued for the paying side over a period is:
fundingUsd = sizeOfPayingSide × durationInSeconds × fundingFactorPerSecond
Settlement is event-driven, not scheduled. The on-chain funding state updates whenever a transaction touches the market — executing an order, a deposit, or a withdrawal. Between transactions, funding accrues implicitly via the time elapsed since the last update. When a position is modified or closed, the contract computes the exact funding owed using the elapsed time since that last update.
Per-position settlement uses a checkpoint pattern. Each position stores a `fundingFeeAmountPerSize` value recorded at the time the position was last updated. When the position is settled, the contract computes:
positionFundingFeeAmount = positionSizeInUsd × (latestFundingAmountPerSize − position.fundingFeeAmountPerSize) / PRECISION
The result is rounded up for the paying side and rounded down for the receiving side.
note
The `fundingFactorPerSecond` exposed by the interface and API represents the rate for the paying side. The receiving side's effective rate is scaled proportionally by `payingOI / receivingOI`, so total funding inflow equals total outflow.
Borrow fees[](https://docs.gmx.io/docs/trading/fees/#borrow-fees "Direct link to Borrow fees")
------------------------------------------------------------------------------------------------
A borrow fee applies to open positions to prevent traders from reserving all pool liquidity by opening equal long and short positions at minimal cost. If the side with larger open interest fully reserves the pool, the borrow fee also incentivizes liquidity providers to add more capital to the pool.
Only the side with the larger open interest pays the borrow fee. If longs exceed shorts, longs pay; if shorts exceed longs, shorts pay.
The borrow fee accrues continuously per second and is settled when you modify or close a position. The fee is calculated as:
borrowingFeeUsd = positionSizeUsd × (cumulativeBorrowingFactor − positionBorrowingFactor)
where `cumulativeBorrowingFactor` increases over time at `borrowingFactorPerSecond`, and `positionBorrowingFactor` is the snapshot taken when your position was last updated.
The current borrow fee rate is shown on the trade interface as a percentage per hour, applied to your position size. The rate changes over time based on pool utilization.
### Rate models[](https://docs.gmx.io/docs/trading/fees/#rate-models "Direct link to Rate models")
Most markets use a kink model (two-segment curve). The rate increases linearly up to an optimal utilization threshold, then rises more steeply above it:
borrowingFactorPerSecond = baseBorrowingFactor × usageFactorif usageFactor > optimalUsageFactor: diff = usageFactor − optimalUsageFactor additional = (aboveOptimalUsageBorrowingFactor − baseBorrowingFactor) × diff / (1 − optimalUsageFactor) borrowingFactorPerSecond += additional
A typical configuration is:
* Optimal utilization: 75%
* Rate at or below 75% utilization: 45–55% per year
* Rate at 100% utilization: 100–130% per year
Some markets use a power (curve) model instead:
borrowingFactorPerSecond = borrowingFactor × reservedUsd ^ borrowingExponentFactor / poolUsd
The default base configuration uses a linear exponent of 1, which targets approximately 15.77% per year at 100% utilization.
Of the borrow fee collected, 63% goes to the pool (accruing to liquidity providers) and 37% goes to the protocol fee receiver.
Network fee[](https://docs.gmx.io/docs/trading/fees/#network-fee "Direct link to Network fee")
------------------------------------------------------------------------------------------------
Every trade on GMX involves two transactions: your request and the keeper's execution. The network fee covers the gas cost of the second transaction.
1. You send a transaction to request an action — open, close, deposit collateral, or withdraw collateral.
2. A keeper observes the request on-chain and executes it in a separate transaction.
The gas cost of the keeper's execution transaction is what the interface calls the network fee. Because gas prices can spike between your request and the keeper's execution, the interface charges a max network fee that overestimates the likely cost. When the keeper executes your order, only the gas actually consumed is paid to the keeper — the remainder is refunded to your account automatically.
The interface displays the network fee row after subtracting an estimated refund. The full max network fee amount, along with an estimated refund breakdown, is visible in the tooltip next to the fee row.
note
The estimated refund shown in the tooltip is an approximation based on recent data, not a guaranteed amount. The actual refund depends on gas prices at the time of execution.
### Max network fee buffer[](https://docs.gmx.io/docs/trading/fees/#max-network-fee-buffer "Direct link to Max network fee buffer")
The max network fee includes a configurable buffer to guard against gas price spikes. You can adjust this buffer in the **Max network fee buffer** setting, found in the settings panel.
When Express Trading is enabled, an additional 10% buffer is applied on top of your configured buffer to account for the higher gas reliability requirements of Express order execution.
### TP/SL and additional orders[](https://docs.gmx.io/docs/trading/fees/#tpsl-and-additional-orders "Direct link to TP/SL and additional orders")
When you place a position with Take-Profit or Stop-Loss orders, the max network fee includes fees for those additional orders. If those orders don't trigger and are canceled, their network fees are refunded in full.
Arbitraging[](https://docs.gmx.io/docs/trading/fees/#arbitraging "Direct link to Arbitraging")
------------------------------------------------------------------------------------------------
GMX's fee and price impact mechanics reward trades that rebalance pools, which creates arbitrage opportunities for both perpetuals and swaps. When a pool is imbalanced, you can profit while helping restore balance.
### Perps[](https://docs.gmx.io/docs/trading/fees/#perps "Direct link to Perps")
You can arbitrage positive price impact and [funding fees](https://docs.gmx.io/docs/trading/fees/#funding-fees)
on perpetual markets.
For example, if ETH long open interest exceeds short open interest, opening a short position reduces the imbalance. The contract calculates price impact based on the change in the absolute difference between long and short open interest before and after your trade. Because the imbalance decreases, you receive a positive price impact — a better entry price than the current mark price. While the position is open, you also earn funding fees, because the dominant (long) side pays the minority (short) side.
If ETH long positions subsequently close such that short open interest exceeds long open interest, closing your short position also reduces the (now reversed) imbalance, and you receive a positive price impact on exit — a better exit price than the mark price.
For markets where the index token is the same as the collateral token (for example, using ETH as collateral in the ETH/USD market), you can open a delta-neutral short position by posting the index token as collateral. This exposes you to funding income without directional ETH price risk. When arbitraging with a long position, opening a 1x long with a stablecoin as collateral gives you 1x exposure to the index token without additional leverage.
note
With adaptive funding, the rate decreases toward the market's `minFundingFactorPerSecond` floor as open interest becomes balanced — not necessarily to zero. Factor this in when sizing an arbitrage position, as the funding income may be lower by the time open interest equalizes.
Pool balances and funding rates per hour can be viewed on the [Stats](https://app.gmx.io/#/stats)
page. For programmatic access, the [`/markets/info`](https://docs.gmx.io/docs/api/rest-api/markets/)
endpoint provides near-live funding rates (refreshed every 5 seconds), while the [`/rates`](https://docs.gmx.io/docs/api/gmx-api/get-rates/)
endpoint provides hourly historical snapshots.
### Swaps[](https://docs.gmx.io/docs/trading/fees/#swaps "Direct link to Swaps")
You can arbitrage positive price impact on swap markets.
Swap price impact is calculated based on the change in the absolute USD difference between the long token pool value and the short token pool value. If your swap reduces that difference, you receive a positive price impact — additional output tokens beyond the baseline swap amount.
For example, in the ETH/USDC pool, if the USD value of ETH in the pool exceeds the USD value of USDC, swapping USDC for ETH reduces the imbalance and earns a positive price impact. You receive more ETH than the unadjusted swap would provide.
Pool balances can be viewed on the [Stats](https://app.gmx.io/#/stats)
page.
* [Open / close fees](https://docs.gmx.io/docs/trading/fees/#open--close-fees)
* [Swap fees](https://docs.gmx.io/docs/trading/fees/#swap-fees)
* [Standard swap fees](https://docs.gmx.io/docs/trading/fees/#standard-swap-fees)
* [Stablecoin swap fees](https://docs.gmx.io/docs/trading/fees/#stablecoin-swap-fees)
* [Atomic swap fees](https://docs.gmx.io/docs/trading/fees/#atomic-swap-fees)
* [Slippage](https://docs.gmx.io/docs/trading/fees/#slippage)
* [Price impact and price impact rebates](https://docs.gmx.io/docs/trading/fees/#price-impact-and-price-impact-rebates)
* [Price impact formula](https://docs.gmx.io/docs/trading/fees/#price-impact-formula)
* [Price impact caps by market](https://docs.gmx.io/docs/trading/fees/#price-impact-caps-by-market)
* [Funding fees](https://docs.gmx.io/docs/trading/fees/#funding-fees)
* [Adaptive funding](https://docs.gmx.io/docs/trading/fees/#adaptive-funding)
* [Accrual and settlement](https://docs.gmx.io/docs/trading/fees/#accrual-and-settlement)
* [Borrow fees](https://docs.gmx.io/docs/trading/fees/#borrow-fees)
* [Rate models](https://docs.gmx.io/docs/trading/fees/#rate-models)
* [Network fee](https://docs.gmx.io/docs/trading/fees/#network-fee)
* [Max network fee buffer](https://docs.gmx.io/docs/trading/fees/#max-network-fee-buffer)
* [TP/SL and additional orders](https://docs.gmx.io/docs/trading/fees/#tpsl-and-additional-orders)
* [Arbitraging](https://docs.gmx.io/docs/trading/fees/#arbitraging)
* [Perps](https://docs.gmx.io/docs/trading/fees/#perps)
* [Swaps](https://docs.gmx.io/docs/trading/fees/#swaps)
---
# Positions and order types | GMX Docs
[Skip to main content](https://docs.gmx.io/docs/trading/order-types/#__docusaurus_skipToContent_fallback)
On this page
This page covers how pricing works on GMX, how to open and manage positions, the available order types, and swaps.
Pricing on GMX[](https://docs.gmx.io/docs/trading/order-types/#pricing-on-gmx "Direct link to Pricing on GMX")
----------------------------------------------------------------------------------------------------------------
GMX uses oracle-based pricing rather than an orderbook model. Understanding this is important for limit orders, stop-loss orders, and other conditional order types.
### Oracle prices: minPrice and maxPrice[](https://docs.gmx.io/docs/trading/order-types/#oracle-prices-minprice-and-maxprice "Direct link to Oracle prices: minPrice and maxPrice")
GMX receives price data from [Chainlink Data Streams](https://docs.chain.link/data-streams)
as a spread with two values derived from the bid and ask in each data stream report:
* minPrice: The lower bound of the price spread (bid)
* maxPrice: The upper bound of the price spread (ask)
The oracle price used for both triggering and execution depends on the operation:
| Operation | Oracle price used | Reasoning |
| --- | --- | --- |
| Long open | maxPrice | You pay the higher price to enter a long |
| Long close / liquidation | minPrice | You receive the lower price when exiting a long |
| Short open | minPrice | You sell at the lower price to enter a short |
| Short close / liquidation | maxPrice | You buy back at the higher price when exiting a short |
Entry price
Your entry price is the Chainlink oracle price used for your order — `maxPrice` for longs, `minPrice` for shorts. No price impact is applied at entry; it is [stored and applied when you close](https://docs.gmx.io/docs/trading/fees/#price-impact-and-price-impact-rebates)
. Because the entry price is the market price from Chainlink with no additional adjustments, it is not displayed separately in the interface.
### Mark price[](https://docs.gmx.io/docs/trading/order-types/#mark-price "Direct link to Mark price")
The mark price is the midpoint of the oracle spread: `(minPrice + maxPrice) / 2`
The mark price is used for:
* Display in the interface and charts
* Funding rate calculations
* Price impact calculations (deposits, swaps, position sizing)
It is not used for order triggering or execution.
### Trigger price evaluation[](https://docs.gmx.io/docs/trading/order-types/#trigger-price-evaluation "Direct link to Trigger price evaluation")
This is a key difference from orderbook exchanges. On orderbook platforms, limit and stop orders fill when a counterparty matches at that price level in the orderbook. On GMX, there is no orderbook — trigger prices are evaluated against minPrice or maxPrice depending on the order direction, which is the same price used for execution.
Example: You set a Stop-Loss at $3,900 for your ETH long. The order triggers when minPrice reaches $3,900 (not when the mark price reaches $3,900). Since closing a long uses minPrice, the trigger and execution price are the same oracle price.
The spread between minPrice and maxPrice is typically small (a few basis points) but can widen during volatility.
### Charts[](https://docs.gmx.io/docs/trading/order-types/#charts "Direct link to Charts")
The current price displayed on the chart — the live price line and the price in the chart header — is the mark price: `(minPrice + maxPrice) / 2`.
Candlestick charts use:
* Open: previous candle's close (the average price at the end of the prior period)
* Close: average price (minPrice + maxPrice) / 2
* High: highest maxPrice reported by oracles
* Low: lowest minPrice reported by oracles
This means a candle may show your trigger price being reached, but your order may not trigger. For example, if you set a Limit Increase to open a long at $3,900, the chart might show a low of $3,900 (based on minPrice), but your order uses maxPrice — which may have only reached $3,901.
### Price gaps and volatility[](https://docs.gmx.io/docs/trading/order-types/#price-gaps-and-volatility "Direct link to Price gaps and volatility")
During rapid price movements, the oracle price at execution may differ from your trigger price. This applies to all trigger-based orders (Limit Increase, Limit Decrease, Stop Market, TP/SL).
Examples:
* Stop-Loss at $4,000: Oracle price updates from $4,010 → $3,990 (skipping past $4,000). Order triggers and executes at $3,990.
* Take-Profit at $4,100: Oracle price updates from $4,090 → $4,110 (skipping past $4,100). Order triggers and executes at $4,110.
Trigger orders are not guaranteed to execute if the oracle price does not reach the specified trigger price.
Opening a position[](https://docs.gmx.io/docs/trading/order-types/#opening-a-position "Direct link to Opening a position")
----------------------------------------------------------------------------------------------------------------------------
On the [Trade](https://app.gmx.io/#/v2)
page, select "Long" or "Short," choose an order type (Market, Limit, or via the "More" dropdown: Stop Market or TWAP), and configure your position using the fields described below.
### Pool and collateral[](https://docs.gmx.io/docs/trading/order-types/#pool-and-collateral "Direct link to Pool and collateral")
Select the market you want to trade from the market selector at the top left of the trade page. At the top of the trade box, you can configure:
* **Pool** — if multiple pools are available for your market (for example, BTC-USDC and BTC-USDT), choose based on your preferred collateral, net rates, and price impact. Each pool may have different funding/borrowing rates and price impact levels depending on its balance.
* **Collateral** — choose which token your position's collateral is stored as. For example, in the BTC-USDC market, you can choose BTC or USDC.
Collateral choice affects your exposure:
* **Long ETH with ETH collateral:** You gain exposure from both the long position and the collateral itself. For example, a 0.1 ETH long with 1 ETH as collateral gives 1.1 ETH total exposure.
* **Long ETH with USDC collateral:** Exposure comes only from the long position. Useful if switching frequently between longing and shorting.
* **Short ETH with ETH collateral:** Useful for delta neutral strategies to earn funding fees. For example, a 1 ETH short with 1 ETH as collateral.
* **Short ETH with USDC collateral:** Useful if switching frequently between longing and shorting.
warning
If you open a long position with non-stablecoin collateral, your liquidation price may change as the collateral's price fluctuates.
### Margin, size, and leverage[](https://docs.gmx.io/docs/trading/order-types/#margin-size-and-leverage "Direct link to Margin, size, and leverage")
The trade box has three interconnected fields:
* **Margin** — the amount of collateral you deposit. You can select the pay token and fill your available balance from this field.
* **Size** — the total position size. You can toggle between USD and token units (for example, BTC). A percentage slider below the size field lets you quickly set the size as a percentage of your maximum available amount.
* **Leverage** — displayed at the top of the trade box. Click on it to open the leverage adjuster, which has a slider with preset marks (0.1x, 1x, 2x, 5x, 10x, 25x, 50x, 100x) and a manual input field.
How these fields interact depends on the **Manual leverage** setting (in Settings):
* **Manual leverage on (default):** You set the leverage and one of the other fields. The third is calculated automatically. For example, setting 10x leverage and 100 USDC margin gives a 1,000 USD position size.
* **Manual leverage off:** You set margin and size freely, and leverage is derived from their ratio.
### Are GMX perps linear or inverse?[](https://docs.gmx.io/docs/trading/order-types/#are-gmx-perps-linear-or-inverse "Direct link to Are GMX perps linear or inverse?")
GMX V2 uses linear PnL math rather than inverse perp math. In simple terms, GMX calculates profit and loss from your token exposure, while inverse perps are built around a fixed USD contract value and usually pay profit and loss in the underlying token. Internally, GMX keeps both token size and USD position value for pricing and risk calculations, while collateral remains flexible within the market's supported tokens.
For linear perps, price-move PnL equals `size in tokens × price move`, which is equivalently the position's USD notional at entry multiplied by the percentage price change. For example, a 10,000 USD ETH position that moves 10% has 1,000 USD of profit or loss before fees and price impact. On GMX, this is true whether your collateral is ETH or USDC.
What changes with collateral is your additional exposure outside the position itself:
* **Stablecoin collateral** feels more linear because the collateral value stays relatively stable while the position PnL moves.
* **Non-stable collateral** can feel more inverse-like because the collateral value can rise or fall with the market too.
Profitable longs use the market's long token and profitable shorts use the market's short token for PnL payments. In the close modal, the token you receive as profit can be changed, but this is done through a swap from that PnL token, so the final output token does not by itself determine whether a position is linear or inverse.
In practice, GMX is best thought of as a **multi-collateral perpetual market with linear, USD-based PnL**, not as an inverse perp venue.
### Take-Profit / Stop-Loss[](https://docs.gmx.io/docs/trading/order-types/#take-profit--stop-loss "Direct link to Take-Profit / Stop-Loss")
You can set basic TP/SL orders directly in the trade box before opening a position. Toggle the TP/SL section to configure a trigger price and view estimated PnL for each. These orders fully close your position when triggered. For more advanced TP/SL configurations (partial closes, multiple entries), use the positions list after opening the position.
### Execution details[](https://docs.gmx.io/docs/trading/order-types/#execution-details "Direct link to Execution details")
Before submitting, expand the "Execution details" section at the bottom of the trade box to review: liquidation price, fees, network fee, collateral spread, allowed slippage, stored price impact, leverage, size, and collateral. Adjust the allowed slippage in this section or in Settings if needed.
### Max leverage[](https://docs.gmx.io/docs/trading/order-types/#max-leverage "Direct link to Max leverage")
The max allowed leverage of a pool decreases as the total open interest of the pool increases. This guards the pool against gaming of price impact using high-leverage positions. This mainly affects markets with less liquidity but can affect high-liquidity markets if the open interest is very large.
The interface shows a warning if the max allowed leverage would be exceeded. This only affects opening or increasing positions — it does not affect positions that have already been opened. For closing or decreasing positions, if the max allowed leverage would be exceeded, the order can still execute, but the collateral within the position would not be reduced.
note
When depositing collateral via the edit button, the interface validates against the full max leverage derived from `minCollateralFactor`. This is less restrictive than the halved limit (`max leverage / 2`) used for opening or increasing positions. A deposit is only blocked when the resulting leverage would exceed the actual market limit — not the halved limit applied to opens.
Managing positions[](https://docs.gmx.io/docs/trading/order-types/#managing-positions "Direct link to Managing positions")
----------------------------------------------------------------------------------------------------------------------------
After opening a trade, you can view it under your positions list. Each position row displays the market and side, size, net value, collateral, entry price, mark price, liquidation price, and any active TP/SL orders.
You can also interact directly from the position row:
* Click the edit button next to the collateral value to deposit or withdraw collateral, adjusting your leverage and liquidation price.
* Use the "Market" or "TWAP" buttons in the Close column to close the position (see [Closing a position](https://docs.gmx.io/docs/trading/order-types/#closing-a-position)
).
### Position actions[](https://docs.gmx.io/docs/trading/order-types/#position-actions "Direct link to Position actions")
Click the "..." menu on a position row to access additional actions:
* **Increase size** — add to your position using a Market, Limit, Stop Market, or TWAP order.
* **Set TP/SL** — create, edit, or cancel Take-Profit and Stop-Loss orders. You can set multiple TP/SL orders per position with different trigger prices and sizes.
* **Share position** — generate a shareable image of your position with optional PnL display, and share it via link or on X.
### Net value and collateral tooltips[](https://docs.gmx.io/docs/trading/order-types/#net-value-and-collateral-tooltips "Direct link to Net value and collateral tooltips")
Hover over the net value to see a breakdown of initial collateral, PnL, borrow fees, funding fees, net price impact, price impact rebates, and close fees. Hover over the collateral to see accrued borrow and funding fees, daily fee rates, and claimable positive funding fees.
Closing a position[](https://docs.gmx.io/docs/trading/order-types/#closing-a-position "Direct link to Closing a position")
----------------------------------------------------------------------------------------------------------------------------
Close a position partially or completely by clicking the "Market" or "TWAP" button in the position row. This opens a dialog where you configure the close amount, receive token, and execution details. Closing realizes pending profits or losses proportional to the percentage of the position that is closed.
### Close amount[](https://docs.gmx.io/docs/trading/order-types/#close-amount "Direct link to Close amount")
Enter the USD amount to close, or use the percentage slider (0–100%) and quick-select buttons (10%, 25%, 50%, 75%) to set a partial or full close.
If the remaining position size would be below 1 USD, the close is treated as a full close instead of leaving a dust position.
### Market vs TWAP close[](https://docs.gmx.io/docs/trading/order-types/#market-vs-twap-close "Direct link to Market vs TWAP close")
* **Market** — closes immediately at the current oracle price.
* **TWAP** — splits the close into multiple smaller orders executed over a specified duration. Configure the duration (hours and minutes), number of parts, and review the calculated frequency and size per part. TWAP is recommended for large positions to reduce price impact — the interface suggests switching to TWAP if it detects high net price impact.
### Keep leverage[](https://docs.gmx.io/docs/trading/order-types/#keep-leverage "Direct link to Keep leverage")
When partially closing with a Market order, the "Keep leverage" toggle maintains your current leverage ratio by proportionally reducing collateral alongside the size. This is enabled by default and disabled for full closes.
If a partial close would leave the position with collateral below the protocol minimum, the close is blocked. This can happen more easily when "Keep leverage" is enabled, since reducing size also withdraws collateral proportionally.
### Receive token[](https://docs.gmx.io/docs/trading/order-types/#receive-token "Direct link to Receive token")
By default, long positions receive the asset you are longing (for example, ETH) and short positions receive the stablecoin used as collateral (for example, USDC). You can change the receive token in the close dialog — if this requires a swap, the associated swap fees are shown. If the swap fails during execution, the decrease order may output two tokens (one from each side of the pool) instead of a single token.
### Execution details[](https://docs.gmx.io/docs/trading/order-types/#execution-details-1 "Direct link to Execution details")
Before confirming, expand the "Execution details" section to review exit price, trade fees, network fee, allowed slippage, leverage, size, and collateral transitions. The net price impact and fees summary is shown above this section.
### PnL[](https://docs.gmx.io/docs/trading/order-types/#pnl "Direct link to PnL")
The PnL from price movement is proportional to your position size. For example, if you open a 10,000 USD long ETH position and the price of ETH increases by 10%, the profit is 1,000 USD. If the price decreases by 10%, the loss is 1,000 USD. This excludes changes in your collateral's value — if your collateral is a non-stablecoin asset, its price movement also affects your net value.
Realized PnL shown in the trade history is labeled "Realized PnL after fees and net price impact." This value includes closing fees, borrowing fees, funding fees, UI fees, and net price impact — but it does not include the opening fee. The opening fee is deducted from the initial margin you pay when opening a position (initial margin − opening fee = initial collateral), so the initial collateral displayed on the interface already accounts for it. Because the opening fee is absorbed into the starting collateral, it is not subtracted again when calculating realized PnL at close.
For example, holding a position for an extended period accumulates borrowing fees, and closing during an imbalanced market may incur negative price impact. Hover over the net value in the positions list for a full breakdown. See [Fees](https://docs.gmx.io/docs/trading/fees/)
for details on each fee type.
Leverage for a position is displayed as (position size) / (position collateral). You can change this to (position size + PnL) / (position collateral) in "Settings."
Swaps[](https://docs.gmx.io/docs/trading/order-types/#swaps "Direct link to Swaps")
-------------------------------------------------------------------------------------
GMX supports perpetual trading and swaps. To swap, click the "Swap" tab on the [Trade](https://app.gmx.io/#/v2)
page.
### Swap order types[](https://docs.gmx.io/docs/trading/order-types/#swap-order-types "Direct link to Swap order types")
Three order types are available for swaps:
* **Market Swap** — executes immediately at the current oracle price, subject to your allowed slippage setting.
* **Limit Swap** — executes when the exchange rate reaches your specified limit price. See [Limit orders](https://docs.gmx.io/docs/trading/order-types/#limit-orders)
for details on how limit swap execution works.
* **TWAP Swap** — splits the swap into smaller parts executed over a specified duration to reduce price impact. See [TWAP orders](https://docs.gmx.io/docs/trading/order-types/#twap-orders)
for configuration details.
Wrap and unwrap operations (for example, ETH to WETH on Arbitrum, AVAX to WAVAX on Avalanche) are restricted to Market Swap only.
### Swap configuration[](https://docs.gmx.io/docs/trading/order-types/#swap-configuration "Direct link to Swap configuration")
The swap form has two main fields:
* **Pay** — the token and amount you are swapping from. You can fill your available balance from this field.
* **Receive** — the token and amount you receive. For TWAP swaps, this value is approximate since the final amount depends on execution conditions across each part.
Use the swap button between the fields to reverse the token pair. For Limit Swaps, click the current mark price to prefill the limit price field.
### Routing[](https://docs.gmx.io/docs/trading/order-types/#routing "Direct link to Routing")
Swaps are routed through GM pools. The available tokens for swapping are the collateral tokens across all active GM pools on the connected network. This includes long tokens (for example, ETH, BTC), short tokens (for example, USDC, USDT), and native tokens where wrapped versions exist.
### Execution details[](https://docs.gmx.io/docs/trading/order-types/#execution-details-2 "Direct link to Execution details")
Before confirming, expand the "Execution details" section to review:
* **Spread** — the combined bid-ask spread for both tokens (Market Swap only). A warning is displayed if the spread is high.
* **Min. receive** — the minimum output amount after slippage is applied. See [Min. receive](https://docs.gmx.io/docs/trading/order-types/#min-receive)
for details.
* **Price impact / fees** — the net price impact percentage and total fee percentage. Positive price impact means you receive more tokens than expected. See [Price impact](https://docs.gmx.io/docs/trading/fees/#price-impact-and-price-impact-rebates)
and [Swap fees](https://docs.gmx.io/docs/trading/fees/#swap-fees)
for details.
* **Network fee** — the estimated blockchain execution fee. Overestimated amounts are refunded after execution.
### Min. receive[](https://docs.gmx.io/docs/trading/order-types/#min-receive "Direct link to Min. receive")
Min. receive is a slippage protection mechanism for swaps. It sets the minimum output amount you accept — if the actual output falls below this value, the swap reverts and you keep your input tokens.
The min. receive value is derived from the expected output and your allowed slippage:
minReceive = expectedOutput × (1 − allowedSlippage)
For example, with 1% slippage and an expected output of 1,000 USDC, the min. receive is 990 USDC.
#### Market Swaps vs. Limit Swaps[](https://docs.gmx.io/docs/trading/order-types/#market-swaps-vs-limit-swaps "Direct link to Market Swaps vs. Limit Swaps")
Min. receive is applied differently depending on the order type:
* **Market Swap** — the interface applies your allowed slippage automatically. It calculates the expected output, reduces it by your slippage tolerance, and sends the reduced value to the contract as `minOutputAmount`.
* **Limit Swap** — slippage is not applied. The expected output based on your limit price is sent directly as `minOutputAmount`, because the limit price itself provides price protection.
You can configure your slippage tolerance in the swap form's execution details section, which offers preset options of 0.3%, 0.5%, 1%, and 1.5%, or enter a custom value. Slippage can also be set in settings. The default is 1% (100 basis points).
#### What happens when the minimum isn't met[](https://docs.gmx.io/docs/trading/order-types/#what-happens-when-the-minimum-isnt-met "Direct link to What happens when the minimum isn't met")
If the actual swap output is less than `minOutputAmount`, the contract reverts the transaction. You don't receive partial output — the swap either completes above the minimum or doesn't execute at all.
#### Factors that affect the output amount[](https://docs.gmx.io/docs/trading/order-types/#factors-that-affect-the-output-amount "Direct link to Factors that affect the output amount")
The final output amount is determined by three factors:
* **Swap fees** — deducted from the swap amount. Rates depend on whether the swap improves pool balance and on the token types involved. See [Swap fees](https://docs.gmx.io/docs/trading/fees/#swap-fees)
for rates.
* **Price impact** — based on pool balance changes caused by your swap. Positive price impact increases your output; negative price impact reduces it. See [Price impact](https://docs.gmx.io/docs/trading/fees/#price-impact-and-price-impact-rebates)
.
* **Oracle price movement** — the oracle price may change between when you submit the swap and when a keeper executes it.
The expected output estimate already accounts for fees and price impact at submission time. Oracle price movement during the execution window is the remaining source of divergence — the slippage buffer protects against this.
note
On most DEX aggregators and AMMs, "slippage" covers everything that can reduce your output — including the price impact of your trade on liquidity pools. On GMX, slippage and [price impact](https://docs.gmx.io/docs/trading/fees/#price-impact-and-price-impact-rebates)
are separate: the expected output already factors in price impact and fees, and slippage only covers oracle price movement during execution. Setting 1% slippage on GMX is narrower in scope than 1% slippage on a typical DEX aggregator.
Limit orders[](https://docs.gmx.io/docs/trading/order-types/#limit-orders "Direct link to Limit orders")
----------------------------------------------------------------------------------------------------------
Limit orders let you specify a price at which to open or increase a position, or to execute a swap. Create a limit order by selecting "Limit" in the trade box, or by selecting "Increase Size (Limit)" from the position menu if you already have an open position.
### Perp limit orders[](https://docs.gmx.io/docs/trading/order-types/#perp-limit-orders "Direct link to Perp limit orders")
Limit orders on GMX work differently from orderbook exchanges. There is no orderbook — when the oracle price reaches your trigger price, a keeper picks up and executes the order at that oracle price.
warning
Unlike resting limit orders on a centralized exchange, GMX orders don't fill passively as price moves through them. They're executed by keepers against oracle prices — there is no queue priority or passive fill. Fast market moves can cause the oracle price to skip past your trigger price entirely, resulting in execution at a different price or non-execution. See [Price gaps and volatility](https://docs.gmx.io/docs/trading/order-types/#price-gaps-and-volatility)
.
On centralized exchanges, traders sometimes use limit orders to open a position immediately with controlled slippage — setting a limit price that would fill right away but caps the worst acceptable execution price. On GMX, use a Market Increase instead and set an acceptable slippage under the execution details.
### Limit swaps[](https://docs.gmx.io/docs/trading/order-types/#limit-swaps "Direct link to Limit swaps")
For Limit Swaps, execution may occur at a price different from your set limit price. The actual execution price is influenced by fees and price impact. For example, with positive price impact, the order might execute before the limit price is reached. With negative price impact, it might execute only after the price moves past your limit.
If the order executes, you receive at least the minimum output amount derived from your limit price and allowed slippage. If this minimum can't be satisfied, the order doesn't execute. This means even if charts show the limit price was reached, execution isn't guaranteed.
### Managing limit orders[](https://docs.gmx.io/docs/trading/order-types/#managing-limit-orders "Direct link to Managing limit orders")
After creating a limit order, it appears under the "Orders" tab. You can edit the order to adjust the trigger price or limit price.
Stop Market orders[](https://docs.gmx.io/docs/trading/order-types/#stop-market-orders "Direct link to Stop Market orders")
----------------------------------------------------------------------------------------------------------------------------
A Stop Market order opens or increases a position when the oracle price reaches your specified stop price. Stop Market orders are available for long and short positions only — they are not available for swaps.
To create a Stop Market order, select "Stop Market" from the order type selector in the trade box. If you already have an open position, select "Increase size (Stop Market)" from the "..." menu in the position row.
### Trigger conditions[](https://docs.gmx.io/docs/trading/order-types/#trigger-conditions "Direct link to Trigger conditions")
The oracle price checked against your stop price depends on the direction of your position:
* **Long:** The order triggers when `maxPrice >= stop price`. The `maxPrice` oracle value is also used for execution.
* **Short:** The order triggers when `minPrice <= stop price`. The `minPrice` oracle value is also used for execution.
The UI enforces that a long stop price must be set above the current mark price, and a short stop price must be set below it.
### Execution price[](https://docs.gmx.io/docs/trading/order-types/#execution-price "Direct link to Execution price")
When the oracle price reaches your stop price, the order executes at the closest oracle price update to the trigger price — not necessarily at the exact stop price you set. During fast market moves, the oracle price may skip past your trigger price, causing execution at a different oracle update or no execution at all. See [Price gaps and volatility](https://docs.gmx.io/docs/trading/order-types/#price-gaps-and-volatility)
.
### Acceptable price[](https://docs.gmx.io/docs/trading/order-types/#acceptable-price "Direct link to Acceptable price")
Stop Market orders do not have a user-configurable acceptable price. The acceptable price is set automatically to the maximum possible value for longs and the minimum for shorts, meaning there is no upper or lower price constraint beyond the trigger condition. No acceptable price is shown for Stop Market orders. Because the acceptable price is set to a boundary value, the UI does not display it.
### Managing Stop Market orders[](https://docs.gmx.io/docs/trading/order-types/#managing-stop-market-orders "Direct link to Managing Stop Market orders")
After creation, a Stop Market order appears under the "Orders" tab. You can edit the order to adjust the stop price. Stop Market orders cannot be partially filled — the full order executes when the trigger condition is met.
note
Stop Market orders are not guaranteed to execute. Execution may fail if the oracle price does not reach your stop price, if there is insufficient liquidity, or if the [max allowed leverage](https://docs.gmx.io/docs/trading/order-types/#max-leverage)
would be exceeded.
TWAP orders[](https://docs.gmx.io/docs/trading/order-types/#twap-orders "Direct link to TWAP orders")
-------------------------------------------------------------------------------------------------------
TWAP (Time-Weighted Average Price) orders execute increases or decreases to positions, and swaps, in evenly distributed parts over a specified duration. By splitting into smaller parts executed at regular time intervals, TWAP reduces price impact — making it suitable for large positions where a single market order would move the price significantly.
The interface suggests switching to TWAP when your order size is at least $1,000,000 USD and the estimated negative price impact exceeds 0.2%.
### How TWAP works[](https://docs.gmx.io/docs/trading/order-types/#how-twap-works "Direct link to How TWAP works")
When you create a TWAP order, the interface submits multiple individual orders — each a Limit Increase, Limit Decrease, or Limit Swap — with their total size divided equally across all parts. Each part has a staggered activation timestamp. The first part activates immediately; the last part activates at the end of your configured duration. Keepers execute each part once its timestamp is reached, using the current oracle price at execution.
TWAP is not a distinct on-chain order type. It is implemented at the application layer by grouping standard limit orders with time-gated activation.
### Configuration[](https://docs.gmx.io/docs/trading/order-types/#configuration "Direct link to Configuration")
The TWAP configuration panel exposes these fields:
* **Duration** — the total time over which parts are spread, entered as hours and minutes. There is no enforced minimum or maximum duration.
* **Number of parts** — the number of individual orders to create. The minimum is 2 and the maximum is 30. The default is 5.
* **Frequency** — a derived, display-only field: total duration in seconds divided by the number of parts.
* **Size per part** — a derived, display-only field: total position size divided by the number of parts.
The default duration is 10 hours.
For new positions (with no existing position), the minimum margin per part is $1 USD.
### Creating a TWAP order[](https://docs.gmx.io/docs/trading/order-types/#creating-a-twap-order "Direct link to Creating a TWAP order")
* To open or increase a position: select "TWAP" from the order type selector (under the "More" dropdown in the trade box), or select "Increase size (TWAP)" from the "..." menu on the position row.
* To close or decrease a position: click the "TWAP" button in the Close column of the position row.
* To perform a TWAP swap: select "TWAP" in the order type selector on the Swap tab.
### Monitoring and cancelling TWAP orders[](https://docs.gmx.io/docs/trading/order-types/#monitoring-and-cancelling-twap-orders "Direct link to Monitoring and cancelling TWAP orders")
After creating a TWAP order, it appears under the "Orders" tab. The trigger price column shows "N/A" because each part executes at the oracle price at the time of execution, not at a fixed trigger price. Progress is displayed as the number of executed parts out of the total — for example, "(3/5)" means 3 of 5 parts have already executed.
TWAP orders can't be edited. To modify a TWAP order, cancel it and create a new one. Cancelling a TWAP order cancels all remaining unexecuted parts in a single transaction.
### Execution fees[](https://docs.gmx.io/docs/trading/order-types/#execution-fees "Direct link to Execution fees")
The total execution fee for all parts is paid upfront when you create the TWAP order. This fee is divided equally across all parts. If network fees rise after creation and a part's allocated fee becomes insufficient for keeper execution, that part may be frozen rather than executed automatically.
note
If a TWAP part is frozen due to insufficient execution fee, you may need to top it up separately. This situation is the same as for any frozen limit order.
TWAP orders are not guaranteed to execute. Individual parts may fail to execute if there is insufficient liquidity, the max allowed leverage would be exceeded, or the allocated execution fee is insufficient for the keeper to process the order at that time. See [Order execution guarantees](https://docs.gmx.io/docs/trading/order-types/#order-execution-guarantees)
for the full list of conditions that apply to all non-market order types.
Take-Profit and Stop-Loss orders[](https://docs.gmx.io/docs/trading/order-types/#take-profit-and-stop-loss-orders "Direct link to Take-Profit and Stop-Loss orders")
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
Take-Profit and Stop-Loss (TP/SL) orders automatically close part or all of a position when the oracle price reaches a specified level. Take-Profit closes at a favorable price to lock in gains. Stop-Loss closes at an unfavorable price to limit losses.
You can create TP/SL orders in three ways:
* Select "Set TP/SL" from the "..." menu in the positions list.
* Use the TP/SL section in the trade box before opening a position.
* Use the close dialog on an open position.
After creating a TP/SL order, it appears in your position row and under the "Orders" tab. You can edit the order to adjust the trigger price if needed.
### Trigger price evaluation[](https://docs.gmx.io/docs/trading/order-types/#trigger-price-evaluation-1 "Direct link to Trigger price evaluation")
Take-Profit and Stop-Loss orders are mapped to distinct on-chain order types — `LimitDecrease` and `StopLossDecrease` — each with its own trigger condition:
| Order | Side | Triggers when |
| --- | --- | --- |
| Take-Profit | Long | `minPrice >= trigger price` |
| Take-Profit | Short | `maxPrice <= trigger price` |
| Stop-Loss | Long | `minPrice <= trigger price` |
| Stop-Loss | Short | `maxPrice >= trigger price` |
The same oracle price component used to trigger the order is also used as the base execution price, before any price impact adjustment is applied.
Fast market moves can cause the oracle price to skip past your trigger price, resulting in execution at the next oracle update or non-execution. See [Price gaps and volatility](https://docs.gmx.io/docs/trading/order-types/#price-gaps-and-volatility)
.
### Auto-cancel TP/SL[](https://docs.gmx.io/docs/trading/order-types/#auto-cancel-tpsl "Direct link to Auto-cancel TP/SL")
When a position is fully closed — whether by a market close, liquidation, or a triggered TP/SL order — any remaining TP/SL orders on that position are automatically cancelled. This prevents orphaned orders from persisting after the position no longer exists.
Auto-cancel applies only to `LimitDecrease` (Take-Profit) and `StopLossDecrease` (Stop-Loss) order types. Limit Increase and Stop Market orders are not auto-cancelled.
Auto-cancel is enabled by default. You can turn it off in settings.
The current per-network limits for auto-cancel TP/SL orders per position are:
| Network | Max auto-cancel TP/SL orders |
| --- | --- |
| Arbitrum | 11 |
| Avalanche | 6 |
These limits are enforced on-chain. If creating an order with auto-cancel enabled would exceed the limit, the transaction reverts. The frontend handles this by automatically setting `autoCancel` to `false` for orders that would exceed the limit, so the order is still created but won't be auto-cancelled when the position closes. The interface displays a warning when this occurs — orders created without auto-cancel require manual cancellation.
note
The auto-cancel limit is read live from the on-chain data store and may change over time.
Order execution guarantees[](https://docs.gmx.io/docs/trading/order-types/#order-execution-guarantees "Direct link to Order execution guarantees")
----------------------------------------------------------------------------------------------------------------------------------------------------
warning
Limit, Stop Market, TWAP, and TP/SL orders are not guaranteed to execute. This can occur in situations including but not limited to:
* The oracle price did not reach the specified trigger price — see [trigger price evaluation](https://docs.gmx.io/docs/trading/order-types/#trigger-price-evaluation)
for how trigger conditions differ by order type and side (Limit, Stop Market, TP/SL)
* There may not be sufficient liquidity to execute the order
* The [max allowed leverage](https://docs.gmx.io/docs/trading/order-types/#max-leverage)
would be exceeded
* If your position becomes liquidatable, keepers attempt to execute associated Stop-Loss orders first, but this is not guaranteed to succeed — see [Stop-Loss orders and liquidations](https://docs.gmx.io/docs/trading/liquidations/#stop-loss-orders-and-liquidations)
* [Pricing on GMX](https://docs.gmx.io/docs/trading/order-types/#pricing-on-gmx)
* [Oracle prices: minPrice and maxPrice](https://docs.gmx.io/docs/trading/order-types/#oracle-prices-minprice-and-maxprice)
* [Mark price](https://docs.gmx.io/docs/trading/order-types/#mark-price)
* [Trigger price evaluation](https://docs.gmx.io/docs/trading/order-types/#trigger-price-evaluation)
* [Charts](https://docs.gmx.io/docs/trading/order-types/#charts)
* [Price gaps and volatility](https://docs.gmx.io/docs/trading/order-types/#price-gaps-and-volatility)
* [Opening a position](https://docs.gmx.io/docs/trading/order-types/#opening-a-position)
* [Pool and collateral](https://docs.gmx.io/docs/trading/order-types/#pool-and-collateral)
* [Margin, size, and leverage](https://docs.gmx.io/docs/trading/order-types/#margin-size-and-leverage)
* [Are GMX perps linear or inverse?](https://docs.gmx.io/docs/trading/order-types/#are-gmx-perps-linear-or-inverse)
* [Take-Profit / Stop-Loss](https://docs.gmx.io/docs/trading/order-types/#take-profit--stop-loss)
* [Execution details](https://docs.gmx.io/docs/trading/order-types/#execution-details)
* [Max leverage](https://docs.gmx.io/docs/trading/order-types/#max-leverage)
* [Managing positions](https://docs.gmx.io/docs/trading/order-types/#managing-positions)
* [Position actions](https://docs.gmx.io/docs/trading/order-types/#position-actions)
* [Net value and collateral tooltips](https://docs.gmx.io/docs/trading/order-types/#net-value-and-collateral-tooltips)
* [Closing a position](https://docs.gmx.io/docs/trading/order-types/#closing-a-position)
* [Close amount](https://docs.gmx.io/docs/trading/order-types/#close-amount)
* [Market vs TWAP close](https://docs.gmx.io/docs/trading/order-types/#market-vs-twap-close)
* [Keep leverage](https://docs.gmx.io/docs/trading/order-types/#keep-leverage)
* [Receive token](https://docs.gmx.io/docs/trading/order-types/#receive-token)
* [Execution details](https://docs.gmx.io/docs/trading/order-types/#execution-details-1)
* [PnL](https://docs.gmx.io/docs/trading/order-types/#pnl)
* [Swaps](https://docs.gmx.io/docs/trading/order-types/#swaps)
* [Swap order types](https://docs.gmx.io/docs/trading/order-types/#swap-order-types)
* [Swap configuration](https://docs.gmx.io/docs/trading/order-types/#swap-configuration)
* [Routing](https://docs.gmx.io/docs/trading/order-types/#routing)
* [Execution details](https://docs.gmx.io/docs/trading/order-types/#execution-details-2)
* [Min. receive](https://docs.gmx.io/docs/trading/order-types/#min-receive)
* [Limit orders](https://docs.gmx.io/docs/trading/order-types/#limit-orders)
* [Perp limit orders](https://docs.gmx.io/docs/trading/order-types/#perp-limit-orders)
* [Limit swaps](https://docs.gmx.io/docs/trading/order-types/#limit-swaps)
* [Managing limit orders](https://docs.gmx.io/docs/trading/order-types/#managing-limit-orders)
* [Stop Market orders](https://docs.gmx.io/docs/trading/order-types/#stop-market-orders)
* [Trigger conditions](https://docs.gmx.io/docs/trading/order-types/#trigger-conditions)
* [Execution price](https://docs.gmx.io/docs/trading/order-types/#execution-price)
* [Acceptable price](https://docs.gmx.io/docs/trading/order-types/#acceptable-price)
* [Managing Stop Market orders](https://docs.gmx.io/docs/trading/order-types/#managing-stop-market-orders)
* [TWAP orders](https://docs.gmx.io/docs/trading/order-types/#twap-orders)
* [How TWAP works](https://docs.gmx.io/docs/trading/order-types/#how-twap-works)
* [Configuration](https://docs.gmx.io/docs/trading/order-types/#configuration)
* [Creating a TWAP order](https://docs.gmx.io/docs/trading/order-types/#creating-a-twap-order)
* [Monitoring and cancelling TWAP orders](https://docs.gmx.io/docs/trading/order-types/#monitoring-and-cancelling-twap-orders)
* [Execution fees](https://docs.gmx.io/docs/trading/order-types/#execution-fees)
* [Take-Profit and Stop-Loss orders](https://docs.gmx.io/docs/trading/order-types/#take-profit-and-stop-loss-orders)
* [Trigger price evaluation](https://docs.gmx.io/docs/trading/order-types/#trigger-price-evaluation-1)
* [Auto-cancel TP/SL](https://docs.gmx.io/docs/trading/order-types/#auto-cancel-tpsl)
* [Order execution guarantees](https://docs.gmx.io/docs/trading/order-types/#order-execution-guarantees)
---