--- name: okx-dex-quote description: "Fetch optimal swap quotes from OKX DEX Aggregator API (v6). Use this skill when a user wants to: 1. Get the best price for swapping tokens on any supported EVM/Solana chain 2. Compare DEX routing paths and price impact for token swaps 3. Build applications or scripts that query real-time DEX aggregator pricing Core value: Generates correct, authenticated API calls with proper token decimals, amount formatting, HMAC-SHA256 signing, and comprehensive error handling." --- # OKX DEX Aggregator Quote Skill ## Overview This skill generates production-ready code for fetching optimal swap quotes from the **OKX DEX Aggregator API v6**. The API finds the best price across multiple DEX protocols (Uniswap, SushiSwap, Curve, etc.) and returns detailed routing information including price impact, gas estimates, and token safety flags. **Key capabilities:** - Authenticated API requests with HMAC-SHA256 signing - Correct handling of token decimals and amount formatting - Support for `exactIn` (fixed input) and `exactOut` (fixed output) swap modes - Multi-chain support (Ethereum, BSC, Arbitrum, Base, Solana, and 20+ chains) - Price impact protection and honeypot detection - Fee/commission splitting configuration ## Prerequisites ### Required Credentials Users must have an OKX Web3 API key set. The skill needs three values: - `OKX_ACCESS_KEY` — API key - `OKX_SECRET_KEY` — Secret key for HMAC signing - `OKX_PASSPHRASE` — Account passphrase ### Environment - **Python**: `requests`, `hmac`, `hashlib`, `base64`, `datetime` (all stdlib except `requests`) - **Node.js**: `axios` or `node-fetch`, built-in `crypto` - No additional blockchain dependencies required (this is a read-only quote endpoint) ### API Endpoint ``` GET https://web3.okx.com/api/v6/dex/aggregator/quote ``` ## Workflow ### Step 1: Validate User Input Before constructing the API call, validate: 1. **Chain ID (`chainIndex`)** — Must be a supported chain. Common values: - `1` = Ethereum - `56` = BSC - `137` = Polygon - `42161` = Arbitrum - `8453` = Base - `130` = Unichain - `501` = Solana 2. **Token addresses** — Must be valid contract addresses or the native token placeholder: - Native tokens (ETH, BNB, etc.): `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee` - Contract tokens: Full 42-character hex address (EVM) or base58 (Solana) 3. **Amount** — MUST include token decimals. This is the #1 source of errors: - 1 ETH (18 decimals) → `"1000000000000000000"` - 1 USDT (6 decimals) → `"1000000"` - 1 WBTC (8 decimals) → `"100000000"` - Formula: `amount_raw = human_amount * (10 ** token_decimals)` 4. **Swap mode** — `exactIn` (default) or `exactOut` - `exactOut` only supported on: Ethereum, Base, BSC, Arbitrum - `exactOut` only works with Uniswap V2/V3 pools ### Step 2: Construct Authentication Headers OKX API requires HMAC-SHA256 signed requests with 4 headers: ``` OK-ACCESS-KEY: OK-ACCESS-SIGN: OK-ACCESS-PASSPHRASE: OK-ACCESS-TIMESTAMP: ``` **Signing algorithm:** ``` timestamp = ISO 8601 UTC time (e.g., "2025-01-15T12:00:00.000Z") prehash = timestamp + "GET" + request_path_with_query signature = Base64(HMAC-SHA256(secret_key, prehash)) ``` **CRITICAL**: The `request_path_with_query` must include the full path starting from `/api/...` plus the query string. Example: ``` /api/v6/dex/aggregator/quote?chainIndex=1&amount=1000000000000000000&fromTokenAddress=0xeee...&toTokenAddress=0xa0b... ``` ### Step 3: Send Request and Parse Response **Success response structure:** ```json { "code": "0", "data": [{ "chainIndex": "1", "fromToken": { "tokenSymbol": "ETH", "decimal": "18", ... }, "toToken": { "tokenSymbol": "USDC", "decimal": "6", ... }, "fromTokenAmount": "1000000000000000000", "toTokenAmount": "3521432100", "dexRouterList": [...], "tradeFee": "2.45", "estimateGasFee": "150000", "priceImpactPercent": "-0.12" }], "msg": "" } ``` **Key fields to extract:** - `toTokenAmount` — The amount you'll receive (in raw units with decimals) - `tradeFee` — Estimated network fee in USD - `priceImpactPercent` — Negative = losing value; large negative = danger - `dexRouterList` — Routing path through various DEX protocols - `fromToken.isHoneyPot` / `toToken.isHoneyPot` — Scam token flag - `fromToken.taxRate` / `toToken.taxRate` — Token buy/sell tax ### Step 4: Format Output for User Convert raw amounts back to human-readable: ``` human_amount = raw_amount / (10 ** decimal) ``` Always display: 1. Exchange rate (e.g., "1 ETH = 3,521.43 USDC") 2. Price impact percentage with warning if > 3% 3. Estimated gas fee in USD 4. Routing summary (which DEXes are used) 5. Honeypot warnings if detected 6. Token tax rates if > 0 ## Best Practices ### Security - **NEVER hardcode API credentials** in generated code. Always use environment variables or config files. - **NEVER log the secret key or signature** in debug output. - Validate all token addresses against expected format before sending. - Check `isHoneyPot` flag on both tokens and warn the user prominently. ### Amount Handling - **Always use string type** for amounts to avoid floating-point precision loss. - Python: Use `int()` for amount calculations, never `float()`. - JavaScript: Use `BigInt` or string math for amounts > 2^53. - When user provides a human-readable amount like "1.5 ETH", convert: `str(int(1.5 * 10**18))`. ### Error Handling - Check `response["code"] == "0"` before accessing data. - Common error codes: - Non-zero code with `msg` = API error (e.g., insufficient liquidity, invalid params) - HTTP 401 = Authentication failure (check signature algorithm) - HTTP 429 = Rate limited - If `priceImpactPercent` is `null`, warn that price impact couldn't be calculated. ### Rate Limits - Respect OKX rate limits. For production use, implement exponential backoff. - Cache quotes if polling repeatedly (quotes are valid for ~15-30 seconds). ### Optional Parameters Usage - `dexIds` — Use when you want to restrict to specific DEXes (e.g., only Uniswap). - `directRoute=true` — Only for Solana; forces single-pool routing. - `priceImpactProtectionPercent` — Set to a sensible default like `10` for safety. Set to `100` to disable. - `feePercent` — For integrators taking commission. Max 3% (EVM) or 10% (Solana). Up to 9 decimal places. ## Examples ### Example 1: Python — Get ETH to USDC Quote on Ethereum ```python import os, hmac, hashlib, base64, requests from datetime import datetime, timezone from urllib.parse import urlencode API_KEY = os.environ["OKX_ACCESS_KEY"] SECRET_KEY = os.environ["OKX_SECRET_KEY"] PASSPHRASE = os.environ["OKX_PASSPHRASE"] def get_okx_quote(chain_index, from_token, to_token, amount, swap_mode="exactIn"): base_url = "https://web3.okx.com" path = "/api/v6/dex/aggregator/quote" params = { "chainIndex": chain_index, "fromTokenAddress": from_token, "toTokenAddress": to_token, "amount": amount, "swapMode": swap_mode, } query_string = urlencode(params) request_path = f"{path}?{query_string}" # Generate timestamp and signature timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z" prehash = timestamp + "GET" + request_path signature = base64.b64encode( hmac.new(SECRET_KEY.encode(), prehash.encode(), hashlib.sha256).digest() ).decode() headers = { "OK-ACCESS-KEY": API_KEY, "OK-ACCESS-SIGN": signature, "OK-ACCESS-PASSPHRASE": PASSPHRASE, "OK-ACCESS-TIMESTAMP": timestamp, } resp = requests.get(base_url + request_path, headers=headers) resp.raise_for_status() data = resp.json() if data["code"] != "0": raise Exception(f"OKX API error: {data['msg']}") return data["data"][0] # Swap 1 ETH -> USDC on Ethereum ETH = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" USDC = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" amount = str(1 * 10**18) # 1 ETH in wei quote = get_okx_quote("1", ETH, USDC, amount) to_decimals = int(quote["toToken"]["decimal"]) received = int(quote["toTokenAmount"]) / (10 ** to_decimals) print(f"You will receive: {received:,.2f} {quote['toToken']['tokenSymbol']}") print(f"Price impact: {quote['priceImpactPercent']}%") print(f"Gas fee (USD): ${quote['tradeFee']}") print(f"Honeypot check: {'WARNING' if quote['toToken']['isHoneyPot'] else 'Safe'}") ``` ### Example 2: Node.js — Get Quote with Commission Fee ```javascript const crypto = require("crypto"); const https = require("https"); const API_KEY = process.env.OKX_ACCESS_KEY; const SECRET_KEY = process.env.OKX_SECRET_KEY; const PASSPHRASE = process.env.OKX_PASSPHRASE; function getQuote(chainIndex, fromToken, toToken, amount, options = {}) { const params = new URLSearchParams({ chainIndex, fromTokenAddress: fromToken, toTokenAddress: toToken, amount, swapMode: options.swapMode || "exactIn", ...(options.feePercent && { feePercent: options.feePercent }), ...(options.priceImpactProtectionPercent && { priceImpactProtectionPercent: options.priceImpactProtectionPercent, }), }); const path = `/api/v6/dex/aggregator/quote?${params}`; const timestamp = new Date().toISOString(); const prehash = timestamp + "GET" + path; const signature = crypto .createHmac("sha256", SECRET_KEY) .update(prehash) .digest("base64"); return new Promise((resolve, reject) => { const req = https.get( `https://web3.okx.com${path}`, { headers: { "OK-ACCESS-KEY": API_KEY, "OK-ACCESS-SIGN": signature, "OK-ACCESS-PASSPHRASE": PASSPHRASE, "OK-ACCESS-TIMESTAMP": timestamp, }, }, (res) => { let body = ""; res.on("data", (chunk) => (body += chunk)); res.on("end", () => { const data = JSON.parse(body); if (data.code !== "0") reject(new Error(`OKX: ${data.msg}`)); else resolve(data.data[0]); }); } ); req.on("error", reject); }); } ``` ### Example 3: Understanding the Routing Path ``` Router: ETH -> WBTC -> USDC dexRouterList shows: - 55% ETH -> WBTC via Uniswap V4 - 30% ETH -> USDC via Uniswap V4 (direct) - WBTC -> USDC via Euler (73%) + Uniswap V4 (27%) This means the aggregator splits the trade across multiple paths to minimize price impact and maximize output. ``` ## Troubleshooting | Problem | Cause | Solution | |---------|-------|----------| | `401 Unauthorized` | Signature mismatch | Verify prehash string is exactly `timestamp + "GET" + full_path_with_query`. Check secret key encoding. | | Amount too small | Missing decimal conversion | Multiply human amount by `10 ** token_decimals`. 1 USDT = `1000000`, not `1`. | | Invalid token address | Wrong chain/address combo | Verify the token exists on the specified chain. Use native token placeholder for ETH/BNB/etc. | | `priceImpactPercent` very negative (< -10%) | Low liquidity or large trade | Reduce trade size or split across multiple transactions. | | `isHoneyPot: true` | Scam token detected | **Do NOT proceed with the swap.** Warn the user immediately. | | `exactOut` not working | Unsupported chain/protocol | Only works on Ethereum, Base, BSC, Arbitrum with Uniswap V2/V3. | | `taxRate > 0` | Token has built-in tax | Factor tax into expected output. E.g., 5% tax means receiving 5% less. | | Empty `dexRouterList` | No liquidity path found | Try a different token pair, smaller amount, or different chain. | | `code` is non-zero | General API error | Read `msg` field for details. Common: rate limit, maintenance, invalid params. | ## Reference: Common Chain IDs | Chain | chainIndex | |-------|-----------| | Ethereum | 1 | | BSC | 56 | | Polygon | 137 | | Arbitrum | 42161 | | Optimism | 10 | | Avalanche | 43114 | | Base | 8453 | | Solana | 501 | | Unichain | 130 | ## Reference: Common Token Addresses (Ethereum) | Token | Address | Decimals | |-------|---------|----------| | ETH (native) | `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee` | 18 | | USDT | `0xdac17f958d2ee523a2206206994597c13d831ec7` | 6 | | USDC | `0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48` | 6 | | WETH | `0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2` | 18 | | WBTC | `0x2260fac5e5542a773aa44fbcfedf7c193bc2c599` | 8 | | DAI | `0x6b175474e89094c44da98b954eedeac495271d0f` | 18 | ## Reference: Request Parameters Summary | Parameter | Required | Description | |-----------|----------|-------------| | `chainIndex` | Yes | Chain ID (e.g., `1` for Ethereum) | | `amount` | Yes | Amount in raw units (with decimals) | | `swapMode` | Yes | `exactIn` or `exactOut` | | `fromTokenAddress` | Yes | Sell token contract address | | `toTokenAddress` | Yes | Buy token contract address | | `dexIds` | No | Comma-separated DEX IDs to restrict routing | | `directRoute` | No | `true` for single-pool only (Solana only) | | `priceImpactProtectionPercent` | No | Max allowed price impact 0-100 (default 90) | | `feePercent` | No | Commission fee percentage for integrators |