# OKX Web3 Documentation ## OKX OnchainOS Developer Documentation - [What is Onchain OS](https://web3.okx.com/onchainos/dev-docs/home/what-is-onchainos.md) # What is Onchain OS ## Built for AI. Ready for Web3. Onchain OS is the Web3 infrastructure for the AI era — reshaping the next generation of finance. Agentic Wallet sets a new benchmark for Agent-native wallets — private key generation and signing are fully within a Trusted Execution Environment (TEE), with Agents driving onchain transactions directly through natural language, backed by OKX's Web3 infrastructure and security system serving tens of millions of users worldwide. All capabilities are packaged as Skills and MCP Server, installable with a single command. ## Two Integration Methods - Skills: Drive Onchain OS directly through natural language conversation with your Agent. - Open API: Programmatically access capabilities of Onchain OS with precision. ## Core Capabilities - **Wallet** — Agentic Wallet serves as the dedicated wallet for AI Agents. Private keys are generated and signed within a Trusted Execution Environment (TEE), untouchable by anyone. Every Agent operation undergoes intent verification and real-time monitoring, purpose-built for autonomous operation. - **Trade** — Powered by OKX DEX aggregation engine, scanning liquidity across the entire network in real time, with intelligent routing to find the best price and maximize the received amount on every swap. Native multi-chain architecture covering major EVM chains and Solana, battle-tested by millions of traders and developers. - **Market** — Real-time multi-chain market data, covering token prices, transaction records, and comprehensive data support for advanced strategies. - **Payments** — Built on the x402 protocol, pay-as-you-go, purpose-built for autonomous Agent payment scenarios. - [Supported Networks](https://web3.okx.com/onchainos/dev-docs/home/supported-chain.md) # Supported Networks ## Agentic Wallet ### Popular Networks | Chain | Status | ChainIndex | |---|---|---| | X Layer | [✓](../wallet/agentic-wallet) | 196 | | Ethereum | [✓](../wallet/agentic-wallet) | 1 | | Solana | [✓](../wallet/agentic-wallet) | 501 | | BNB Chain | [✓](../wallet/agentic-wallet) | 56 | | Base | [✓](../wallet/agentic-wallet) | 8453 | ### EVM Networks | Chain | Status | ChainIndex | |---|---|---| | Arbitrum One | [✓](../wallet/agentic-wallet) | 42161 | | Avalanche C | [✓](../wallet/agentic-wallet) | 43114 | | Blast | [✓](../wallet/agentic-wallet) | 81457 | | Conflux | [✓](../wallet/agentic-wallet) | 1030 | | Fantom | [✓](../wallet/agentic-wallet) | 250 | | Linea | [✓](../wallet/agentic-wallet) | 59144 | | Monad | [✓](../wallet/agentic-wallet) | - | | Optimism | [✓](../wallet/agentic-wallet) | 10 | | Polygon | [✓](../wallet/agentic-wallet) | 137 | | Scroll | [✓](../wallet/agentic-wallet) | 534352 | | Sonic | [✓](../wallet/agentic-wallet) | 146 | | zkSync Era | [✓](../wallet/agentic-wallet) | 324 | ## Open API ### Popular Networks | Chain | Wallet API | Trade | Market | Payments | Dapp Connect | ChainIndex | |---|---|---|---|---|---|---| | X Layer | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | [✓](../payments/x402-introduction) | [✓](../sdks/okx-wallet-integration-introduction) | 196 | | Bitcoin | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 0 | | Ethereum | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 1 | | Solana | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | Coming Soon | [✓](../sdks/okx-wallet-integration-introduction) | 501 | | Tron | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 195 | | BNB Chain | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | Coming Soon | [✓](../sdks/okx-wallet-integration-introduction) | 56 | | Base | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | Coming Soon | [✓](../sdks/okx-wallet-integration-introduction) | 8453 | | SUI | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 784 | ### EVM Networks | Chain | Wallet API | Trade | Market | Payments | Dapp Connect | ChainIndex | |---|---|---|---|---|---|---| | Arbitrum One | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 42161 | | Avalanche C | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 43114 | | Base | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | Coming Soon | [✓](../sdks/okx-wallet-integration-introduction) | 8453 | | Blast | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 81457 | | BNB Chain | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | Coming Soon | [✓](../sdks/okx-wallet-integration-introduction) | 56 | | Conflux | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 1030 | | Cronos | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 25 | | Ethereum | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 1 | | Fantom | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 250 | | Linea | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 59144 | | Manta Pacific | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 169 | | Mantle | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 5000 | | Merlin | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 4200 | | Metis | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 1088 | | Optimism | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 10 | | Polygon | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 137 | | Polygon zkEVM | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 1101 | | Scroll | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 534352 | | Sonic | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 146 | | Uni Chain | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 130 | | X Layer | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | [✓](../payments/x402-introduction) | [✓](../sdks/okx-wallet-integration-introduction) | 196 | | ZetaChain | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 7000 | | zkSync Era | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 324 | ### Other Networks | Chain | Wallet API | Trade | Market | Payments | Dapp Connect | ChainIndex | |---|---|---|---|---|---|---| | Bitcoin | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 0 | | Solana | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | Coming Soon | [✓](../sdks/okx-wallet-integration-introduction) | 501 | | SUI | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 784 | | Ton | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 607 | | Tron | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 195 | - [Authentication](https://web3.okx.com/onchainos/dev-docs/home/api-access-and-usage.md) # Authentication ## If you use Agentic Wallet ### Email Authentication Create or access your wallet with just an email — no developer account or API key required. Ideal for getting started quickly. **Step 1** Tell your Agent: ```plain text Log in to Agentic Wallet with email ``` **Step 2** Enter your email and wait for the verification code: ```plain text ``` **Step 3** Enter the verification code: ```plain text ``` Once verified, the Agent will automatically create a wallet on first login: ```plain text Wallet created successfully! EVM Address: Solana Address: ``` Private keys are generated and stored in a TEE environment and are never exposed to anyone, including your Agent. Logging in again with the same email will restore your existing wallet — no need to recreate it. ### API Key Authentication The built-in sandbox keys are for testing only and may be subject to rate limits. For stable production usage, set up your own API credentials: 1. Go to the [OKX Developer Portal](https://web3.okx.com/onchainos/dev-portal/project). 2. Generate your **API Key**, **Secret Key**, and **Passphrase**. Tell your agent: ```plain text Create a .env file with these variables: OKX_API_KEY, OKX_SECRET_KEY, and OKX_PASSPHRASE. Add .env to .gitignore. And open it, tell me what to do next, and remind me to save after I filled out the passkeys. ``` Your agent will create the file and open it — paste your keys there. Never commit `.env` to git (add it to `.gitignore`) and never expose these credentials in logs, screenshots, or chat messages ## If you use Open API You can also authenticate using an API Key for Onchain OS Skills/Open API. You'll need to create a project and generate an API key in the developer management portal first. For detailed steps and resources, refer to [here](./developer-portal). All API requests must include the following headers for authentication: - OK-ACCESS-KEY: API key - OK-ACCESS-TIMESTAMP: Request timestamp (UTC), in ISO format, e.g. 2020-12-08T09:08:57.715Z - OK-ACCESS-PASSPHRASE: The passphrase specified when creating the API key - OK-ACCESS-SIGN: Signature Signing steps: - Step 1: Concatenate timestamp, method, requestPath, and body into a single string - Step 2: Sign the pre-hash string (result of Step 1) using HMAC SHA256 with the secret key (generated when creating the API key) - Step 3: Encode the signature using Base64 For example, sign=CryptoJS.enc.Base64.stringify(CryptoJS.HmacSHA256(timestamp + 'GET' + '/api/v6/dex/aggregator/swap', SecretKey)). The timestamp must match OK-ACCESS-TIMESTAMP. GET is the method (HTTP request method, all uppercase). /api/v6/dex/aggregator/swap is the requestPath. The body is empty — it can be omitted if there is no request body (typically for GET requests). The timestamp must not differ from the server time by more than 30 seconds. POST requests must include the raw request body in the signature calculation. The secret key is only visible at creation time — store it through a secure channel. **Postman Example** Postman is a popular API development and testing tool that allows developers to design, test, and document APIs. It provides a user-friendly graphical interface for sending HTTP requests to APIs. If you haven't installed Postman yet, you can download it for free from the Postman website: https://www.postman.com/ This example requires a basic understanding of Postman. ### Add Parameters - This typically applies to GET requests. - If your request requires query parameters, you can add them under the **Params** tab. Here you can add key-value pairs for query parameters. ![Image](../images/postman1.png) ### Set Headers Under the **Headers** tab, add the following key-value pairs: - `OK-ACCESS-KEY` - `OK-ACCESS-PASSPHRASE` ![Image](../images/postman2.png) ### Add Body - This typically applies to POST requests. - If your request requires a request body, you can add it under the **Body** tab. - Select **raw** and **JSON** from the dropdown menu. - Enter your request body in JSON format. ![Image](../images/postman3.png) ### Set Pre-request Script - Used to generate the required signature (`OK-ACCESS-SIGN`) and timestamp (`OK-ACCESS-TIMESTAMP`). - Under the **Pre-request Script** tab, insert the script corresponding to your request type. - When generating the pre-hash string, GET requests exclude the request body. - Edit the secret key as needed. GET request: ```javascript var method = pm.request.method; var now = new Date(); var isoString = now.toISOString(); var path = pm.request.url.getPathWithQuery(); var sign = CryptoJS.enc.Base64.stringify( CryptoJS.HmacSHA256( isoString + method + path, pm.variables.replaceIn('{{secret_key}}') ) ); pm.request.headers.add({ key: 'OK-ACCESS-SIGN', value: sign, }); pm.request.headers.add({ key: 'OK-ACCESS-TIMESTAMP', value: isoString, }); ``` POST request: ```javascript var method = pm.request.method; var now = new Date(); var isoString = now.toISOString(); var path = pm.request.url.getPathWithQuery(); var bodyStr = pm.request.body.raw; var sign = CryptoJS.enc.Base64.stringify( CryptoJS.HmacSHA256( isoString + method + path + bodyStr, pm.variables.replaceIn('{{secret_key}}') ) ); pm.request.headers.add({ key: 'OK-ACCESS-SIGN', value: sign, }); pm.request.headers.add({ key: 'OK-ACCESS-TIMESTAMP', value: isoString, }); ``` **JavaScript Example** To call the API via a JavaScript script, refer to the following code example: ```javascript const https = require('https'); const crypto = require('crypto'); const querystring = require('querystring'); // Define API credentials const api_config = { api_key: '', secret_key: '', passphrase: '', }; function preHash(timestamp, method, request_path, params) { // Create pre-sign string from parameters let query_string = ''; if (method === 'GET' && params) { query_string = '?' + querystring.stringify(params); } if (method === 'POST' && params) { query_string = JSON.stringify(params); } return timestamp + method + request_path + query_string; } function sign(message, secret_key) { // Sign the pre-hash string using HMAC-SHA256 const hmac = crypto.createHmac('sha256', secret_key); hmac.update(message); return hmac.digest('base64'); } function createSignature(method, request_path, params) { // Get ISO 8601 formatted timestamp const timestamp = new Date().toISOString().slice(0, -5) + 'Z'; // Generate signature const message = preHash(timestamp, method, request_path, params); const signature = sign(message, api_config['secret_key']); return { signature, timestamp }; } function sendGetRequest(request_path, params) { // Generate signature const { signature, timestamp } = createSignature('GET', request_path, params); // Build request headers const headers = { 'OK-ACCESS-KEY': api_config['api_key'], 'OK-ACCESS-SIGN': signature, 'OK-ACCESS-TIMESTAMP': timestamp, 'OK-ACCESS-PASSPHRASE': api_config['passphrase'], }; const options = { hostname: 'web3.okx.com', path: request_path + (params ? `?${querystring.stringify(params)}` : ''), method: 'GET', headers: headers, }; const req = https.request(options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { console.log(data); }); }); req.end(); } function sendPostRequest(request_path, params) { // Generate signature const { signature, timestamp } = createSignature( 'POST', request_path, params ); // Build request headers const headers = { 'OK-ACCESS-KEY': api_config['api_key'], 'OK-ACCESS-SIGN': signature, 'OK-ACCESS-TIMESTAMP': timestamp, 'OK-ACCESS-PASSPHRASE': api_config['passphrase'], 'Content-Type': 'application/json', }; const options = { hostname: 'web3.okx.com', path: request_path, method: 'POST', headers: headers, }; const req = https.request(options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { console.log(data); }); }); if (params) { req.write(JSON.stringify(params)); } req.end(); } // GET request example const getRequestPath = '/api/v6/dex/aggregator/quote'; const getParams = { chainIndex: 42161, amount: 1000000000000, toTokenAddress: '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', fromTokenAddress: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', }; sendGetRequest(getRequestPath, getParams); // POST request example const postRequestPath = '/api/v5/mktplace/nft/ordinals/listings'; const postParams = { slug: 'sats', }; sendPostRequest(postRequestPath, postParams); ``` - [Developer Portal](https://web3.okx.com/onchainos/dev-docs/home/developer-portal.md) # Developer Portal This section covers the features of the development portal and best practices which will help you to build your own apps efficiently. ## Sign up/Log in 1. Click on the [**Developer portal**](https://web3.okx.com/build/dev-portal). 2. Click **Connect Wallet** to create or log in to an account. We recommend to use OKX Wallet for a seamless experience.You can also choose other wallets for your project. 3. Click **Verify** in the developer portal, then confirm **Signature** request in the extension. You have successfully created your developer account with OKX API. A default project is also created for your convenience. ## Link E-mail and Phone number to your account 1. Click the **Get started** button. 2. Input your E-mail and Phone number correctly. If you find you cannot find your country in the Phone number country selection part, that's mainly because some regions are restricted to OKX API services. 3. Complete the verification code process. You have successfully linked your E-mail and phone number to your developer account. You can now immediately create OKX API keys on the developer portal and start embedding our advanced trading capability into your dApps. ## Generate a New API Key 1. Switch to the project that you want to create an API key. Note, you can create up to three projects per developer account, and three API keys per project. 2. Navigate to the **Home** page and click the **Create API key** button. 3. Enter the name of the API key and passphrase, and click **Create** to generate the corresponding API Key.
Please keep your passphrase safe and accessible. You cannot access your API key in your project without the passphrase. ## View the Secret Key When making API calls with a generated API key, you need to provide both the API passphrase and the secret key. The secret key is system generated, and can be viewed by clicking the **View details** button on the Home page. ## General Terms - API key: a unique identifier used to authenticate and authorize an application or user when making requests to OKX API. - Secret key: a system generated security token to provide additional security for your API key. - Passphrase: a phrase supplied by the developer when creating an API key, used to encrypt the secret key on the server to provide additional security. The passphrase is also needed to view the secret key and modify the API information. - [Agentic Wallet](https://web3.okx.com/onchainos/dev-docs/home/agentic-wallet-overview.md) # Agentic Wallet **Your AI Agent now has its own wallet.** The most powerful AI Agentic wallet in the industry — key generation, storage, and signing all happen inside TEE. No one can touch the private key, not even OKX. Agents autonomously scan the market, assess timing, and execute trades, backed by OKX's full-chain liquidity and security infrastructure. Install with a single command, sign in with email to get started. ## Why Your Agent Needs Agentic Wallet - **Closed-Loop Execution** — From signal to onchain settlement, Agents handle everything autonomously. No profit lost to manual delays. - **24/7 nonstop** — The market never sleeps, neither does your Agent. Always first in when opportunity strikes. - **Automatic risk protection** — Malicious approvals and abnormal transfers identified in real time. Assets remain fully in your control. - **Multi-Strategy in Parallel** — Up to 50 sub-wallets, isolated positions, multiple strategies running simultaneously for maximum returns. - **Autonomous payments** — Built on the x402 protocol, Agents automatically pay for the data and services they need, keeping the execution chain uninterrupted. ## What Agentic Wallet Can Do - **Automated trading** — Describe your strategy, and your Agent scans the market 7×24 and executes autonomously. - **Assets & security** — Multi-chain balances, risk detection, and one-click revocation of malicious approvals. Protect your profits. - **Multi-wallet** — Up to 50 sub-wallets, batch transfers, parallel position management. - **Auto-payments** — Built on the x402 protocol, Agents pay onchain automatically when calling external APIs. - **Market monitoring** — Token prices, smart money movements, onchain anomalies — tracked in real time. Start exploring Agentic Wallet - [Skills/MCP Services](https://web3.okx.com/onchainos/dev-docs/home/skills-mcp-services.md) # Skills/MCP Services **Give your Agent the power to trade, access market data, and make payments.** Trade, Market, and Payment Skills/MCP are now live. Agents can swap tokens, fetch real-time prices, query onchain data, and stream market updates. - [Install Your Agentic Wallet](https://web3.okx.com/onchainos/dev-docs/home/install-your-agentic-wallet.md) # Install Your Agentic Wallet Give your AI Agent its first onchain wallet — private keys protected by TEE, automatic risk detection before transactions, from wallet setup to onchain trading all through conversation. ## Preparation: Install an AI Agent This guide uses [Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview) as an example. Onchain OS supports all mainstream agents ([Cursor](https://docs.cursor.com/get-started/installation), [OpenClaw](https://docs.openclaw.ai/), etc.). ## Step 1: Add Onchain OS to Your Agent Tell your Agent: ```plain text Run npx skills add okx/onchainos-skills to install Onchain OS skills. Note: Please install to the skill directory corresponding to your current Agent. ``` The Agent will complete the installation automatically. For more details, see [Github](https://github.com/okx/onchainos-skills). ## Step 2: Create a Wallet Tell your Agent: ```plain text Log in to Agentic Wallet with email ``` Enter your email and wait for the verification code: ```plain text ``` Enter the verification code: ```plain text ``` Once verified, the Agent will automatically create a wallet on first login: ```plain text Wallet created successfully! EVM Address: Solana Address: ``` Private keys are generated and stored entirely within the TEE — never exposed to anyone, including your Agent. Logging in with the same email restores the existing wallet automatically. - [Run Your First AI Agent](https://web3.okx.com/onchainos/dev-docs/home/run-your-first-ai-agent.md) # Run Your First AI Agent You've installed Agentic Wallet — now let your AI Agent start trading. Share your strategy, and your Agent will run it around the clock with your private keys secured at all times. Here's a full walkthrough from setting your strategy to viewing your returns: ## 1. Describe Your Strategy ```plain text Monitor what smart money is buying on Solana, with these conditions: - Market cap under $5M - At least 2 smart money wallets buying - Auto-buy 1 USDT after security check passes - Take profit at +50% with trailing stop (sell on 10% pullback), stop loss at -20% ``` Agent breaks down the strategy and confirms: ```plain text Got it, let me break this down: 1. Monitor: Solana smart money wallet activity 2. Filters: Market cap < $5M, ≥ 2 smart money wallets buying, security check passed 3. Buy: 1 USDT per trade 4. Take profit: Trailing stop after +50%, sell on 10% pullback 5. Stop loss: -20% Confirm and I'll start executing. ``` ## 2. Auto Trading Agent detects a signal and executes buy: ```plain text Signal detected: meets criteria - Smart money buys: 3 wallets - Current market cap: $2.9M - Security check: Passed Executing buy : 1 USDT Trade complete ✓ Buy price: $0.00999 Tx hash: ``` ## 3. Auto Take-Profit / Stop-Loss ```plain text current price: $0.01699 (+70.2%) Trailing take-profit triggered, tracking... pulled back to $0.01539 (10.1% from high) Trailing take-profit triggered, executing sell. Sell complete ✓ Profit: +0.54 USDT (+54.1%) Tx hash: ``` ## 4. View Report Ask your Agent: ```plain text How did I do today? ``` Agent generates a report: ```plain text Today's report: Closed: 3 trades | Open: 2 trades 1. +54.1% ✓ Trailing take-profit 2. -20.0% ✗ Stop loss 3. +10.0% ✓ Timeout exit Today's realized profit: +0.44 USDT ``` The above example is for demonstration purposes only and does not constitute any investment advice. Please make trading decisions based on your own judgment. - [Build Your DApp](https://web3.okx.com/onchainos/dev-docs/home/run-your-first-dapp.md) # Build Your DApp If you're a DApp developer, this demo shows you how to build your DApp. Example: Using the Trade API endpoint for token swaps. You'll swap USDC for ETH on the Ethereum network. ## 1. Set Up Your Environment ```typescript // --------------------- npm package --------------------- import { Web3 } from 'web3'; import axios from 'axios'; import * as dotenv from 'dotenv'; import CryptoJS from 'crypto-js'; // The URL for the Ethereum node you want to connect to const web3 = new Web3('https://......com'); // --------------------- environment variable --------------------- // Load hidden environment variables dotenv.config(); // Your wallet information - REPLACE WITH YOUR OWN VALUES const WALLET_ADDRESS: string = process.env.EVM_WALLET_ADDRESS || '0xYourWalletAddress'; const PRIVATE_KEY: string = process.env.EVM_PRIVATE_KEY || 'YourPrivateKey'; // Token addresses for swap on Base Chain const ETH_ADDRESS: string = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'; // Native ETH const USDC_ADDRESS: string = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'; // USDC on Base // Chain ID for Base Chain const chainIndex: string = '8453'; // API URL const baseUrl: string = 'https://web3.okx.com/api/v6/'; // Amount to swap in smallest unit (0.0005 ETH) const SWAP_AMOUNT: string = '500000000000000'; // 0.0005 ETH const SLIPPAGEPERCENT: string = '0.5'; // 0.5% slippagePercent tolerance // --------------------- util function --------------------- export function getHeaders(timestamp: string, method: string, requestPath: string, queryString = "") { // Check https://web3.okx.com/zh-hans/web3/build/docs/waas/rest-authentication for api-key const apiKey = process.env.OKX_API_KEY; const secretKey = process.env.OKX_SECRET_KEY; const apiPassphrase = process.env.OKX_API_PASSPHRASE; const projectId = process.env.OKX_PROJECT_ID; if (!apiKey || !secretKey || !apiPassphrase || !projectId) { throw new Error("Missing required environment variables"); } const stringToSign = timestamp + method + requestPath + queryString; return { "Content-Type": "application/json", "OK-ACCESS-KEY": apiKey, "OK-ACCESS-SIGN": CryptoJS.enc.Base64.stringify( CryptoJS.HmacSHA256(stringToSign, secretKey) ), "OK-ACCESS-TIMESTAMP": timestamp, "OK-ACCESS-PASSPHRASE": apiPassphrase, "OK-ACCESS-PROJECT": projectId, }; }; ``` ## 2. Check Allowance You need to check if the token has been approved for the DEX to spend. This step is only needed for ERC20 tokens, not for native tokens like ETH. ```typescript /** * Check token allowance for DEX * @param tokenAddress - Token contract address * @param ownerAddress - Your wallet address * @param spenderAddress - DEX spender address * @returns Allowance amount */ async function checkAllowance( tokenAddress: string, ownerAddress: string, spenderAddress: string ): Promise { const tokenABI = [ { "constant": true, "inputs": [ { "name": "_owner", "type": "address" }, { "name": "_spender", "type": "address" } ], "name": "allowance", "outputs": [{ "name": "", "type": "uint256" }], "payable": false, "stateMutability": "view", "type": "function" } ]; const tokenContract = new web3.eth.Contract(tokenABI, tokenAddress); try { const allowance = await tokenContract.methods.allowance(ownerAddress, spenderAddress).call(); return BigInt(String(allowance)); } catch (error) { console.error('Failed to query allowance:', error); throw error; } } ``` ## 3. Check the Approval Parameters and Initiate the Approval If the allowance is lower than the amount you want to swap, you need to approve the token.
### 3.1 Define your transaction approval parameters ```typescript const getApproveTransactionParams = { chainIndex: chainIndex, tokenContractAddress: tokenAddress, approveAmount: amount }; ``` ### 3.2 Define helper functions ```typescript async function getApproveTransaction( tokenAddress: string, amount: string ): Promise { try { const path = 'dex/aggregator/approve-transaction'; const url = `${baseUrl}${path}`; const params = { chainIndex: chainIndex, tokenContractAddress: tokenAddress, approveAmount: amount }; // Prepare authentication const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); if (response.data.code === '0') { return response.data.data[0]; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get approval transaction data:', (error as Error).message); throw error; } } ``` ### 3.3 Create Compute gasLimit utility function Using the Onchain gateway API to get the gas limit. ```typescript /** * Get transaction gas limit from Onchain gateway API * @param fromAddress - Sender address * @param toAddress - Target contract address * @param txAmount - Transaction amount (0 for approvals) * @param inputData - Transaction calldata * @returns Estimated gas limit */ async function getGasLimit( fromAddress: string, toAddress: string, txAmount: string = '0', inputData: string = '' ): Promise { try { const path = 'dex/pre-transaction/gas-limit'; const url = `https://web3.okx.com/api/v6/${path}`; const body = { chainIndex: chainIndex, fromAddress: fromAddress, toAddress: toAddress, txAmount: txAmount, extJson: { inputData: inputData } }; // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { return response.data.data[0].gasLimit; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get gas limit:', (error as Error).message); throw error; } } ``` Using RPC to get the gas limit. ```typescript const gasLimit = await web3.eth.estimateGas({ from: WALLET_ADDRESS, to: tokenAddress, value: '0', data: approveData.data }); // Add 20% buffer const gasLimit = (BigInt(gasLimit) * BigInt(12) / BigInt(10)).toString(); ``` ### 3.4 Get transaction information and send approveTransaction ```typescript /** * Sign and send approve transaction * @param tokenAddress - Token to approve * @param amount - Amount to approve * @returns Transaction hash of the approval transaction */ async function approveToken(tokenAddress: string, amount: string): Promise { const spenderAddress = '0x3b3ae790Df4F312e745D270119c6052904FB6790'; // Ethereum Mainnet DEX spender // See Router addresses at: https://web3.okx.com/build/docs/waas/dex-smart-contract const currentAllowance = await checkAllowance(tokenAddress, WALLET_ADDRESS, spenderAddress); if (currentAllowance >= BigInt(amount)) { console.log('Sufficient allowance already exists'); return null; } console.log('Insufficient allowance, approving tokens...'); // Get approve transaction data from OKX DEX API const approveData = await getApproveTransaction(tokenAddress, amount); // Get accurate gas limit using RPC const gasLimit = await web3.eth.estimateGas({ from: WALLET_ADDRESS, to: tokenAddress, value: '0', data: approveData.data }); // Get accurate gas limit using Onchain gateway API // const gasLimit = await getGasLimit(WALLET_ADDRESS, tokenAddress, '0', approveData.data); // Get current gas price const gasPrice = await web3.eth.getGasPrice(); const adjustedGasPrice = BigInt(gasPrice) * BigInt(15) / BigInt(10); // 1.5x for faster confirmation // Get current nonce const nonce = await web3.eth.getTransactionCount(WALLET_ADDRESS, 'latest'); // Create transaction object const txObject = { from: WALLET_ADDRESS, to: tokenAddress, data: approveData.data, value: '0', gas: gasLimit, gasPrice: adjustedGasPrice.toString(), nonce: nonce }; // Sign and broadcast transaction const signedTx = await web3.eth.accounts.signTransaction(txObject, PRIVATE_KEY); const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction); console.log(`Approval transaction successful: ${receipt.transactionHash}`); return receipt.transactionHash; } ``` ## 4. Get Quote Data ### 4.1 Define quote parameters ```typescript const quoteParams = { amount: fromAmount, chainIndex: chainIndex, toTokenAddress: toTokenAddress, fromTokenAddress: fromTokenAddress, }; ``` ### 4.2 Define helper functions ```typescript /** * Get swap quote from DEX API * @param fromTokenAddress - Source token address * @param toTokenAddress - Destination token address * @param amount - Amount to swap * @param slippagePercent - Maximum slippagePercent (e.g., "0.5" for 0.5%) * @returns Swap quote */ async function getSwapQuote( fromTokenAddress: string, toTokenAddress: string, amount: string, slippagePercent: string = '0.5' ): Promise { try { const path = 'dex/aggregator/quote'; const url = `${baseUrl}${path}`; const params = { chainIndex: chainIndex, fromTokenAddress, toTokenAddress, amount, slippagePercent }; // Prepare authentication const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); if (response.data.code === '0') { return response.data.data[0]; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get swap quote:', (error as Error).message); throw error; } } ``` ## 5. Prepare Transaction ### 5.1 Define swap parameters ```typescript const swapParams = { chainIndex: chainIndex, fromTokenAddress, toTokenAddress, amount, userWalletAddress: userAddress, slippagePercent }; ``` ### 5.2 Request swap transaction data ```typescript /** * Get swap transaction data from DEX API * @param fromTokenAddress - Source token address * @param toTokenAddress - Destination token address * @param amount - Amount to swap * @param userAddress - User wallet address * @param slippagePercent - Maximum slippagePercent (e.g., "0.5" for 0.5%) * @returns Swap transaction data */ async function getSwapTransaction( fromTokenAddress: string, toTokenAddress: string, amount: string, userAddress: string, slippagePercent: string = '0.5' ): Promise { try { const path = 'dex/aggregator/swap'; const url = `${baseUrl}${path}`; const params = { chainIndex: chainIndex, fromTokenAddress, toTokenAddress, amount, userWalletAddress: userAddress, slippagePercent }; // Prepare authentication const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); if (response.data.code === '0') { return response.data.data[0]; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get swap transaction data:', (error as Error).message); throw error; } } ``` ## 6. Simulate Transaction Before executing the actual swap, it's crucial to simulate the transaction to ensure it will succeed and to identify any potential issues: The Simulate API is available to our whitelisted customers only. Please reach out to dexapi@okx.com to request access. ```typescript async function simulateTransaction(swapData: any) { try { if (!swapData.tx) { throw new Error('Invalid swap data format - missing transaction data'); } const tx = swapData.tx; const params: any = { fromAddress: tx.from, toAddress: tx.to, txAmount: tx.value || '0', chainIndex: chainIndex, extJson: { inputData: tx.data }, includeDebug: true }; const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/pre-transaction/simulate"; const requestBody = JSON.stringify(params); const headers = getHeaders(timestamp, "POST", requestPath, "", requestBody); console.log('Simulating transaction...'); const response = await axios.post( `https://web3.okx.com${requestPath}`, params, { headers } ); if (response.data.code !== "0") { throw new Error(`Simulation failed: ${response.data.msg || "Unknown simulation error"}`); } const simulationResult = response.data.data[0]; // Check simulation success if (simulationResult.success === false) { console.error('Transaction simulation failed:', simulationResult.error); throw new Error(`Transaction would fail: ${simulationResult.error}`); } console.log('Transaction simulation successful'); console.log(`Estimated gas used: ${simulationResult.gasUsed || 'N/A'}`); if (simulationResult.logs) { console.log('Simulation logs:', simulationResult.logs); } return simulationResult; } catch (error) { console.error("Error simulating transaction:", error); throw error; } } ``` ## 7. Broadcast Transaction Use the Transaction API for gas estimation. This approach leverages Transaction API, which provides more accurate gas estimations than standard methods. ```typescript /** * Get transaction gas limit from Onchain gateway API * @param fromAddress - Sender address * @param toAddress - Target contract address * @param txAmount - Transaction amount (0 for approvals) * @param inputData - Transaction calldata * @returns Estimated gas limit */ async function getGasLimit( fromAddress: string, toAddress: string, txAmount: string = '0', inputData: string = '' ): Promise { try { const path = 'dex/pre-transaction/gas-limit'; const url = `https://web3.okx.com/api/v6/${path}`; const body = { chainIndex: chainIndex, fromAddress: fromAddress, toAddress: toAddress, txAmount: txAmount, extJson: { inputData: inputData } }; // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { return response.data.data[0].gasLimit; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get gas limit:', (error as Error).message); throw error; } } ``` - [Support](https://web3.okx.com/onchainos/dev-docs/home/support.md) # Support Welcome to API Support. Here you'll find resources and guidance for getting help with our products and services. ## Technical Support - Technical inquiries: [Discord Developer Community](https://discord.gg/mUqMWaFGyW). - Developers are encouraged to join the real-time technical discussion channel. ## Business Support - Business cooperation: onchainos@okx.com - For enterprise service requests, please include your company name and contact information. - [Change Log](https://web3.okx.com/onchainos/dev-docs/home/change-log.md) # Change Log ### March 30, 2026 - The dex router address for EVM chains under the Trade API has been updated. The API will automatically construct transaction calldata based on the latest address. If you have whitelist configurations, please update them accordingly. - The Token API under the Market API now supports pagination. ### March 26, 2026 - The Market API has added WebSocket push channels, enabling more customized and more real-time market capabilities. ### March 20, 2026 - The Market API has added address subscription and tracking, position cluster analysis, and new push channels, enabling more customized and more real-time market capabilities. ### March 10, 2026 - The Market API has added new Portfolio APIs to support PnL analysis and track. ### March 6, 2026 - The Market API has added new Trenches APIs to support meme trade and golden dog track. ### March 5, 2026 - The Market API has added new Strategy APIs to support more advanced indicators and tools. ### March 3, 2026 - The Trading API now supports AI-native tools. - The Market Data API now supports AI-native tools. ### January 28, 2026 Update - DEX API supports directly returning the approved contract address and approved calldata via the /swap endpoint. - RFQ has added support for an EVM EIP-712 signature troubleshooting tool, including the testSignOrder.js example. ### January 22, 2026 Update - DEX API now supports `useTokenLedger` feature in Solana `/swap-instruction` endpoint to support more customized and specific trading scenario ### December 19, 2025 Update - Update Firm-order API Request Parameters ### December 11, 2025 Update - Update Settlement Contract Address ### December 9, 2025 Update - Update Dexrouter Contract Address ### December 2, 2025 Update - Update Settlement Contract Address - Update EVM Signature Example ### November 26, 2025 Update - Update firm- order API Parameter: beneficiaryAddress - Remove dex-get-quote API Parameter: quoteCompareList ### November 21, 2025 Update - DEX API: Support Monad Chain ### October 30, 2025 Update - DEX API: corrected the parameter types for market, market firm order, makerAmount, and rfqId. - Added exactOut functionality (currently supported only in V5 DEX API). ### October 30, 2025 Update - DEX API Upgraded EVM routing algorithm for more intelligent order routing and splitting with new smart contract addresses. ### October 9, 2025 Update - Swap API supported Plasma chain from now. ### September 25, 2025 Update - Upgraded DEX API to V6 with major updates including an updated routing algorithm with Directed Acyclic Graphs for more intelligent order routing and splitting. - Updated a few paramaters in Get Quotes API, Get Solana Swap Instructions API, and Swap API including `chainIndex`, `slippagePercent`, `priceImpactProtectionPercent`, `maxAutoSlippagePercent`, `priceImpactPercent`, `toTokenIndex`, `fromTokenIndex`. ### September 11, 2025 Update - Standard market maker integration guidelines are published for market makers to easily integrate with OKX DEX RFQ system and provide liquidity to our users and partners. ### September 4, 2025 Update - The Market API now supports **Token API services**, allowing you to search for the tokens you need, access basic and detailed information, check holder statistics, or retrieve token ranking lists with a single request. ### August 28, 2025 Update - We are excited to announce that our paid plan will officially launch in September 2025! - The DEX API now supports multiple service tiers, designed to give you greater flexibility and scalability. - Higher tiers unlock enhanced features, increased rate limits, and priority support — empowering your business to build faster and scale with confidence. ### August 27, 2025 Update - The trading API swap endpoint now **supports RFQ quotes by default**, enabling your large orders to receive more favorable pricing. Since RFQ quotes may introduce some latency, you can disable it by adding the `disableRFQ` parameter in the `/swap` endpoint request. ### August 19, 2025 Update - DEX API does not support OKT Chain any more. - The `/swap API` now supports excluding specific liquidity sources when assembling calldata. You can use the `excludeDexIds` parameter to specify the liquidity pools you don’t want to use. ### July 1, 2025 Update - The `feePercent` parameter in the swap API now supports 9 decimal. - Trade API now supports MEV protection feature on SOL,ETH,BSC,BASE. ### June 6, 2025 Update - The `swapReceiverAddress` parameter in the swap API now supports Sui and Ton chains. You can now specify a different receiving address for a swap transaction on Sui and Ton chains. ### May 30, 2025 Update - Trade API now supports transaction simulate. You can take a look at "Onchain gateway API" for reference. - The Trade API now supports the `exactOut` reverse quoting function. You can specify the amount you want to receive in the swap to query the required input token amount. {' '} ExactOut feature currently only support Ethereum、Base、BSC 、Arbitrum chain and Uni v3 protocols ### May 22, 2025 Update - Market API now supports to returen up to 100 tokens' 5m、1h、4h、24h trading volume and 5m、1h、4h、24h price change,you can check in the /price-info endpoint ### May 16, 2025 Update - Trade API now supports Uni chain. - Trade API now supports four tier priority fee for the Solana chain. ### May 13, 2025 Update - Trade API now supports setting positive slippage gains for the Solana chain. This feature is only available to **whitelisted or enterprise users**. If you would like to use it, please contact dexapi@okx.com. ### May 5, 2025 Update - Trade API now supports setting the referral fee **for Solana chain up to 10%**. ### May 2, 2025 Update - Trade API now supports the Onchain Gateway API function, offering gas price estimation and on-chain transaction broadcasting services. ### May 1, 2025 Update - Trade API now supports setting the referral fee for **Ton chain**. - Trade API now supports setting referral fees for **wrapped tokens on EVM chains**. ### March 27, 2025 Update - OKX DEX API now supports the **Market API**. ### March 12, 2025 Update - Single-chain swaps now support the Sonic chain. ### January 23, 2025 Update - The single-chain swap API now supports specifying a single liquidity pool for swaps. You can achieve this by setting the `directRoute` parameter. - The single-chain swap API now supports the Transaction querying feature. ### December 26, 2024 Update - The single-chain swap API now supports an automatic slippage feature. ### November 25, 2024 Update - The single-chain swap API parameter `swapReceiverAddress` now supports the Solana chain. It is now possible to specify a different recipient address for a swap transaction on the Solana chain. ### November 12, 2024 Update - Added a new referral wallet address parameter for the single-chain swap API. Both Sol and SPL tokens now support direct use of wallet addresses for referral fee collection. - APIs for retrieving the single-chain liquidity list and the cross-chain bridge list now support protocol logos. - Single-chain quote and swap APIs now recognize and return risk tokens with honeypot mechanisms or tokens with 100% buy/sell tax. ### October 29, 2024 Update - Single-chain swaps now support the Sui chain. ### July 1, 2024 Update - The ETH dexRouter contract 0xf3de3c0d654fda23dad170f0f320a92172509127 will no longer function normally after August 1, 2024. Please switch to the latest version. ### June 19, 2024 Update - Swap API DEX Router eth contract address update ### May 7, 2024 Update - Solana mainnet supports commission-sharing ### April 19, 2024 Update - Cross-chain swap support SUI chain ### April 19, 2024 Update - Cross-chain swap support X Layer chain ### April 12, 2024 Update - Cross-chain slippage request parameter range adjusted to 0.002-0.5 - Cross-chain swap support Merlin chain ### April 12, 2024 Update - Added new response parameters (quoteCompareList) to DEX swap endpoint ### April 8, 2024 Update - Added new response parameters (toTokenReferrerAddress) to DEX swap endpoint ### April 2, 2024 Update - Updated DEX swap trading support Merlin Chain ### March 22, 2024 Update - Added new response parameters (callDataMemo) to DEX swap endpoint ### March 22, 2024 Update - Added new request parameters (sort) to cross-chain Get route information and Cross-chain swap endpoint - DEX XBridge contract address update ### March 13, 2024 Update - Added new response parameters (sourceChainGasfee, destinationChainGasfee, crossChainFee) to cross-chain Get transaction status endpoint - Added new request parameters (onlyBridge) and new response parameters (minmumReceive,maxPriorityFeePerGas) - Cross-chain API Smart contract part added cross-chain contract address (DEX XBridge contract address) - Cross-chain API added new Get the list of tokens supported by the cross-chain bridges endpoint ### March 07, 2024 Update - Added new request parameters (priceImpactProtectionPercentage) to Cross-chain & Single-chain swap endpoint ### February 29, 2024 Update - Added new response parameters (decimal) to DEX swap endpoint ### February 22, 2024 Update - Added new response parameters (maxPriorityFeePerGas) to DEX swap endpoint ### February 01, 2024 Update - Updated DEX swap trading support solana, added new request parameters (solTokenAccountAddress) - Added DEX swap trading support solana quick start ### January 17, 2024 Update - Added new request parameters (feePercent, referrerAddress) to Cross-chain swap endpoint ### January 11, 2024 Update - Cross-chain slippage range adjusted to 0.5-0.5 ### January 02, 2024 Update - Added new request parameters (receiveAddress) to Cross-chain swap endpoint - Added new request parameters (chainld) to cross-chain Get transaction status endpoint ### December 28, 2023 Update - Launched the first edition of OKX Web3 DeFi API documentation - Added functionality for investment, redemption, and reward claiming processes via DeFi API - Added methods for querying information, calculating estimated data, generating transaction data, and querying user information ### December 20, 2023 Update - Added new response parameters (crossChainFeeTokenAddress) to cross-chain Get route information endpoint and Cross-chain swap endpoint - Added new response parameters (status) to cross-chain Get transaction status endpoint ### December 14, 2023 Update - Added DEX Iframe ### December 14, 2023 Update - Added new optional parameter (swapReceiverAddress) to DEX swap interface ### December 08, 2023 Update - Added DEX limit order list query - Added DEX limit order get cancellation calldata ### December 06, 2023 Update - Added new response parameters (toDexRouterList) to cross-chain Get route information endpoint - Added new response parameters (toAmount, errorMsg) to cross-chain Get transaction status endpoint - Added cross-chain refund issues to cross-chain FAQ ### November 24, 2023 Update - The Order API has been expanded with a new listing module, enabling listings on OpenSea and OKX. - Added more detailed description to order structure ### November 23, 2023 Update - Added DEX cross-chain API quick start guidelines ### November 21, 2023 Update- Added DEX cross-chain API quick start guidelines ### November 15, 2023 Update - Added new response parameters (crossChainFee) to cross chain Get route information endpoint cross-chain/quote - Added new response parameters (crossChainFee) to cross chain Cross-chain swap endpoint cross-chain/quote ### November 10, 2023 Update - Added DEX API quick start guidelines ### November 7, 2023 Update - Added DEX cross-chain aggregator API ### October 31, 2023 Update - Added DEX limit order API ### October 23, 2023 Update - Added smart contract information, including contract addresses and ABI ### September 27, 2023 Update - Updated the content of integrating DApps with OKX Wallet on the mobile app - Added guide and sub pages for integrating DApps with OKX Wallet on the mobile app
### August 17, 2023 Update - Updated the API key authentication mechanism. Moving forward, all endpoints will require an API key generated from the Web3 developer portal. - Updated the URI of all endpoints to reflect the latest versioning - Updated error codes Update - Added API key authentication. Moving forward, all endpoints will require an API key generated from the Web3 developer portal - Updated error codes Update - Updated the API key authentication mechanism. Moving forward, all Web3 API endpoints will require an API key generated from the Web3 developer portal - Updated the URI of all endpoints to reflect the latest versioning
### May 29, 2023 Update- Added new BRC-20 endpoint: ``brc20/token-list`` - Added new response parameters (index, location) to BRC-20 endpoint ``brc20/transaction-list`` - Added new response parameters (location) to BRC-20 endpoint ``brc20/inscriptions-list``
- [Overview](https://web3.okx.com/onchainos/dev-docs/wallet/product-and-service.md) # Overview Onchain OS offers two services: Agentic Wallet and Wallet API. ## Agentic Wallet The most powerful Agentic wallet — private keys are fully protected by TEE at all times, AI Agents trade directly via natural language, backed by OKX's trading infrastructure and security systems serving tens of millions of users worldwide. ### Core Capabilities - **Security Architecture** — Private key generation, storage, and signing are completed entirely within a TEE secure environment. Automatic identity verification, blacklisted address blocking, and risky token alerts before every transaction — anomalies are blocked instantly. - **Multi-Chain Coverage** — Supports X Layer, Ethereum, Solana, and other major chains, with more being added. - **Multi-Address Management** — Create a wallet with just an email login. Derive up to 50 sub-wallets per account for parallel operations. - **Zero Gas on X Layer** — 0 Gas fees on X Layer, ideal for high-frequency trading scenarios. ## Wallet API Wallet API provides AI Agents, trading bots, and Web3 applications with complete on-chain asset querying and transaction execution — check balances, send transactions, and track on-chain activity, all through one unified interface. - **Check Balance** — Query total asset value, multi-chain token balances, and specific token holdings for any wallet in real time. - **Broadcast Transactions** — Estimate gas, simulate execution, broadcast transactions, and track order status in real time. - **Check Transaction History** — Query complete transaction records by address, with filters for asset type, transaction direction, and time range. - [Supported Networks](https://web3.okx.com/onchainos/dev-docs/wallet/supported-networks.md) # Supported Networks ## EVM-Compatible Networks | Chain | Agentic Wallet | Wallet API | ChainIndex | | ------------- | -------------- | ---------- | ---------- | | Arbitrum One | ✓ | ✓ | 42161 | | Avalanche C | ✓ | ✓ | 43114 | | Base | ✓ | ✓ | 8453 | | Blast | ✓ | ✓ | 81457 | | BNB Chain | ✓ | ✓ | 56 | | Conflux | ✓ | ✓ | 1030 | | Cronos | - | ✓ | 25 | | Ethereum | ✓ | ✓ | 1 | | Fantom | ✓ | ✓ | 250 | | Linea | ✓ | ✓ | 59144 | | Manta Pacific | - | ✓ | 169 | | Mantle | - | ✓ | 5000 | | Merlin | - | ✓ | 4200 | | Metis | - | ✓ | 1088 | | Monad | ✓ | ✓ | 143 | | Optimism | ✓ | ✓ | 10 | | Plasma | - | ✓ | 9745 | | Polygon | ✓ | ✓ | 137 | | Polygon zkEVM | - | ✓ | 1101 | | Scroll | ✓ | ✓ | 534352 | | Sonic | ✓ | ✓ | 146 | | Uni Chain | - | ✓ | 130 | | X Layer | ✓ | ✓ | 196 | | ZetaChain | - | ✓ | 7000 | | zkSync Era | ✓ | ✓ | 324 | ## Non-EVM Networks | Chain | Agentic Wallet | Wallet API | ChainIndex | | ------- | -------------- | ---------- | ---------- | | Bitcoin | - | ✓ | 0 | | Solana | ✓ | ✓ | 501 | | SUI | Coming Soon | ✓ | 784 | | Ton | Coming Soon | ✓ | 607 | | Tron | Coming Soon | ✓ | 195 | - [Agentic Wallet](https://web3.okx.com/onchainos/dev-docs/wallet/agentic-wallet.md) # Agentic Wallet Agentic Wallet is a dedicated onchain wallet for AI Agents — turning them from query assistants into onchain executors that can hold assets, sign, and submit transactions. ## Why OKX Agentic Wallet - **Quick setup** — Log in with email to create a wallet instantly — no seed phrase, no key configuration needed. - **Private keys are untouchable** — Generated and stored within a TEE secure environment, AI Agents can trade but cannot access the keys — including OKX. - **OKX-level execution capability** — Backed by the trading engine and security system serving tens of millions of users worldwide. - **Security controls** — Transactions go through risk simulation and scoring before execution, keeping everything safe and auditable. ## Core Capabilities - **Security Architecture** — Private key generation, storage, and signing are all completed within a TEE secure environment. Automatic identity verification before transactions, blacklisted address interception, risky token alerts, and immediate blocking upon anomaly detection. - **Multi-chain Coverage** — Covers nearly 20 chains, supporting transactions and transfers on X Layer, Ethereum, Solana, and other major chains, with continuous expansion. - **Multi-address Management** — A single wallet can derive up to 50 sub-wallets, supporting parallel multi-address operations. - **Zero Gas on X Layer** — Zero gas fees for operations on X Layer, ideal for high-frequency trading scenarios. ![agentic](../images/agentic.jpeg) - [Quickstart](https://web3.okx.com/onchainos/dev-docs/wallet/agentic-quickstart.md) # Quickstart AI Agents need a wallet to truly interact with the chain securely — holding assets, signing, and submitting transactions. With Agentic Wallet installed, your AI Agent can swap tokens, check balances, and transfer funds directly in conversation, no tool-switching, no manual signing. Don't have a wallet yet? Start with setup: Already have a wallet? Jump right in: - [Install Your Agentic Wallet](https://web3.okx.com/onchainos/dev-docs/wallet/install-your-agentic-wallet.md) # Install Your Agentic Wallet Provide your AI Agent with onchain wallet capabilities — private keys protected by TEE, automatic risk detection before transactions, from wallet setup to onchain trading all through conversation. ## Preparation: Install an AI Agent This guide uses [Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview) as an example. Onchain OS supports all mainstream agents ([Cursor](https://docs.cursor.com/get-started/installation), [OpenClaw](https://docs.openclaw.ai/), etc.). ## Step 1: Add Onchain OS to Your Agent Tell your Agent: ```plain text Run npx skills add okx/onchainos-skills to install Onchain OS skills. Note: Please install to the skill directory corresponding to your current Agent. ``` The Agent will complete the installation automatically. For more details, see [Github](https://github.com/okx/onchainos-skills). ## Step 2: Create a Wallet Tell your Agent: ```plain text Log in to Agentic Wallet with email ``` Enter your email and wait for the verification code: ```plain text ``` Enter the verification code: ```plain text ``` Once verified, the Agent will automatically create a wallet on first login: ```plain text Wallet created successfully! EVM Address: Solana Address: ``` Private keys are generated and stored entirely within the TEE — never exposed to anyone, including your Agent. Logging in with the same email restores the existing wallet automatically. - [Run Your First AI Agent](https://web3.okx.com/onchainos/dev-docs/wallet/run-your-first-ai-agent.md) # Run Your First AI Agent After installing and creating your wallet, fund your Agentic Wallet, then use natural language to have your Agent execute onchain trades. ## Fund Your Wallet Transfer assets to your Agentic Wallet address via an on-chain wallet or exchange. ## Check Balance ```plain text Check my wallet balance. ``` Once the funds arrive, you can start onchain trading! Try using natural language to have your Agent execute trades! ## Trading Example User tells the Agent to filter tokens and buy: ```plain text Find tokens on Solana that KOLs are buying, market cap under $5M, at least 2 KOL wallets buying, and buy 1 USDT worth ``` Agent filters tokens and recommends the best pick: ```plain text Token Market Cap Smart Money Wallets Sell Ratio $9.99M 9 wallets (×9 signals) 9.99% $9.99M 9 wallets (×9 signals) 99.99% is the best choice — lowest sell ratio and most signal occurrences. Buying 1 USDT worth. ``` Agent gets trade quote and asks for confirmation: ```plain text Trade quote: Details Value Sell 1 USDT Buy ~99.99 Price 1 ≈ $0.0099 Route USDT → ... → Price Impact -0.99% Honeypot No Tax 0% Gas Fee ~$0.009 Confirm trade? ``` User confirms the trade: ```plain text Confirm ``` Agent broadcasts transaction: ```plain text Trade successful! Details Value Sell 1 USDT Buy ~99.99 Route USDT → ... → Price Impact -0.99% Slippage 1% Order ID Wallet (Wallet 1) Transaction broadcast on Solana! ``` The above example is for demonstration purposes only and does not constitute investment advice. Please make trading decisions based on your own judgment. - [Skills](https://web3.okx.com/onchainos/dev-docs/wallet/agentic-wallet-skills.md) # Skills ## Overview Agentic Wallet provides the following features, covering the full workflow from login authentication to onchain transaction execution. Tell the Agent what you want to do in natural language, and it will automatically select and execute the corresponding feature. ## Features at a Glance | Feature | Description | |---|---| | Wallet Login Authentication | Email OTP or API Key authentication, with verification code validation, status queries, and logout | | Wallet Management | Create up to 50 sub-wallets, with default wallet configuration | | Portfolio Query | Multi-chain balance queries, total asset valuation, single token balance, supporting 17 chains | | Security Detection | Token honeypot detection, DApp phishing scanning, transaction risk interception, approval management | | Transfer | Send tokens to specified addresses, batch transfers supported, automatic security detection | | Transaction History | Transaction record queries, filterable by chain / token / direction | ## Wallet Login Authentication Log in to your wallet via email OTP or API Key. This is a prerequisite for all wallet operations. ```shell Log in to my wallet with email # Calls wallet login → wallet verify ``` ```shell Create a wallet with API Key # Calls wallet login (apikey mode) ``` ```shell Am I logged in? # Calls wallet status ``` ```shell Log out of my wallet # Calls wallet logout ``` ## Wallet Management Create, derive, and switch wallets. Each login method supports up to 50 sub-wallets, with each sub-wallet generating both EVM and Solana addresses simultaneously. ```shell Check wallet status # Calls wallet status ``` ```shell Show all wallets # Calls wallet balance --all ``` ```shell Create a new sub-wallet for me # Calls wallet add ``` ```shell Switch to wallet 2 # Calls wallet switch ``` ```shell Show my deposit address # Calls wallet balance ``` ```shell Operate on Solana # Calls wallet chains ``` ## Portfolio Query Query balances and assets. Query your own wallet after logging in, or query any address without logging in. ```shell Check my balance # Calls wallet balance ``` ```shell How much OKB do I have? # Calls wallet balance --token-address ``` ```shell Check the assets of this address 0x1234... # Calls wallet balance ``` ```shell How much are the total assets of this address worth? # Calls wallet balance ``` ## Security Detection Comprehensive security protection to ensure every operation is safe. ```shell Is this token safe? # Calls security token-scan ``` ```shell Is this website safe? # Calls security dapp-scan ``` ```shell Check my approvals # Calls security approvals ``` ```shell Is this transaction safe? # Calls security tx-scan ``` ```shell Is this signature request safe? # Calls security sig-scan ``` ## Transfer Send tokens to a specified address, with batch consolidation support. ```shell Send 0.1 ETH to 0x1234... # Calls wallet send ``` ```shell Consolidate all wallets' ETH to 0x1234... # Calls wallet balance --all → wallet send for each ``` ## Transaction History View transaction records, filterable by chain, token, and direction. Shows the most recent 20 entries by default, with pagination support. ```shell Show me my recent transactions # Calls wallet history ``` ```shell Show transactions on Arbitrum # Calls wallet history --chain ``` ```shell Show USDC transfer history # Calls wallet history ``` ```shell Show only incoming transfers # Calls wallet history ``` ```shell Look up this transaction 0xabc123... # Calls wallet history --tx-hash ``` ## Cross-Feature Composite Workflows A single instruction can automatically chain multiple features together. The Agent plans and executes in order — no need to break down steps manually. ```shell Check my holdings and sell the ones that dropped # Check holdings → Analyze → Trade ``` ```shell Find a promising meme coin on Solana and buy some # Search tokens → Check security → Buy ``` ```shell Execute this transaction safely # Check Gas → Simulate → Security scan → Execute → Track ``` ```shell Transfer 10 USDC from my main wallet to wallet 3, then use wallet 3 to buy ETH # Multi-wallet collaboration ``` ```shell Run a comprehensive security check and summarize the report # Full security audit workflow ``` ```shell I want to trade on uniswap.org, is it safe? # DApp security + interaction ``` - [Wallet API](https://web3.okx.com/onchainos/dev-docs/wallet/wallet-api-introduction.md) # Wallet API Wallet API is the core infrastructure module of OnchainOS, built for DApp developers — providing complete onchain asset querying and transaction execution capabilities. Check balances, send transactions, and track onchain activity, all through a unified multi-chain interface. - **Check Balance** — Query any wallet's total asset value, multi-chain token balances, and specific token holdings in real time. Automatically fetch the latest onchain state before trading. - **Transaction Gateway** — Estimate gas, simulate execution, broadcast transactions, and track order status in real time. Combines OKX's proprietary nodes with third-party nodes for smart multi-path broadcasting that improves onchain success rates. - **Transaction History** — Query complete transaction records by address or view specific transaction details. Supports multiple chains and transaction types, with filtering by asset type, direction, and time range. - [Check Balance](https://web3.okx.com/onchainos/dev-docs/wallet/balance-api-overview.md) # Check Balance Check Balance API retrieves asset balances for any wallet address. It supports querying total portfolio value, all token balances, or a specific token balance across multiple chains. Use it to build wallet dashboards, portfolio trackers, and asset management tools. ## Key Capabilities ### 1. Flexible Balance Query * Query total asset value across all supported chains by wallet address. * Retrieve a full list of token balances or query a specific token directly. * Supports native tokens and ERC-20/SPL tokens. ### 2. Real-Time Data * Returns up-to-date balances with current token prices. * Covers 130+ chains in a single integration. * Structured responses for easy parsing and display. - [API Reference](https://web3.okx.com/onchainos/dev-docs/wallet/balance-api-reference.md) # API Reference - [Get Supported Chains](https://web3.okx.com/onchainos/dev-docs/wallet/balance-api-chains.md) {/* api-page */} # Get Supported Chains Retrieve information on chains supported by the DEX Balance endpoint ### Request URL GET `https://web3.okx.com/api/v6/dex/balance/supported/chain` ## Request Parameters None ## Response Parameters | Parameter | Type | Description | |-----------|--------|-------------------| | name | String | Chain name | | logoUrl | String | Chain logo URL | | shortName | String | Chain short name | | chainIndex| String | Chain unique identifier | ## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/balance/supported/chain' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "name": "Ethereum", "logoUrl": "http://www.eth.org/eth.png", "shortName": "ETH", "chainIndex": "1" } ], "msg": "" } ``` - [Get Total Value](https://web3.okx.com/onchainos/dev-docs/wallet/balance-api-total-value.md) {/* api-page */} # Get Total Value Retrieve the total balance of all tokens and DeFi assets under an account. ### Request URL GET `https://web3.okx.com/api/v6/dex/balance/total-value-by-address` ## Request Parameters | Parameter | Type | Required | Description | | ------------------| ------- | -------- | ------------------------------------------------------------------ | | address | String | Yes | Get the total valuation for the address | | chains | String | Yes | Filter chains for which to query total assets, separated by ",". Supports up to 50 chains..
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). | | assetType | String | No | Query balance type. Default is to query all asset balances.
`0`: Query total balance for all assets, including tokens and DeFi assets.
`1`: Query only token balance.
`2`: Query only DeFi balance. | | excludeRiskToken | Boolean | No | Option to filter out risky airdrop & honeypot tokens. Default is to filter.
`true`: filter out, `false`: do not filter out
It supports only `ETH`、`BSC`、`SOL`、`BASE` for honeypot tokens, more chains will be supported soon. |
## Response Parameters | Parameter | Type | Description | | --- | --- | --- | | totalValue | String | Total asset balance based on the query type, returned in USD |
## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/balance/total-value-by-address?address=0x0b32aa5c1e71715206fe29b7badb21ad95f272c0&chains=1&assetType=0' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ``` json { "code": "0", "msg": "success", "data": [ { "totalValue": "1172.895057177065864522056725546579939398" } ] } ```
- [Get Total Token Balances](https://web3.okx.com/onchainos/dev-docs/wallet/balance-api-all-token-balances.md) {/* api-page */} # Get Total Token Balances Retrieve the list of token balances for an address across multiple chains or specified chains. ### Request URL GET `https://web3.okx.com/api/v6/dex/balance/all-token-balances-by-address` ## Request Parameters | Parameter | Type | Required | Description | |----------------|--------|----------|-----------------------------------------| | address | String | Yes | Address | | chains | Array | Yes | When filtering the chains for querying asset details, multiple chains should be separated by commas (`,`). A maximum of 50 chains is supported.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain).| | excludeRiskToken | String | No | Option to filter out risky airdrop & honeypot tokens. Default is to filter.
`0`: Filter out
`1`: Do not filter out
It supports only `ETH`、`BSC`、`SOL`、`BASE` for honeypot tokens, more chains will be supported soon. |
## Response Parameters | Parameter | Type | Description | |---------------|--------|------------------------------------------| | tokenAssets | Array | List of token balances | | >chainIndex | String | Unique identifier for the chain | | >tokenContractAddress | String | Contract address | | >address | String | Address | | >symbol | String | Token symbol | | >balance | String | Token balance | | >rawBalance | String | Raw balance of token address. For unsupported chains, this field is empty. More chains will be supported soon. | | >tokenPrice | String | Token unit value, priced in USD | | >isRiskToken | Boolean| `true`: flagged as a risky airdrop & honeypot token
`false`: not flagged as a risky airdrop & honeypot token |
## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/balance/all-token-balances-by-address?address=0xEd0C6079229E2d407672a117c22b62064f4a4312&chains=1' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ``` json { "code": "0", "msg": "success", "data": [ { "tokenAssets": [ { "chainIndex": "1", "tokenContractAddress": "0x386ae941d4262b0ee96354499df2ab8442734ec0", "symbol": "PT-sUSDE-27FEB2025", "balance": "47042180.520700015", "tokenPrice": "0.968391562089677097", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0", "symbol": "wstETH", "balance": "7565.892480395067", "tokenPrice": "4321.611627695311", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", "symbol": "WBTC", "balance": "329.10055205", "tokenPrice": "98847.8", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x23878914efe38d27c4d67ab83ed1b93a74d4086a", "symbol": "aEthUSDT", "balance": "30057379.938443", "tokenPrice": "0.99978", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x657e8c867d8b37dcc18fa4caead9c45eb088c642", "symbol": "eBTC", "balance": "271.94970471", "tokenPrice": "99094.345321371", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8", "symbol": "aEthWETH", "balance": "6080.001975381972", "tokenPrice": "3634.32", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xe00bd3df25fb187d6abbb620b3dfd19839947b81", "symbol": "PT-sUSDE-27MAR2025", "balance": "19016580.895408865", "tokenPrice": "0.952031186961110727", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xa17581a9e3356d9a858b789d68b4d866e593ae94", "symbol": "cWETHv3", "balance": "3000.000734740809", "tokenPrice": "3663.74", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x9d39a5de30e57443bff2a8307a4256c8797a3497", "symbol": "sUSDe", "balance": "4863500.628333919", "tokenPrice": "1.144688569528375454", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xec5a52c685cc3ad79a6a347abace330d69e0b1ed", "symbol": "PT-LBTC-27MAR2025", "balance": "46.02912324", "tokenPrice": "97165.169717785655331396", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x8236a87084f8b84306f72007f36f2618a5634494", "symbol": "LBTC", "balance": "38.09998", "tokenPrice": "99187.19184268864", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xbeef047a543e45807105e51a8bbefcc5950fcfba", "symbol": "steakUSDT", "balance": "482651.8612595832", "tokenPrice": "1.063", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x4c9edd5852cd905f086c759e8383e09bff1e68b3", "symbol": "USDe", "balance": "69564", "tokenPrice": "0.99977", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x8be3460a480c80728a8c4d7a5d5303c85ba7b3b9", "symbol": "sENA", "balance": "42294.989425", "tokenPrice": "1.19", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "", "symbol": "ETH", "balance": "8.135546539084933", "tokenPrice": "3638.63", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xbf5495efe5db9ce00f80364c8b423567e58d2110", "symbol": "ezETH", "balance": "5.270854886240325", "tokenPrice": "3763.152404188635320082", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x6b175474e89094c44da98b954eedeac495271d0f", "symbol": "DAI", "balance": "1196.2693184870445", "tokenPrice": "1.0002", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xc00e94cb662c3520282e6f5717214004a7f26888", "symbol": "COMP", "balance": "0.007643", "tokenPrice": "84.43345772756197", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x9abfc0f085c82ec1be31d30843965fcc63053ffe", "symbol": "Q*", "balance": "900", "tokenPrice": "0.000419255747329174", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xa1290d69c65a6fe4df752f95823fae25cb99e5a7", "symbol": "rsETH", "balance": "0.00007090104120006", "tokenPrice": "3765.640772858747921444", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x56015bbe3c01fe05bc30a8a9a9fd9a88917e7db3", "symbol": "CAT", "balance": "0.42", "tokenPrice": "0.06242994543936436", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xec53bf9167f50cdeb3ae105f56099aaab9061f83", "symbol": "EIGEN", "balance": "0.002496149915967488", "tokenPrice": "4.018538365202288", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x58d97b57bb95320f9a05dc918aef65434969c2b2", "symbol": "MORPHO", "balance": "0.001409373661132556", "tokenPrice": "3.3568669630371337", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xaf5191b0de278c7286d6c7cc6ab6bb8a73ba2cd6", "symbol": "STG", "balance": "0.000009547670354338", "tokenPrice": "0.49707759500034454", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xba3335588d9403515223f109edc4eb7269a9ab5d", "symbol": "GEAR", "balance": "0.000009005734110189", "tokenPrice": "0.012329598382413718", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x35fa164735182de50811e8e2e824cfb9b6118ac2", "symbol": "eETH", "balance": "0.000000000000000001", "tokenPrice": "3637.93", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xae7ab96520de3a18e5e111b5eaab095312d7fe84", "symbol": "stETH", "balance": "0.000000000000000001", "tokenPrice": "3637.93", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xa3931d71877c0e7a3148cb7eb4463524fec27fbd", "symbol": "sUSDS", "balance": "67435907.43236613", "tokenPrice": "0", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xa8705a14c79fa1cded70875510211fec822b3c30", "symbol": "BEEX", "balance": "5000000", "tokenPrice": "0", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xabc0abace9fb9625fcefbedc423e8f94225bd251", "symbol": "TANUKI", "balance": "3548102.746002181", "tokenPrice": "0", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x356b8d89c1e1239cbbb9de4815c39a1474d5ba7d", "symbol": "syrupUSDT", "balance": "1750000", "tokenPrice": "0", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" } ] } ] } ```
- [Get Specific Token Balance](https://web3.okx.com/onchainos/dev-docs/wallet/balance-api-token-balances.md) {/* api-page */} # Get Specific Token Balance Query the balance of a specific token under an address. ### Request URL POST `https://web3.okx.com/api/v6/dex/balance/token-balances-by-address` ## Request Parameters | Parameter | Type | Required | Description | |----------------|--------|----------|-----------------------------------------| | address | String | Yes | Address | | tokenContractAddresses | Array | Yes | List of tokens addresses to query. Maximum of 20 items. | | >chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). | | >tokenContractAddress | String | Yes | Token address.
`1`: Pass an empty string `""` to query the native token of the corresponding chain.
`2`: Pass the specific token contract address to query the corresponding token. | | excludeRiskToken | String | No | Option to filter out risky airdrop & honeypot tokens. Default is to filter
`0`: Filter out
`1`: Do not filter out
It supports only `ETH`、`BSC`、`SOL`、`BASE` for honeypot tokens, more chains will be supported soon. |
## Response Parameters | Parameter | Type | Description | |--------------|--------|-----------------------------------------| | tokenAssets | Array | List for token balances | | >chainIndex | String | Unique identifier for the chain | | >tokenContractAddress | String | Token address.If the return is an empty string `""`, it means the query is for the native token of the corresponding blockchain. | | >address | String | Address | | >symbol | String | Token symbol | | >balance | String | Token balance. | | >rawBalance | String | Raw balance of token address. For unsupported chains, this field is empty. More chains will be supported soon. | | >tokenPrice | String | Token price in USD | | >isRiskToken | Boolean| `true`: flagged as a risky airdrop & honeypot token
`false`: not flagged as a risky airdrop & honeypot token |
## Request Example ```shell curl --location --request POST 'https://web3.okx.com/api/v6/dex/balance/token-balances' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '{ "address": "0x50c476a139aab23fdaf9bca12614cdd54a4244e3", "tokenContractAddresses": [ { "chainIndex": "1", "tokenContractAddress": "" } ] }' ``` ## Response Example ``` json { "code": "0", "msg": "success", "data": [ { "tokenAssets": [ { "chainIndex": "1", "tokenContractAddress": "", "symbol": "eth", "balance": "0", "tokenPrice": "3640.43", "isRiskToken": false, "rawBalance": "", "address": "" } ] } ] } ```
- [Error Codes](https://web3.okx.com/onchainos/dev-docs/wallet/balance-error-code.md) # Error Codes | Code | HTTP status | Message | |-------|-------------|-----------------------------------------------------------------| | 50014 | 400 | param \{param0\} is invalid | | 50001 | 200 | Service temporarily unavailable. Try again later | | 81001 | 200 | Incorrect parameter: : \{param0\} | | 50011 | 429 | Too Many Requests | | 81104 | 200 | Chain not support | | 81001 | 200 | Required request body is missing | - [Broadcast Transactions](https://web3.okx.com/onchainos/dev-docs/wallet/onchain-gateway-api-overview.md) # Broadcast Transactions Transaction API supports onchain transaction simulation and broadcasting. It combines OKX Web3's proprietary RPC nodes with premium third-party nodes to enable intelligent broadcasting, lower failure rates, and faster confirmation speeds. Pair it with the Swap and Cross-Chain APIs to build a complete experience — no extra external resources needed. ## Key Capabilities ### 1. High-Availability Hybrid Node Architecture * Proprietary multi-chain node clusters for stable, high-performance service. * Third-party premium nodes integrated to form a redundant, resilient network. * Real-time health monitoring, dynamic load balancing, and sub-second failover. ### 2. Intelligent Multi-Broadcasting Engine * Broadcasts transactions across multiple node networks simultaneously. * Distributed propagation algorithms that raise onchain success rates. * Priority block-packaging for Ethereum, BNB Chain, Solana, and more. - [API Reference](https://web3.okx.com/onchainos/dev-docs/wallet/onchain-gateway-api-reference.md) # API Reference - [Get Supported Chains](https://web3.okx.com/onchainos/dev-docs/wallet/onchain-gateway-api-chains.md) {/* api-page */} # Get Supported Chains Retrieve information on chains supported by Onchain gateway API ### Request URL GET `https://web3.okx.com/api/v6/dex/pre-transaction/supported/chain` ## Request Parameters None ## Response Parameters | Parameter | Type | Description | |-----------|--------|-------------------| | name | String | Chain name | | logoUrl | String | Chain logo URL | | shortName | String | Chain short name | | chainIndex| String | Chain unique identifier | ## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/pre-transaction/supported/chain' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "name": "Ethereum", "logoUrl": "http://www.eth.org/eth.png", "shortName": "ETH", "chainIndex": "1" } ], "msg": "" } ``` - [Get Gas Price](https://web3.okx.com/onchainos/dev-docs/wallet/onchain-gateway-api-gas-price.md) {/* api-page */} # Get Gas Price Dynamically obtain estimated gas prices for various chains. ### Request URL GET `https://web3.okx.com/api/v6/dex/pre-transaction/gas-price` ## Request Parameters | Parameter | Type | Required | Description | |------------|--------|----------|-----------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). |
## Response Parameters ### EVM & Tron | Parameter | Type | Description | |------------------|---------|-----------------------------------| | normal | String | Medium gas price. For EVM, it is in wei. For Tron,it is in SUN | | min | String | Low gas price. For EVM, it is in wei. For Tron,it is in SUN | | max | String | High gas price. For EVM, it is in wei. For Tron,it is in SUN | | supporteip1559 | Boolean | Whether supports 1559 | | eip1559Protocol | Object | 1559 protocol | ### eip1559 Protocol | Parameter | Type | Description | |---------------------|--------|--------------------------------------| | eip1559Protocol | Object | Structure of 1559 protocol | | >suggestBaseFee | String | Suggested base fee = base fee * 1.25, in wei | | >baseFee | String | Base fee, in wei | | >proposePriorityFee | String | Medium priority fee, in wei | | >safePriorityFee | String | Low priority fee, in wei | | >fastPriorityFee | String | High priority fee, in wei | ### Solana | Parameter | Type | Description | |------------------|---------|-------------------| | priorityFee | String | Priority fee per compute unit. Only applicable to Solana | | >proposePriorityFee | String | Medium priority fee in microlamports.( it is also called Medium compute unit price ) 80th percentile| | >safePriorityFee | String | Low priority fee in microlamports.( it is also called Low compute unit price ) 60th percentile| | >fastPriorityFee | String | High priority fee in microlamports.( it is also called High compute unit price ) 95th percentile| | >extremePriorityFee | String | Extreme High priority fee in microlamports.( it is also called Extreme High compute unit price ) 99th percentile |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/pre-transaction/gas-price?chainIndex=1' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "normal" : "21289500000", // Medium gas price "min" : "15670000000", // Low gas price "max" : "29149000000", // High gas price "supportEip1559" : true, // Whether supports 1559 "eip1599Protocol": { "suggestBaseFee" : "15170000000", // Suggested base fee "baseFee" : "15170000000", // Base fee "proposePriorityFee" : "810000000", // Medium priority fee "safePriorityFee" : "500000000", // Low priority fee "fastPriorityFee" : "3360000000" // High priority fee }, "priorityFee":{} } ], "msg": "" } ```
- [Get Gas Limit](https://web3.okx.com/onchainos/dev-docs/wallet/onchain-gateway-api-gas-limit.md) {/* api-page */} # Get Gas Limit Retrieve estimated Gas Limit consumption through pre-execution of transaction information. ### Request URL POST `https://web3.okx.com/api/v6/dex/pre-transaction/gas-limit` ## Request Parameters | Parameter | Type | Required | Description | |------------|--------|----------|-----------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). | | fromAddress| String | Yes | From address. For `transfer`,`Swap`, `Approve`, it is a wallet address | | toAddress | String | Yes | To address.
For `transfer`, it can be a token address or wallet address.
For `Swap`, it should be OKX DEX router address.
For `Approve`, it is a token address | | txAmount | String | No | Transaction amount. Default value: `0`.
1. For **Native token transactions** ( where the `fromToken` is native token. e.g., Ethereum), the txAmount can be set to the native token quantity, or retrieved from [/swap](./dex-swap) api(e.g., `txAmount = swapResponse.tx.value`).
2.For **non-native token transactions**, set `txAmount` to `0`.
The valle must use base unit of the native token, e.g., wei for ETH | | extJson | Object | No | Additional parameters for calldata and other information | extJson | Parameter | Type | Required | Description | |-----------|--------|----------|-------------| | inputData | String | No | Calldata |
## Response Parameters | Parameter | Type | Description | |-----------|--------|-------------------| | gasLimit | String | Estimated gas limit |
## Request Example ``` shell curl --location --request POST 'https://web3.okx.com/api/v6/dex/pre-transaction/gas-limit' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '{ "fromAddress": "0x383c8208b4711256753b70729ba0cf0cda55efad", "toAddress": "0x4ad041bbc6fa102394773c6d8f6d634320773af4", "txAmount": "31600000000000000", "chainIndex": "1", "extJson": { "inputData":"041bbc6fa102394773c6d8f6d634320773af4" } }' ``` ## Response Example ```json { "code": "0", "data": [ { "gasLimit": "652683" } ], "msg": "" } ```
- [Simulate Transactions](https://web3.okx.com/onchainos/dev-docs/wallet/onchain-gateway-api-simulate-transaction.md) {/* api-page */} # Simulate Transactions Simulate a blockchain transaction before executing it to see the expected outcomes and potential risks.
Transaction simulate API is available to our whitelisted customers only. If you are interested, please contact us dexapi@okx.com. ### Request URL GET `https://web3.okx.com/api/v6/dex/pre-transaction/simulate` ## Request Parameters | Parameter | Type | Required | Description | |--------------|--------|----------|---------------------------------------------------------------------------------------| | fromAddress | String | Yes | Source address. For `Swap`, `Approve`, it is a wallet address | | toAddress | String | Yes | Destination address.
For `Swap`, it should be OKX DEX router address.
For `Approve`, it is a token address | | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum
See [Supported Chains](../home/supported-chain) for more.
It supports EVM、SOL、SUI, more chains will be supported soon. | | txAmount | String | No | Transaction amount. Default value: `0`.
1. For **Native token transactions** ( where the `fromToken` is native token. e.g., Ethereum), the txAmount can be set to the native token quantity, or retrieved from [/swap](./dex-swap) api(e.g., `txAmount = swapResponse.tx.value`).
2.For **non-native token transactions**, set `txAmount` to `0`.
The valle must use base unit of the native token, e.g., wei for ETH | | extJson | Object | Yes | Extended information object containing the following fields: | | > inputData | String | Yes | Call data for the transaction. The encoding rule require `base58`. | | priorityFee | String | No | Priority fee. Only applicable to Solana. | | gasPrice | String | No | Gas price for the transaction. |
## Response Parameters | Parameter | Type | Description | |--------------|--------|--------------------------------------------------------------------| | intention | String | Transaction purpose. Valid values: "Swap", "Token Approval" | | assetChange | Array | Details of asset changes resulting from the transaction | | > assetType | String | Asset type. Valid values: "NATIVE", "ERC20", "SPLTOKEN","SUITOKEN"| | > name | String | Asset name (e.g., "Ethereum") | | > symbol | String | Asset symbol (e.g., "ETH") | | > decimals | Number | Asset decimal precision | | > address | String | Asset contract address | | > imageUrl | String | URL to the asset's image | | > rawValue | String | Asset amount. Positive values indicate receiving assets, negative values indicate sending assets. | | gasUsed | String | Gas consumed by the transaction | | failReason | String | Human-friendly explanation if the transaction would fail | | risks | Array | Potential risks identified in the transaction | | > address | String | Address associated with the risk | | > addressType| String | Type of address. Valid values: "contract", "eoa" |
## Request Example ```shell curl --location --request POST 'https://web3.okx.com/api/v6/dex/pre-transaction/simulate' \ --header 'OK-ACCESS-KEY: your-access-key' \ --header 'OK-ACCESS-SIGN: your-access-sign' \ --header 'OK-ACCESS-PASSPHRASE: your-passphrase' \ --header 'OK-ACCESS-TIMESTAMP: 2025-05-19T10:00:00.000Z' \ --header 'Content-Type: application/json' \ --data-raw '{ "fromAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "toAddress": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", "chainIndex": "1", "txAmount": "0", "extJson": { "inputData": "0x38ed1739000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000000000000000000000000000000000000042ab52c000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000742d35cc6634c0532925a3b844bc454e4438f44e0000000000000000000000000000000000000000000000000000000064794b4b0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" }, "gasPrice": "12000000000" }' ``` ## Response Example ```json { "code": "0", "data": [ { "intention": "SWAP", "assetChange": [ { "assetType": "NATIVE", "name": "Ether", "symbol": "ETH", "decimals": 18, "address": "", "imageUrl": "", "rawValue": "-1000000000000000" }, { "assetType": "ERC20", "name": "USD Coin", "symbol": "USDC", "decimals": 6, "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "imageUrl": "", "rawValue": "1000000000000000" } ], "gasUsed": "180000", "failReason": "", "risks": [] } ], "msg": "success" } ```
- [Broadcast Transactions](https://web3.okx.com/onchainos/dev-docs/wallet/onchain-gateway-api-broadcast-transaction.md) {/* api-page */} # Broadcast Transactions Broadcast transactions to the specified blockchain.
Your end-user's transaction can only be covered by the MEV protection feature if you actually utilise OKX Build's API services for that particular transaction. MEV protection is currently an experimental feature provided by third-parties and OKX Build does not guarantee the effectiveness and quality of such MEV protection. ### Request URL POST `https://web3.okx.com/api/v6/dex/pre-transaction/broadcast-transaction` ## Request Parameters | Parameter | Type | Required | Description | |------------ |-------- |----------|------------------------------------------------------------------------| | signedTx | String | Yes | The transaction string after being signed | | chainIndex | String | Yes | Unique identifier for the chain.
e.g., ETH=1.
See more [here](../home/supported-chain). | | address | String | Yes | Address. | | extraData | String | No | Additional parameters for calldata and other information | | > enableMevProtection | Boolean | No | Enable MEV protection. Not enabled by default. Valid values: `false`:not enabled, `true`:enabled
It supports only `ETH`、`BSC`、`SOL`、`BASE`, more chains will be supported soon. | | > jitoSignedTx | String | No | The transaction string after being signed that will send to Jito. The encoding rule require `base58`, applicable to `SOL`. For SOL, `signedTx` and `jitoSignedTx` must be passed at the same time |
## Response Parameters | Parameter | Type | Description | |-----------|--------|--------------------| | orderId | String | Unique transaction identifier | | txHash | String | Transaction Hash.
It supports only `ETH`、`BSC`、`SOL`、`BASE`, more chains will be supported soon. |
## Request Example ``` shell curl --location --request POST 'https://web3.okx.com/api/v6/dex/pre-transaction/broadcast-transaction' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '{ "signedTx":"0x08b47112567534ad041bbc6fa102394773c6d8f6d634320773af4da55efa", "address": "0x383c8208b4711256753b70729ba0cf0cda55efad", "chainIndex": "1", "extraData":"{\"enableMevProtection\":true,\"jitoSignedTx\":\"0x123456\"}" }' ``` ## Response Example ```json { "code": "0", "data": [ { "orderId": "0x383c8208b4711256753b70729ba0cf0cda55efad", "txHash": "0xd394f356a16b618ed839c66c935c9cccc5dde0af832ff9b468677eea38759db5" } ], "msg": "" } ```
- [Get Transaction Orders](https://web3.okx.com/onchainos/dev-docs/wallet/onchain-gateway-api-orders.md) {/* api-page */} # Get Transaction Orders Get the list of orders sent from transaction broadcasting API. This supports querying transactions sorted in descending order by time. ### Request URL GET `https://web3.okx.com/api/v6/dex/post-transaction/orders` ## Request Parameters | Parameter | Type | Required | Description | |------------ |-------- |----------|----------------------------------------------------| | address | String | Yes | Address | | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). | | txStatus | String | No | Transaction status:
`1`: Pending
`2`: Success
`3`: Failed | | orderId | String | No | Unique identifier for the transaction order | | cursor | String | No | Cursor | | limit | String | No | Number of records returned, default is the most recent 20, maximum is 100 |
## Response Parameters | Parameter | Type | Description | |------------ |-------- |-----------------------------------------------------| | chainIndex | String | Unique identifier for the chain | | address | String | Address | | orderId | String | Order ID | | txStatus | String | Transaction status:
`1`: Pending
`2`: Success
`3`: Failed | | failReason | String | The reason for failed transaction | | txHash | String | Transaction hash |
## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/post-transaction/orders?address=0x238193be9e80e68eace3588b45d8cf4a7eae0fa3&chainIndex=1' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ``` json { "code": "0", "msg": "success", "data": [ { "cursor": "1", "orders":[ { "chainIndex": "1", "orderId": "016cf21d020be6c2f071dad9bbd8ec5cb9342fa8", "address": "0x238193be9e80e68eace3588b45d8cf4a7eae0fa3", "txHash": "0xb240e65dd9156b4a450be72f6c9fe41be6f72397025bb465b21a96ee9871a589", "failReason": "", "txstatus": "2" }, { "chainIndex": "1", "orderId": "592051a92a744627022955be929ecb5c9e777705", "address": "0x238193be9e80e68eace3588b45d8cf4a7eae0fa3", "txHash": "0xc401ffcd2a2b4b1db42ce68dfde8e63c0a1e9653484efb2873dbf5d0cbeb227a", "txstatus": "1", "failReason": "", } ] } ] } ```
- [Error Codes](https://web3.okx.com/onchainos/dev-docs/wallet/onchain-gateway-error-code.md) # Error Codes | Code | HTTP status | Message | |-------|-------------|-----------------------------------------------------------------------------------------| | 50001 | 200 | Service temporarily unavailable. Try again later | | 81001 | 200 | Incorrect parameter | | 81108 | 200 | Wallet type does not match the required type | | 81104 | 200 | Chain not support | | 81152 | 200 | Coin not exist | | 81451 | 200 | node return failed | - [Check Transaction History](https://web3.okx.com/onchainos/dev-docs/wallet/tx-history-api-overview.md) # Check Transaction History Transaction History API retrieves onchain transaction records for any wallet address. It supports multiple chains and returns structured data covering transfers, contract interactions, and token activity. Use it to build portfolio trackers, wallet dashboards, and onchain analytics tools. ## Key Capabilities ### 1. Multi-Chain Transaction Query * Query transaction history across all supported chains by wallet address. * Filter by asset type, transaction type, or time range. * Paginated responses for efficient data handling. ### 2. Detailed Transaction Data * Returns transaction hash, timestamp, status, gas fee, and block number. * Covers native token transfers, ERC-20/SPL token transfers, and contract calls. * Supports both real-time and historical data access. - [API Reference](https://web3.okx.com/onchainos/dev-docs/wallet/tx-history-api-reference.md) # API Reference - [Get Supported Chains](https://web3.okx.com/onchainos/dev-docs/wallet/tx-history-api-chains.md) {/* api-page */} # Get Supported Chains Retrieve information on chains supported by Transaction history API ### Request URL GET `https://web3.okx.com/api/v6/dex/balance/supported/chain` ## Request Parameters None ## Response Parameters | Parameter | Type | Description | |-----------|--------|-------------------| | name | String | Chain name | | logoUrl | String | Chain logo URL | | shortName | String | Chain short name | | chainIndex| String | Chain unique identifier | ## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/balance/supported/chain' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "name": "Ethereum", "logoUrl": "http://www.eth.org/eth.png", "shortName": "ETH", "chainIndex": "1" } ], "msg": "" } ``` - [Get History by Address](https://web3.okx.com/onchainos/dev-docs/wallet/tx-history-api-history.md) {/* api-page */} # Get History by Address Query the transaction history under the address dimension for 6 months, sorted in descending chronological order. ### Request URL GET `https://web3.okx.com/api/v6/dex/post-transaction/transactions-by-address` ## Request Parameters | Parameter | Type | Required | Description | |-------------- |-------- |---------- |--------------------------------------------------------------------------------------------------------------- | | address | String | Yes | Address to query the transaction history for | | chains | String | No | Filter the chains whose transaction history needs to be queried. Multiple chains are separated by ",". A maximum of 50 chains are supported. | | tokenContractAddress | String | No | Token contract address; if empty, query addresses with main chain currency balance;if not pass, query all | | begin | String | No | Start time, queries transactions after this time. Unix timestamp, in milliseconds | | end | String | No | End time, queries transactions before this time. If both begin and end are not provided, queries transactions before the current time. Unix timestamp, in milliseconds | | cursor | String | No | Cursor | | limit | String | No | Number of records to return, defaults to the most recent 20 records.
Up to a maximum of 20 records for query on single chain.
Up to a maximum of 100 records for query on multiple chain. | |
## Response Parameters | Parameter | Type | Description | |----------------- |--------------------------------- |----------------------------------------------------- | | transactions | Array | List of transactions | | >chainIndex | String | Chain ID | | >txHash | String | Transaction hash | | >itype | String | Transaction tier type
`0`: Outer main chain coin transfer
`1`: Contract inner main chain coin transfer
`2`: Token transfer | | >methodId | String | Contract Function Call | | >nonce | String | The nth transaction initiated by the sender address | | >txTime | String | Transaction time in Unix timestamp format, in milliseconds, e.g., 1597026383085 | | >from | Array | Transaction input | | >>address | String | Sending/input address, comma-separated for multi-signature transactions | | >>amount | String | Input amount | | >to | Array | Transaction output | | >>address | String | Receiving/output address, comma-separated for multiple addresses | | >>amount | String | Output amount | >tokenContractAddress | String | Token contract address | | >amount | String | Transaction amount | | >symbol | String | Currency symbol corresponding to the transaction amount | | >txFee | String | Transaction fee | | >txStatus | String | Transaction status: `success` for successful transactions, `fail` for failed transactions, `pending` for pending transactions | | >hitBlacklist | Boolean | `false`: Not in blacklist, `true`: In blacklist | | cursor | String | Cursor |
## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/post-transaction/transactions-by-address?addresses=0x50c476a139aab23fdaf9bca12614cdd54a4244e4&chains=1' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ``` json { "code": "0", "msg": "success", "data": [ { "cursor": "1706197403", "transactionList": [ { "chainIndex": "1", "txHash": "0x963767695543cfb7804039c470b110b87adf9ab69ebc002b571523b714b828ca", "methodId": "", "nonce": "", "txTime": "1724213411000", "from": [ { "address": "0xae7ab96520de3a18e5e111b5eaab095312d7fe84" "amount": "" } ], "to": [ { "address": "0x50c476a139aab23fdaf9bca12614cdd54a4244e4" "amount": "" } ], "tokenContractAddress": "0xe13c851c331874028cd8f681052ad3367000fb13", "amount": "1", "symbol": "claim rewards on stethdao.net", "txFee": "", "txStatus": "success", "hitBlacklist": true, "itype": "2" } ] } ] } ```
- [Get Specific Transaction](https://web3.okx.com/onchainos/dev-docs/wallet/tx-history-api-detail.md) {/* api-page */} # Get Specific Transaction Retrieve details of a transaction based on `txHash` for 6 months. It decomposes a transaction and its internal transactions into sub-transactions based on asset type:
`0`: Outer layer mainnet coin transfer
`1`: Inner layer mainnet coin transfer in a contract
`2`: Token transfer It decomposes a transaction into sub-transactions based on asset type. For EVM transactions, different sub-transaction types include:
`0`: Outer layer mainnet coin transfer
`1`: Inner layer mainnet coin transfer in a contract
`2`: Token transfer
### Request URL GET `https://web3.okx.com/api/v6/dex/post-transaction/transaction-detail-by-txhash` ## Request Parameters | Parameter | Type | Required | Description | |--------------------|----------------|------------------|--------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain | | txHash | String | Yes | Transaction hash | | itype | String | No | Layer type for transactions
`0`: Outer layer mainnet coin transfer
`1`: Inner layer mainnet coin transfer
`2`: Token transfer |
## Response Parameters | Parameter | Type | Description | |------------------------------------|----------------|----------------------------------------------------------------| | chainIndex | String | Unique identifier for the chain | | height | String | Block height where the transaction occurred | | txTime | String | Transaction time; Unix timestamp in milliseconds | | txhash | String | Transaction hash | | txStatus | String | Transaction status:
`1`: pending
`2`: success
`3`: fail | | gasLimit | String | Gas limit | | gasUsed | String | Gas used | | gasPrice | String | Gas price | | txFee | String | Transaction fee. | | nonce | String | Nonce | | amount | String | Transaction amount | | symbol | String | Currency symbol for the transaction amount | | methodId | String | Contract method ID | | fromDetails | Array | Details of transaction inputs | | >address | String | Sender/input address | | >vinIndex | String | Index of the input in the current transaction | | >preVoutIndex | String | Index of the output in the previous transaction | | >txhash | String | Transaction hash, used with `preVoutIndex` to uniquely identify the UTXO | | >isContract | Boolean | Whether the sender address is a contract (true: yes; false: no) | | >amount | String | Transaction amount | | toDetails | Array | Details of transaction outputs | | >address | String | Receiver/output address | | >voutIndex | String | Output index | | >isContract | Boolean | Whether the receiver address is a contract (true: yes; false: no) | | >amount | String | Transaction amount | | internalTransactionDetails | Array | Internal transaction details | | >from | String | Sender address for the internal transaction | | >to | String | Receiver address for the internal transaction | | >isFromContract | Boolean | Whether the sender address is a contract (true: yes; false: no) | | >isToContract | Boolean | Whether the receiver address is a contract (true: yes; false: no) | | >amount | String | Transaction amount | | >txStatus | String | Transaction status | | tokenTransferDetails | Array | Token transfer details | | >from | String | Sender address for token transfer | | >to | String | Receiver address for token transfer | | >isFromContract | Boolean | Whether the sender address is a contract (true: yes; false: no) | | >isToContract | Boolean | Whether the receiver address is a contract (true: yes; false: no) | | >tokenContractAddress | String | Token contract address | | >symbol | String | Token symbol | | >amount | String | Token amount | | l1OriginHash | String | Hash of the L1 transaction executed |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/post-transaction/transaction-detail-by-txhash?txHash=0x9ab8ccccc9f778ea91ce4c0f15517672c4bd06d166e830da41ba552e744d29a5&chainIndex=42161' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ``` json { "code": "0", "msg": "success", "data": [ { "chainIndex": "42161", "height": "245222398", "txTime": "1724253417000", "txhash": "0x9ab8ccccc9f778ea91ce4c0f15517672c4bd06d166e830da41ba552e744d29a5", "gasLimit": "2000000", "gasUsed": "2000000", "gasPrice": "10000000", "txFee":"", "nonce": "0", "symbol": "ETH", "amount": "0", "txStatus": "success", "methodId": "0xc9f95d32", "l1OriginHash": "0xa6a87ba2f18cc32bbae8f3b2253a29a9617ed1eb0940d80443f6e3bf9873dbad", "fromDetails": [ { "address": "0xd297fa914353c44b2e33ebe05f21846f1048cfeb", "vinIndex": "", "preVoutIndex": "", "txHash": "", "isContract": false, "amount": "" } ], "toDetails": [ { "address": "0x000000000000000000000000000000000000006e", "voutIndex": "", "isContract": false, "amount": "" } ], "internalTransactionDetails": [ { "from": "0x0000000000000000000000000000000000000000", "to": "0xd297fa914353c44b2e33ebe05f21846f1048cfeb", "isFromContract": false, "isToContract": false, "amount": "0.02", "txStatus": "success" }, { "from": "0xd297fa914353c44b2e33ebe05f21846f1048cfeb", "to": "0x428ab2ba90eba0a4be7af34c9ac451ab061ac010", "isFromContract": false, "isToContract": false, "amount": "0.00998", "txStatus": "success" }, { "from": "0xd297fa914353c44b2e33ebe05f21846f1048cfeb", "to": "0x428ab2ba90eba0a4be7af34c9ac451ab061ac010", "isFromContract": false, "isToContract": false, "amount": "0.009977946366846017", "txStatus": "success" } ], "tokenTransferDetails": [] } ] } ```
- [Error Codes](https://web3.okx.com/onchainos/dev-docs/wallet/tx-history-error-code.md) # Error Codes | Code | HTTP status | Message | |-------|-------------|-----------------------------------------------------------------------------------------| | 81001 | 200 | Incorrect parameter | - [Introduction](https://web3.okx.com/onchainos/dev-docs/wallet/defi-api-overview.md) # Introduction DeFi API is a core infrastructure module of OnchainOS, providing DeFi users with comprehensive DeFi investment capabilities — product discovery, trade execution, and position management, all through a single interface that covers mainstream DeFi protocols. - **Product Discovery** — Query investment products across dozens of DeFi protocols such as Aave, Lido, and more. Retrieve detailed product information including APY, fees, total value locked, etc. - **Trade Execution** — Subscribe to or redeem investment products, lend or repay assets, and claim related investment rewards. - **User Holdings** — Query DeFi investment position details across chains and protocols, with real-time tracking of principal, earnings, APY, and other relevant data. - [Investment Product Query](https://web3.okx.com/onchainos/dev-docs/wallet/defi-product-introduction.md) # Investment Product Query The Investment Product Query API aggregates investment product information from dozens of DeFi protocols. Developers can search or filter by keywords to retrieve detailed product parameters (APY, TVL, underlying assets, fees, etc.) to prepare for subsequent transaction execution. ## Core Capabilities ### 1. Product Search and Filtering - Search investment products by token keywords, protocol names, chain ID, investment type, and other criteria - Filter investment products by key metrics such as APY, TVL, and more ### 2. Query Product Details - Retrieve product details including underlying assets, APY breakdowns, fee structures, and other data. - Query which operations a DeFi investment product supports (such as subscribe, redeem, claim rewards, etc.) - [API Reference](https://web3.okx.com/onchainos/dev-docs/wallet/defi-product-api-reference.md) # API Reference - [Get Supported Chains](https://web3.okx.com/onchainos/dev-docs/wallet/defi-product-supported-chains.md) # Get Supported Chains Query all chains currently covered by DeFi investment products. The chain list is aggregated from the database by a scheduled task and cached in Redis, containing chain IDs and network names. It can be used to display chain filters on the frontend, or as a source for the `chainIndex` parameter in other endpoints (such as `/api/v6/defi/product/search` and `/api/v6/defi/product/supported-platforms`). **URL**: GET `/api/v6/defi/product/supported-chains` ## Request Parameters No request parameters. ## Request Example ``` GET /api/v6/defi/product/supported-chains ``` ## Response Parameters **data Array Elements** | Field | Type | Explanation | | --- | --- | --- | | chainIndex | String | Chain ID (e.g., "1"=Ethereum, "56"=BSC, "137"=Polygon) | | network | String | Network identifier (e.g., "ETH", "BSC", "POLYGON") | ## Response Example ```json { "code": 0, "data": [ { "chainIndex": "1", "network": "ETH" }, { "chainIndex": "56", "network": "BSC" }, { "chainIndex": "137", "network": "POLYGON" }, { "chainIndex": "42161", "network": "ARBITRUM" }, { "chainIndex": "8453", "network": "BASE" } ] } ``` > The API returns chains based on which ones currently have listed investment products. The list is updated by a scheduled task, typically refreshed once per hour. - [Get Supported Protocols](https://web3.okx.com/onchainos/dev-docs/wallet/defi-product-supported-platforms.md) # Get Supported Protocols Query all protocols currently covered by DeFi investment products along with their statistics. The response includes protocol name, protocol ID, and the number of investment products under each protocol. It can be used to display protocol filters on the frontend or for protocol overview pages. **URL**: GET `/api/v6/defi/product/supported-platforms` ## Request Parameters No request parameters. ## Request Example ``` GET /api/v6/defi/product/supported-platforms ``` ## Response Parameters **data Array Elements** | Field | Type | Explanation | | --- | --- | --- | | analysisPlatformId | String | Protocol ID | | platformName | String | Protocol name (e.g., "Aave V3", "Lido", "PancakeSwap V3") | | investmentCount | Long | Number of investment products under this protocol | ## Response Example ```json { "code": 0, "data": [ { "analysisPlatformId": "10", "platformName": "Aave V3", "investmentCount": 68 }, { "analysisPlatformId": "20", "platformName": "Lido", "investmentCount": 1 }, { "analysisPlatformId": "30", "platformName": "PancakeSwap V3", "investmentCount": 120 } ] } ``` > The actual number of protocols and investment products depends on what is currently live. - [Investment Product Search](https://web3.okx.com/onchainos/dev-docs/wallet/defi-product-search.md) # Investment Product Search This is the first step in the DeFi investment workflow. When a user wants to find DeFi investment opportunities, use this endpoint to search for available investment products by token name (e.g. "USDC", "ETH"). The response includes investment product ID, name, protocol, APY, TVL, and other information. Once you have the `investmentId`, you can call `/product/detail` to retrieve details, or call `/product/detail/prepare` to prepare transaction parameters. **URL**: POST `/api/v6/defi/product/search` ## Request Parameters | Field | Type | Required | Explanation | | --- | --- | --- | --- | | tokenKeywordList | Array | Yes | Token keyword list (e.g. ["USDC", "ETH"]) | | platformKeywordList | Array | No | Platform keyword list (e.g. ["AAVE V3"]) | | pageNum | Integer | No | Page number, minimum 1; current fixed pageSize=20 | | chainIndex | String | No | Chain ID (e.g. 1=ETH, 56=BSC, etc.) | | productGroup | String | No | Investment type filter, default SINGLE\_EARN; includes: SINGLE\_EARN, DEX\_POOL, LENDING | ## Request Examples ### Example 1: Search USDC Token Only ```json { "tokenKeywordList": ["USDC"], "pageNum": 1 } ``` ### Example 2: Search Multiple Tokens + Specified Chain ```json { "tokenKeywordList": ["USDC", "ETH"], "chainIndex": "1", "pageNum": 1 } ``` ### Example 3: Search + Filter by Protocol + Investment Type ```json { "tokenKeywordList": ["USDC"], "platformKeywordList": ["Aave"], "productGroup": "SINGLE_EARN", "pageNum": 1 } ``` ```json { "tokenKeywordList": ["USDC"], "platformKeywordList": ["Uniswap"], "productGroup": "DEX_POOL", "pageNum": 1 } ``` ```json { "tokenKeywordList": ["USDC"], "platformKeywordList": ["AAVE V3"], "productGroup": "LENDING", "pageNum": 1 } ``` ### Example 4: Search Multi-Chain Data ```json { "tokenKeywordList": ["USDT"], "pageNum": 1 } ``` ## Response Parameters | Field | Type | Explanation | | --- | --- | --- | | total | Integer | Total count | | list | Array | Product list | | > investmentId | String | Investment product ID | | > name | String | Investment product name | | > platformName | String | Protocol name | | > rate | String | APY | | > tvl | String | TVL | | > chainIndex | String | Chain ID | | > detailPath | String | Detail page path | | > feeRate | BigDecimal | Fee rate | | > productGroup | String | Investment product type | ## Response Example **Search USDC + Protocol Aave** ```json { "code": 0, "msg": "", "data": { "total": 8, "list": [ { "investmentId": 9502, "name": "USDC", "platformName": "Aave V3", "rate": "0.02140", "tvl": "3423591587.48413", "detailPath": null, "feeRate": null, "productGroup": "SINGLE_EARN", "chainIndex": "1" }, { "investmentId": 378532533, "name": "USDC", "platformName": "Aave V3", "rate": "0.02590", "tvl": "370145418.65238", "detailPath": null, "feeRate": null, "productGroup": "SINGLE_EARN", "chainIndex": "8453" }, { "investmentId": 124, "name": "USDC", "platformName": "Aave V3", "rate": "0.03510", "tvl": "100947767.28590", "detailPath": null, "feeRate": null, "productGroup": "SINGLE_EARN", "chainIndex": "43114" } ] } } ``` > The actual response returns 8 results; only the first 3 are shown here. `rate` is in decimal format (0.02140 = 2.14%), and `tvl` is in USD. - [Get Product Details](https://web3.okx.com/onchainos/dev-docs/wallet/defi-product-detail.md) # Get Product Details When the user has selected a specific investment product (i.e., `investmentId` has been obtained), use this endpoint to retrieve the full product information, including APY breakdown, underlying assets, and whether subscribe/redeem/claim operations are supported. This information is used to display product details to the user and to determine which subsequent operations are available. **URL**: GET `/api/v6/defi/product/detail` ## Request Parameters | Field | Type | Required | Explanation | | --- | --- | --- | --- | | investmentId | String | Yes | Investment product ID | ## Response Parameters | Field | Type | Explanation | | --- | --- | --- | | investmentId | String | Investment product ID | | investmentName | String | Investment product name | | platformName | String | Protocol name | | platformLogo | String | Protocol logo | | investType | Integer | Investment type | | chainIndex | String | Chain ID string | | network | String | Network name | | rate | String | Yield rate | | tvl | String | TVL | | feeRate | String | Fee rate | | isSupportClaim | Boolean | Whether claim is supported | | isInvestable | Boolean | Whether investable | | isSupportRedeem | Boolean | Whether redemption is supported | | analysisPlatformId | String | Protocol ID | | subscriptionMethod | Integer | Subscription method | | redeemMethod | Integer | Redemption method | | underlyingToken | Array | Underlying asset tokens | | > tokenSymbol | String | Token symbol | | > tokenAddress | String | Contract address | | > chainIndex | String | Chain ID | | > tokenPrecision | Integer | Precision | | > tokenLogo | String | Logo | | aboutToken | Array | Related tokens | | > tokenSymbol | String | Token symbol | | > tokenAddress | String | Contract address | | > chainIndex | String | Chain ID | | > tokenPrecision | Integer | Precision | | > tokenLogo | String | Logo | | > marketCap | String | Market cap | | > price | String | Price | | rateDetails | Array | Yield rate details | | qaList | Array | Q&A list | ## Response Example **Aave V3 USDC (Ethereum, investmentId=9502)** ```json { "code": 0, "msg": "", "data": { "investmentId": 9502, "investmentName": "USDC", "platformName": "Aave V3", "platformLogo": "https://static.coinall.ltd/cdn/web3/protocol/logo/aave-v3.png/type=png_350_0?v=1774409445039", "investType": 1, "tvl": "3423591587.48413", "rate": "0.02140", "rateType": 0, "rateTypeDesc": "APY", "network": "Ethereum", "networkLogo": "https://static.coinall.ltd/cdn/wallet/logo/ETH-20220328.png", "underlyingToken": [ { "tokenSymbol": "USDC", "tokenLogo": "https://static.coinall.ltd/cdn/wallet/logo/USDC.png", "tokenAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "isBaseToken": false } ], "rateDetails": [ { "tokenAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "tokenSymbol": "USDC", "rate": "0.0214", "title": "Supply APY", "type": 1 } ], "aboutToken": [ { "tokenSymbol": "USDC", "tokenLogo": "https://static.coinall.ltd/cdn/wallet/logo/USDC.png", "tokenAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "isBaseToken": false, "marketCap": "55468602892.82830569743700036", "price": "0.99988" } ], "isSupportClaim": false, "isInvestable": true, "isSupportRedeem": true, "analysisPlatformId": "10", "chainIndex": "1", "detailPath": "aave-v3-ethereum-usdc-9502", "platformUrl": "https://app.aave.com", "utilizationRate": "0.755200", "hasRateChart": true, "hasTvlChart": false } } ``` - [Historical APY Line Chart](https://web3.okx.com/onchainos/dev-docs/wallet/defi-product-rate-chart.md) # Historical APY Line Chart When a user wants to view the historical yield trend of an investment product, use this endpoint. Pass in the product ID and time range (WEEK / MONTH / SEASON / YEAR), and it returns APY data at each time point, which can be used to plot a line chart showing the yield trend. **URL**: GET `/api/v6/defi/product/rate/chart` ## Request Parameters | Field | Type | Required | Default | Explanation | | --- | --- | --- | --- | --- | | investmentId | String | Yes | — | Investment Product ID | | timeRange | String | No | WEEK | Time range: WEEK (one week), MONTH (one month), SEASON (three months), YEAR (one year) | ## Request Examples ### Example 1: Query APY Line Chart for Past Week (Default) ``` GET /api/v6/defi/product/rate/chart?investmentId=124 ``` ### Example 2: Query APY Line Chart for Past Three Months ``` GET /api/v6/defi/product/rate/chart?investmentId=124&timeRange=SEASON ``` ## Response Parameters | Field | Type | Explanation | | --- | --- | --- | | timestamp | String | Statistical timestamp (milliseconds) | | rate | String | Investment product yield (including base interest rate + mining coin reward) | | bonusRate | String | Additional bonus yield (OKX Bonus/Merkl, etc.) | | limitValue | Integer | Limit value marking: 1=highest point, -1=lowest point, null=normal point | | totalReward | String | Total fee + bonus reward during the statistical period | ## Response Example ```json { "code": 0, "msg": "", "data": [ { "timestamp": 1741737600000, "rate": "0.0312", "bonusRate": "0.0045", "limitValue": 1, "totalReward": "0.0357" }, { "timestamp": 1741651200000, "rate": "0.0298", "bonusRate": "0.0045", "limitValue": null, "totalReward": "0.0343" } ] } ``` - [Historical TVL Line Chart](https://web3.okx.com/onchainos/dev-docs/wallet/defi-product-tvl-chart.md) # Historical TVL Line Chart Use this endpoint when a user wants to view the historical TVL (Total Value Locked) trend of an investment product. Pass the investment product ID and time range, and it returns TVL data at each time point, which can be used to assess the product's scale changes and market popularity. **URL**: GET `/api/v6/defi/product/tvl/chart` ## Request Parameters | Field | Type | Required | Default | Explanation | | --- | --- | --- | --- | --- | | investmentId | String | Yes | — | Investment product ID (Query parameter) | | timeRange | String | No | WEEK | Time range enum: WEEK (one week), MONTH (one month), SEASON (three months), YEAR (one year) | ## Request Examples ### Example 1: Query the past week's TVL line chart (default) ``` GET /api/v6/defi/product/tvl/chart?investmentId=124 ``` ### Example 2: Query the past year's TVL line chart ``` GET /api/v6/defi/product/tvl/chart?timeRange=YEAR&investmentId=124 ``` ## Response Parameters | Field | Type | Explanation | | --- | --- | --- | | chartVos | Array | TVL line chart data list | | > timestamp | String | Statistics timestamp (milliseconds) | | > tvl | String | TVL value (USD) | | > limitValue | Integer | Extreme value marker: 1=highest point, -1=lowest point, null=regular point | | text | String | Line chart description text (may be empty) | ## Response Example ```json { "code": 0, "msg": "", "data": { "chartVos": [ { "timestamp": 1741737600000, "tvl": "523847291.45", "limitValue": 1 }, { "timestamp": 1741651200000, "tvl": "498312044.78", "limitValue": null }, { "timestamp": 1741564800000, "tvl": "480125367.22", "limitValue": -1 } ], "text": null } } ``` - [V3 Depth Price History Chart](https://web3.okx.com/onchainos/dev-docs/wallet/defi-product-depth-price-chart.md) # V3 Depth Price History Chart Use this endpoint when you want to view the liquidity depth distribution or historical price trends of a V3 Pool. Pass in the investment product ID, chart type (depth chart or price history chart), and time range. Returns the corresponding depth/price data list for rendering liquidity distribution charts or price candlestick charts. **Only applicable to V3 Pool type investment products**. **URL**: GET `/api/v6/defi/product/depth-price/chart` ## Request Parameters | Field | Type | Required | Default | Explanation | | --- | --- | --- | --- | --- | | investmentId | String | Yes | — | Investment product ID (integer string) | | chartType | String | No | DEPTH | Chart type: `DEPTH`=depth chart, `PRICE`=price history chart | | timeRange | String | No | DAY | Only used when chartType=`PRICE`. Time range: `DAY`=24h, `WEEK`=1W | ## Request Examples ### Example 1: Query Depth Chart (default, last 24h) ``` GET /api/v6/defi/product/depth-price/chart?investmentId=1589649169 ``` ### Example 2: Query Price History Chart (last 1 week) ``` GET /api/v6/defi/product/depth-price/chart?investmentId=1589649169&chartType=PRICE&timeRange=WEEK ``` ## Response Parameters Returns an `Array`, each element has the following structure: | Field | Type | Explanation | | --- | --- | --- | | tick | Integer | Tick index (has value in depth chart, empty in price history chart) | | liquidity | String | Liquidity at this tick (has value in depth chart) | | liquidityNet | String | Net liquidity at this tick (has value in depth chart) | | token0Price | String | Depth chart: token0 price at this tick; Price history chart: historical token0 price at this timestamp | | token1Price | String | Depth chart: token1 price at this tick; Price history chart: historical token1 price at this timestamp | | timestamp | Long | Timestamp in milliseconds (only has value in price history chart) | ## Response Examples ### Depth Chart (chartType=DEPTH) ```json { "code": 0, "msg": "", "data": [ { "tick": -32932, "liquidity": "1234567890123456", "liquidityNet": "500000000000000", "token0Price": "0.9985", "token1Price": "1.0015" }, { "tick": -32931, "liquidity": "1234567890123456", "liquidityNet": "0", "token0Price": "0.9986", "token1Price": "1.0014" } ] } ``` ### Price History Chart (chartType=PRICE) ```json { "code": 0, "msg": "", "data": [ { "token0Price": "0.9985", "token1Price": "1.0015", "timestamp": 1741737600000 }, { "token0Price": "0.9990", "token1Price": "1.0010", "timestamp": 1741651200000 } ] } ``` ### Error Example: Non-V3 Pool Investment Product ```json { "code": 84032, "msg": "This api is only supported for V3 DEX Pool products", "data": null } ``` - [Trade Execution](https://web3.okx.com/onchainos/dev-docs/wallet/defi-transaction-introduction.md) # Trade Execution The Trade Execution API provides subscribe (deposit/borrow), redeem (withdraw/repay), and claim DeFi rewards capabilities. It supports DeFi investment product operations across multiple chains including EVM (Ethereum, BSC, Avalanche, etc.), Solana, Sui, Aptos, and more. - **Subscribe/Deposit/Borrow**: Deposit assets into DeFi protocols to earn yield, or borrow assets. - **Redeem/Withdraw/Repay**: Redeem assets from DeFi protocols, or repay loans. - **Claim Rewards**: Claim various rewards generated by your investments (protocol rewards, investment yields, bonus incentives, etc.) with a single call. - [API Reference](https://web3.okx.com/onchainos/dev-docs/wallet/defi-transaction-api-reference.md) # API Reference - [Prepare Transaction Parameters](https://web3.okx.com/onchainos/dev-docs/wallet/defi-product-prepare.md) # Prepare Transaction Parameters This is a required preparatory step before initiating a subscription transaction. Call this endpoint to obtain the "available input token list", "receipt token", "yield tokens", and other information. These are required inputs when subsequently calling `/transaction/enter` or `/transaction/exit` to construct calldata. **URL**: POST `/api/v6/defi/product/detail/prepare` ## Request Parameters | Field | Type | Required | Explanation | | --- | --- | --- | --- | | investmentId | String | Yes | Investment product ID | ## Request Example ### Example 1: Subscription Initialization ```json { "investmentId": 12345 } ``` ## Response Parameters | Field | Type | Explanation | | --- | --- | --- | | investWithTokenList | Array | Available input token list, used for the subscription enter endpoint | | > tokenId | String | NFT TokenId | | > tokenSymbol | String | Token symbol | | > tokenName | String | Token name | | > tokenAddress | String | Contract address | | > tokenPrecision | String | Precision | | > chainIndex | String | Chain ID | | > network | String | Network | | > coinAmount | String | Token amount | | > currencyAmount | String | USD value | | receiveTokenInfo | Object | Received receipt token | | > tokenId | String | NFT TokenId | | > tokenSymbol | String | Token symbol | | > tokenName | String | Token name | | > tokenAddress | String | Contract address | | > tokenPrecision | String | Precision | | > chainIndex | String | Chain ID | | > network | String | Network | | > coinAmount | String | Token amount | | > currencyAmount | String | USD value | | gainsTokenList | Array | Yield token list | | > tokenId | String | NFT TokenId | | > tokenSymbol | String | Token symbol | | > tokenName | String | Token name | | > tokenAddress | String | Contract address | | > tokenPrecision | String | Precision | | > chainIndex | String | Chain ID | | > network | String | Network | | > coinAmount | String | Token amount | | > currencyAmount | String | USD value | | isAllowSubscribe | Boolean | Whether subscription is allowed (has value when type=1) | | feeRate | String | Fee rate (dex_pool exclusive) | | currentTick | String | Current tick (corresponding to current price exchange rate) (dex_pool exclusive) | | currentPrice | String | token0 current price exchange rate (dex_pool exclusive) | | lowerPrice | String | Lower price bound when entering the initial page for adding positions (dex_pool exclusive) | | upperPrice | String | Upper price bound when entering the initial page for adding positions (dex_pool exclusive) | | tickSpacing | String | Tick spacing (dex_pool exclusive) | | underlyingTokenList | Array | Underlying asset list, index0=token0, index1=token1 (dex_pool exclusive) | | > tokenId | String | NFT Token ID (tokenId of the V3 position NFT) | | > tokenSymbol | String | Token symbol, e.g. USDC, ETH | | > tokenName | String | Token full name | | > tokenLogo | String | Token logo image URL | | > tokenAddress | String | Token contract address | | > network | String | Network identifier, e.g. eth, bsc | | > chainIndex | String | Chain ID, e.g. 1 (ETH), 56 (BSC) | | > tokenPrecision | String | Token precision (i.e. decimals), e.g. 18, 6 | | > isBaseToken | Boolean | Whether it is the chain's native token (e.g. ETH, BNB) | ## Response Example **Single Earn: Aave V3 USDC (Ethereum, investmentId=9502)** ```json { "code": 0, "msg": "", "data": { "investWithTokenList": [ { "tokenSymbol": "USDC", "tokenName": "USD Coin", "tokenLogo": "https://static.coinall.ltd/cdn/wallet/logo/USDC.png", "tokenAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "network": "ETH", "chainIndex": "1", "tokenPrecision": "6", "isBaseToken": false, "coinAmount": "0", "currencyAmount": "0", "browserUrl": "https://web3.okx.com/explorer/eth/token/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" } ], "receiveTokenInfo": { "tokenSymbol": "aEthUSDC", "tokenName": "Aave Ethereum USDC", "tokenLogo": "https://static.coinall.ltd/cdn/web3/currency/token/1-0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c-97.png/type=png_350_0", "tokenAddress": "0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c", "network": "ETH", "chainIndex": "1", "tokenPrecision": "6", "coinAmount": "0" }, "gainsTokenList": [ { "tokenSymbol": "USDC", "tokenName": "USD Coin", "tokenLogo": "https://static.coinall.ltd/cdn/wallet/logo/USDC.png", "tokenAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "network": "ETH", "tokenPrecision": "6", "coinAmount": "0", "dataType": "0" } ] } } ``` - [Subscription](https://web3.okx.com/onchainos/dev-docs/wallet/defi-transaction-enter.md) # Subscription Call this endpoint when a user wants to deposit assets into a DeFi protocol or borrow assets. Key parameters: `investmentId` (investment product ID), `address` (user wallet address), `userInputList` (input token address, chain ID, and amount). The returned `dataList` contains transaction steps to be executed in order (e.g., APPROVE followed by DEPOSIT), each of which must be signed and broadcast on-chain sequentially. For V3 Pool operations, additional parameters such as `tickLower` and `tickUpper` are required. **URL**: POST `/api/v6/defi/transaction/enter` ## Request Parameters > Enter and exit share the same request model, and some fields are only valid under specific operations. | Field | Type | Required | Default | Explanation | | --- | --- | --- | --- | --- | | investmentId | String | Yes | — | Investment product ID | | address | String | Yes | — | User wallet address | | tickLower | String | No | — | V3 tick lower bound. Only required when creating a new position for Dex Pool type investments | | tickUpper | String | No | — | V3 tick upper bound. Only required when creating a new position for Dex Pool type investments | | tokenId | String | No | — | V3 Pool NFT position token ID. When isV3Pool=true: required for adding liquidity (appending to an existing position); required for redemption | | userInputList | Array | No | — | Input tokens and amounts. For subscription, this is the token or token list information to invest | | > tokenAddress | String | No | — | Required when `userInputList` is provided; Token contract address | | > chainIndex | String | No | — | Required when `userInputList` is provided; Chain ID | | > coinAmount | String | No | — | Required when `userInputList` is provided; Amount (human-readable, e.g., "0.2") | | > tokenSymbol | String | No | — | Token symbol | | > tokenPrecision | Integer | No | — | Precision | | slippage | String | No | "0.01" | Transaction slippage (effective for adapter/Zap routing). "0.01"=1%, "0.1"=10% | ## Request Examples ### Example 1: BSC V3 Pool subscription Investment product: PancakeSwapV3 USDT-RIVER (id=1589649169, chainIndex=56) ```json { "investmentId": "1589649169", "address": "0x1ae68a40b9f903a469aed01574f3a9ab6d45c563", "tickLower": "-32150", "tickUpper": "-31350", "userInputList": [ { "tokenAddress": "0x55d398326f99059fF775485246999027B3197955", "chainIndex": "56", "coinAmount": "0.2" } ], "slippage": "0.1" } ``` ### Example 2: Avalanche Aave V3 deposit (Single Earn) Investment product: Aave V3 USDC (id=124, chainIndex=43114) ```json { "investmentId": "124", "address": "0x1ae68a40b9f903a469aed01574f3a9ab6d45c563", "userInputList": [ { "tokenAddress": "0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e", "chainIndex": "43114", "coinAmount": "0.05" } ] } ``` ### Example 3: Avalanche Aave V3 borrow Investment product: Aave V3 USDC Borrow (id=33901, chainIndex=43114) ```json { "investmentId": "33901", "address": "0x1ae68a40b9f903a469aed01574f3a9ab6d45c563", "userInputList": [ { "tokenAddress": "0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e", "chainIndex": "43114", "coinAmount": "0.01" } ] } ``` ### Example 4: Sui NAVI borrow Investment product: NAVI SUI Borrow (id=40047, chainIndex=784) ```json { "investmentId": "40047", "address": "0x2791c11545a2fef7d8b3188002c80343bf6dc64130a603914238d8660b3bddde", "userInputList": [ { "tokenAddress": "0x2::sui::SUI", "chainIndex": "784", "coinAmount": "0.02" } ] } ``` ### Example 5: Solana Kamino borrow Investment product: Kamino USDC Borrow (id=29130, chainIndex=501) ```json { "investmentId": "29130", "address": "4GK2VMnznuPpg8gG9vqD5MM6889pjJ8WS2HqzktaBfSo", "userInputList": [ { "tokenAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "chainIndex": "501", "coinAmount": "0.05" } ] } ``` ## Response Parameters | Field | Type | Explanation | | --- | --- | --- | | code | String | "0"=success, non-"0"=failure | | msg | String | Error message | | data.dataList | Array | Calldata result list (execute in order, e.g., APPROVE → DEPOSIT) | | > callDataType | String | Operation type (approve, subscribe, redeem, claim), see enum table below | | > from | String | From address (user wallet address) | | > to | String | To address (target contract address). Depending on product type and operation, this may be a Zap contract or a direct protocol contract | | > value | String | Transfer amount (native token quantity). Empty string or "0x0" when no native token transfer is needed | | > serializedData | String | Serialized transaction data. EVM: hex calldata (0x prefix); Solana: base58 encoded; Sui: base64 encoded BCS bytes | | > originalData | String | Auxiliary metadata (JSON string). EVM chains include function ABI (methodId/methodDefine/methodParams); Aptos chains include module ABI JSON | | > transactionPayload | String | Transaction template, only returned for Aptos chains. Contains payload JSON; the client needs to supplement the sequence\_number and build the complete transaction via SDK | | > signatureData | String | Signature data. EVM chains: Zap contract permit signature; non-EVM chains: server-side signature credential | | > gas | String | Gas limit, only returned for non-EVM chains such as Aptos. EVM chains require client-side estimation or a fixed value | ### callDataType Enum Values | Value | Explanation | | --- | --- | | APPROVE | ERC20 authorization (approve spender) | | DEPOSIT | Deposit into protocol | | SWAP,DEPOSIT | Swap then deposit (V3 Pool scenario, single token into dual-token pool) | | WITHDRAW | Withdraw from protocol | | WITHDRAW,SWAP | Withdraw then swap back to target token (V3 Pool scenario) | > **Note**: Aave Borrow returns callDataType=WITHDRAW, and Aave Repay returns callDataType=DEPOSIT. This follows Aave's internal method semantics (borrow=withdraw assets from the pool, repay=deposit assets into the pool) and does not affect actual business operations. ### serializedData Processing by Chain | Chain | Encoding | Client Processing Flow | | --- | --- | --- | | EVM (BSC/AVAX/ETH) | Hex (0x prefix) | Use directly as tx.data, with to as the target address | | Sui | Base64 BCS | base64 decode → prepend intent [0,0,0] → blake2b-256 hash → Ed25519 sign → submit sui\_executeTransactionBlock | | Solana | Base58 | bs58 decode → skip first 65 bytes (signature placeholder) → VersionedMessage.deserialize() → sign → send immediately (blockhash expires in ~60s) | | Aptos | — | Use the payload JSON from the transactionPayload field, build transaction via SDK build.simple() → sign → submit | ## Response Examples **EVM chain (BSC V3 Enter, APPROVE + SWAP,DEPOSIT two steps)**: ```json { "code": 0, "msg": "", "data": { "dataList": [ { "callDataType": "APPROVE", "from": "0x1ae68a40b9f903a469aed01574f3a9ab6d45c563", "to": "0xda7ad9dea9397cffddae2f8a052b82f1484252b3", "value": "0x0", "serializedData": "0x095ea7b3000000000000000000000000...ffffffff", "originalData": "{\"callDataType\":\"APPROVE\",\"methodId\":\"0x095ea7b3\",\"methodDefine\":\"approve(address,uint256)\",...}", "signatureData": "..." }, { "callDataType": "SWAP,DEPOSIT", "from": "0x1ae68a40b9f903a469aed01574f3a9ab6d45c563", "to": "0x7251FEbEABB01eC9dE53ECe7a96f1C951F886Dd2", "value": "0x0", "serializedData": "0xec5b999d000000000000000000000000...", "originalData": "{\"callDataType\":\"SWAP,DEPOSIT\",\"methodDefine\":\"{...executeWithPermit...}\",...}", "signatureData": "..." } ] } } ``` **Sui chain (NAVI Deposit, single step)**: ```json { "code": 0, "msg": "", "data": { "dataList": [ { "serializedData": "", "from": "0x2791c11545a2fef7d8b3188002c80343bf6dc64130a603914238d8660b3bddde", "to": "...", "value": "0" } ] } } ``` **Solana chain (Kamino Deposit, single step)**: ```json { "code": 0, "msg": "", "data": { "dataList": [ { "serializedData": "", "from": "4GK2VMnznuPpg8gG9vqD5MM6889pjJ8WS2HqzktaBfSo", "to": "...", "value": "0" } ] } } ``` ## V3 Pool Dual-Token Position Ratio Calculator Note: This endpoint only needs to be called when investing in V3 Pool related products. Before subscribing to a V3 Pool, call this endpoint to calculate the required dual-token input ratio — the user only needs to provide a single token amount, and the endpoint intelligently computes how much of each token is needed based on the current pool price and selected price range. The returned `investWithTokenList` can be passed directly as `userInputList` to the subscription endpoint above. **URL**: POST `/api/v6/defi/calculator/enter/info` ### Request Parameters | Field | Type | Required | Explanation | | --- | --- | --- | --- | | inputAmount | String | Yes | Single-token amount entered by the user (human-readable format, e.g. "0.05") | | inputTokenAddress | String | Yes | Contract address of the token entered by the user. Can be token0 or token1 of the V3 Pool | | tokenDecimal | String | Yes | Decimals of the input token (e.g. "18", "6") | | investmentId | String | Yes | Investment product ID (investmentId corresponding to the V3 Pool) | | address | String | Yes | User wallet address | | tickLower | String | Yes | Lower tick bound of the V3 position (e.g. "-33500") | | tickUpper | String | Yes | Upper tick bound of the V3 position (e.g. "-30450") | ### Request Example **Example: BSC V3 Pool (USDT → Dual-Token Allocation)** Investment product: PancakeSwapV3 USDT-RIVER (id=1589649169, chainIndex=56) ```json { "inputAmount": "0.05", "inputTokenAddress": "0x55d398326f99059fF775485246999027B3197955", "tokenDecimal": "18", "investmentId": 1589649169, "address": "0x1ae68a40b9f903a469aed01574f3a9ab6d45c563", "tickLower": "-33500", "tickUpper": "-30450" } ``` ### Response Parameters **data Object** | Field | Type | Explanation | | --- | --- | --- | | investWithTokenList | Array | Dual-token allocation result list, typically containing 2 elements (token0 and token1) | | > tokenAddress | String | Token contract address (lowercase format) | | > chainIndex | String | Chain ID (e.g. "56" = BSC) | | > coinAmount | String | Allocated amount (human-readable format, e.g. "0.05"). High-precision decimal, can be used directly as userInputList in transaction/enter | ### Response Example **Success: USDT Input → USDT + RIVER Dual-Token Allocation** ```json { "code": 0, "data": { "investWithTokenList": [ { "tokenAddress": "0x55d398326f99059ff775485246999027b3197955", "chainIndex": "56", "coinAmount": "0.05" }, { "tokenAddress": "0xda7ad9dea9397cffddae2f8a052b82f1484252b3", "chainIndex": "56", "coinAmount": "0.000275606738038671" } ] } } ``` Explanation: The user invests 0.05 USDT. Based on the current tick ≈ -32932 price ratio, 0.05 USDT + 0.000275 RIVER are needed to form the dual-token entry. ### Complete Invocation Flow 1. **POST `/api/v6/defi/calculator/enter/info`** (current endpoint) — Input: single-token amount + tick range → Output: investWithTokenList 2. **Verify wallet balance** — Ensure both token balances meet the coinAmount specified in investWithTokenList 3. **POST `/api/v6/defi/transaction/enter`** — Pass in userInputList (= investWithTokenList) + tickLower + tickUpper + slippage → Output: calldata (DEPOSIT) 4. **Sign & send on-chain transaction** — Dual-token entry is a pure DEPOSIT (no on-chain swap) - [Redemption](https://web3.okx.com/onchainos/dev-docs/wallet/defi-transaction-exit.md) # Redemption Call this endpoint when a user wants to withdraw assets from a DeFi protocol or repay a loan. Key parameters: `investmentId`, `address`. **Critical note**: always pass `redeemPercent` when redeeming (e.g., "1" for 100%) — otherwise, for tokens with dynamic balances such as aTokens, the on-chain execution may revert due to balance changes between API response and transaction confirmation. For V3 Pool redemptions, `tokenId` is required. **URL**: POST `/api/v6/defi/transaction/exit` ## Request Parameters | Field | Type | Required | Default | Explanation | | --- | --- | --- | --- | --- | | investmentId | String | Yes | — | Investment product ID | | address | String | Yes | — | User wallet address | | tokenId | String | No | — | V3 Pool NFT position token ID. Required for redemption when isV3Pool=true | | redeemPercent | String | Recommended | — | Redemption ratio, e.g., "1"=100%, "0.5"=50%. When not provided, the Zap calldata's tokenIn amount uses the exact value from userInputList.coinAmount; when provided, MAX\_UINT256 is used to represent the full balance | | userInputList | Array | No | — | For Farm and V2 Pool, input LP Token information; for other cases, input the target receiving token information | | > tokenAddress | String | No | — | Required when `userInputList` is provided; Token contract address | | > chainIndex | String | No | — | Required when `userInputList` is provided; Chain ID | | > coinAmount | String | No | — | Required when `userInputList` is provided; Amount (human-readable, e.g., "0.05") | | > tokenSymbol | String | No | — | Token symbol | | > tokenPrecision | Integer | No | — | Precision | | > tokenId | String | No | — | NFT token ID (V3 Pool scenario) | | slippage | String | No | "0.01" | Transaction slippage (effective for adapter/Zap routing). "0.01"=1%, "0.1"=10% | ## Key Notes > **redeemPercent is required**: When type="REDEEM", if `redeemPercent` is not provided, the Zap calldata generated by the API will use an exact value for `tokenIn.amount` (e.g., 60009) instead of MAX\_UINT256. For tokens like aToken whose interest grows dynamically, the balance may change between the API response and on-chain execution, causing `SafeERC20: low-level call failed`. When `redeemPercent: "1"` is provided, the amount is set to MAX\_UINT256, and the contract dynamically retrieves the actual balance. ## Request Examples ### Example 1: BSC V3 Pool pure redemption (50%, without userInputList) Investment product: PancakeSwapV3 USDT-RIVER (id=1589649169) ```json { "investmentId": "1589649169", "address": "0x1ae68a40b9f903a469aed01574f3a9ab6d45c563", "tokenId": "6632738", "redeemPercent": "0.5" } ``` ### Example 2: Avalanche Aave V3 redemption (redeemPercent="1") Investment product: Aave V3 USDC (id=124, chainIndex=43114) ```json { "investmentId": "124", "address": "0x1ae68a40b9f903a469aed01574f3a9ab6d45c563", "userInputList": [ { "tokenAddress": "0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e", "chainIndex": "43114", "coinAmount": "0.05" } ], "redeemPercent": "1" } ``` ### Example 3: Sui NAVI redemption Investment product: NAVI USDC (id=32202, chainIndex=784) ```json { "investmentId": "32202", "address": "0x2791c11545a2fef7d8b3188002c80343bf6dc64130a603914238d8660b3bddde", "userInputList": [ { "tokenAddress": "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC", "chainIndex": "784", "coinAmount": "0.3" } ] } ``` ### Example 4: Solana Kamino repayment Investment product: Kamino USDC Borrow (id=29130, chainIndex=501) ```json { "investmentId": "29130", "address": "4GK2VMnznuPpg8gG9vqD5MM6889pjJ8WS2HqzktaBfSo", "userInputList": [ { "tokenAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "chainIndex": "501", "coinAmount": "0.05" } ] } ``` ## Response Parameters | Field | Type | Explanation | | --- | --- | --- | | data.dataList | Array | Calldata result list (execute in order) | | > callDataType | String | Operation type (approve, subscribe, redeem, claim) | | > from | String | From address (user wallet address) | | > to | String | To address (target contract address) | | > value | String | Transfer amount (native token quantity). Empty string or "0x0" when no native token transfer is needed | | > serializedData | String | Serialized transaction data. EVM: hex calldata (0x prefix); Solana: base58 encoded; Sui: base64 encoded BCS bytes | | > originalData | String | Auxiliary metadata (JSON string) | | > transactionPayload | String | Transaction template, only returned for Aptos chains | | > signatureData | String | Signature data | | > gas | String | Gas limit, only returned for non-EVM chains such as Aptos | Common dataList combinations during redemption: - Single step: `[WITHDRAW]` — pure redemption/repayment - Two steps: `[APPROVE, WITHDRAW]` — requires prior aToken authorization to Zap - Two steps: `[WITHDRAW, SWAP]` — V3 withdraw then swap back to target token (actually combined into a single callDataType=WITHDRAW,SWAP) ## Response Example **EVM chain (Avalanche Aave V3 USDC redemption, APPROVE + WITHDRAW two steps)** ```json { "code": 0, "msg": "", "data": { "dataList": [ { "callDataType": "APPROVE", "from": "0x1ae68a40b9f903a469aed01574f3a9ab6d45c563", "to": "0x625e7708f30ca75bfd92586e17077590c60eb4cd", "value": "0x0", "serializedData": "0x095ea7b3000000000000000000000000...ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "originalData": "{\"callDataType\":\"APPROVE\",\"methodId\":\"0x095ea7b3\",\"methodDefine\":\"approve(address,uint256)\",...}", "signatureData": "" }, { "callDataType": "WITHDRAW", "from": "0x1ae68a40b9f903a469aed01574f3a9ab6d45c563", "to": "0x794a61358d6845594f94dc1db02a252b5b4814ad", "value": "0x0", "serializedData": "0x69328dec000000000000000000000000...0000000000000000000000001ae68a40b9f903a469aed01574f3a9ab6d45c563", "originalData": "{\"callDataType\":\"WITHDRAW\",\"methodId\":\"0x69328dec\",\"methodDefine\":\"withdraw(address,uint256,address)\",...}", "signatureData": "" } ] } } ``` > **Note**: When `redeemPercent="1"`, the amount parameter in `serializedData` is MAX_UINT256, and the contract dynamically retrieves the actual balance for redemption, avoiding insufficient balance issues caused by aToken interest growth. - [Claim DeFi Protocol Rewards](https://web3.okx.com/onchainos/dev-docs/wallet/defi-transaction-claim.md) # Claim DeFi Protocol Rewards Call this endpoint when a user wants to claim rewards generated from DeFi investments. Key parameters: `address` (wallet address), `rewardType` (reward type). Common `rewardType` values include: `REWARD_INVESTMENT` (investment product mining rewards, most common), `REWARD_PLATFORM` (protocol rewards, requires `analysisPlatformId`), `V3_FEE` (V3 fees, requires `tokenId`), `REWARD_OKX_BONUS` (OKX Bonus), `REWARD_MERKLE_BONUS` (Merkle Bonus, requires `expectOutputList`), `UNLOCKED_PRINCIPAL` (matured principal, requires `principalIndex`). **URL**: POST `/api/v6/defi/transaction/claim` ## Request Parameters | Field | Type | Required | Explanation | | --- | --- | --- | --- | | address | String | Yes | User wallet address | | rewardType | String | Yes | Reward type (see below) | | investmentId | String | No | Investment product ID (required for all reward types except protocol rewards) | | analysisPlatformId | String | No | Protocol ID (required when claiming protocol rewards) | | expectOutputList | Array | No | Expected output token list | | > chainIndex | String | No | Required when `rewardType=REWARD_MERKLE_BONUS` and `expectOutputList` is provided; Chain ID | | > tokenAddress | String | No | Required when `rewardType=REWARD_MERKLE_BONUS` and `expectOutputList` is provided; Token contract address | | > coinAmount | String | No | Required when `rewardType=REWARD_MERKLE_BONUS` and `expectOutputList` is provided; Amount (human-readable, e.g., "0.001") | | tokenId | String | No | Position tokenId required when claiming V3 fees | | principalIndex | String | No | Matured order index required when claiming matured principal | **Supported rewardType values:** | Value | Explanation | | --- | --- | | REWARD\_INVESTMENT | Investment product mining rewards (most common) | | REWARD\_PLATFORM | Protocol rewards (requires `analysisPlatformId`) | | V3\_FEE | V3 fees (requires `tokenId`) | | REWARD\_OKX\_BONUS | OKX Bonus | | REWARD\_MERKLE\_BONUS | Merkle Bonus (requires `expectOutputList`) | | UNLOCKED\_PRINCIPAL | Matured principal (requires `principalIndex`) | ## Request Examples ### Example 1: Claim protocol rewards ```json { "rewardType": "REWARD_PLATFORM", "analysisPlatformId": "144", "address": "0x46e3420d02d628d3781fa16149e741bcb97da055", "expectOutputList": [ { "chainIndex": "1", "tokenAddress": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "coinAmount": "0.001" } ] } ``` ### Example 2: Claim investment product mining rewards ```json { "rewardType": "REWARD_INVESTMENT", "investmentId": "27100", "address": "0x46e3420d02d628d3781fa16149e741bcb97da055" } ``` ### Example 3: Claim V3 fees ```json { "rewardType": "V3_FEE", "investmentId": "42101", "address": "0x46e3420d02d628d3781fa16149e741bcb97da055", "tokenId": "64219" } ``` ### Example 4: Claim OKX Bonus ```json { "rewardType": "REWARD_OKX_BONUS", "investmentId": "42101", "address": "0x46e3420d02d628d3781fa16149e741bcb97da055" } ``` ### Example 5: Claim Merkle Bonus ```json { "rewardType": "REWARD_MERKLE_BONUS", "investmentId": "43304", "address": "0x46e3420d02d628d3781fa16149e741bcb97da055", "expectOutputList": [ { "chainIndex": "747474", "coinAmount": "10", "tokenAddress": "0x2dca96907fde857dd3d816880a0df407eeb2d2f2" } ] } ``` ### Example 6: Claim matured principal For example, LSD: Lido requires a lock-up period after redemption. Once the lock-up period expires, claim the principal: ```json { "rewardType": "UNLOCKED_PRINCIPAL", "investmentId": "10002", "address": "0x46e3420d02d628d3781fa16149e741bcb97da055", "principalIndex": "107580" } ``` ## Response Parameters | Field | Type | Explanation | | --- | --- | --- | | dataList | Array | Calldata result list | | > callDataType | String | Operation type (approve, subscribe, redeem, claim) | | > from | String | From address (user wallet address) | | > to | String | To address (target contract address) | | > value | String | Transfer amount (native token quantity). Empty string or "0x0" when no native token transfer is needed | | > serializedData | String | Serialized transaction data. EVM: hex calldata (0x prefix); Solana: base58 encoded; Sui: base64 encoded BCS bytes | | > originalData | String | Auxiliary metadata (JSON string). EVM chains include function ABI; Aptos chains include module ABI JSON | | > transactionPayload | String | Transaction template, only returned for Aptos chains | | > signatureData | String | Signature data. EVM chains: Zap contract permit signature; non-EVM chains: server-side signature credential | | > gas | String | Gas limit, only returned for non-EVM chains such as Aptos | ## Response Example **Claim investment product mining rewards (REWARD_INVESTMENT)** ```json { "code": 0, "msg": "", "data": { "dataList": [ { "callDataType": "CLAIM", "from": "0x46e3420d02d628d3781fa16149e741bcb97da055", "to": "0x197e90f9fad81970ba7976f33cbd77088e5d7cf7", "value": "0x0", "serializedData": "0x3111e7b3000000000000000000000000...", "originalData": "{\"callDataType\":\"CLAIM\",\"methodId\":\"0x3111e7b3\",...}", "signatureData": "" } ] } } ``` - [User Holdings](https://web3.okx.com/onchainos/dev-docs/wallet/defi-user-asset-overview.md) # User Holdings Query the user's current positions in DeFi protocols. Supports aggregated queries across multiple wallets, chains, and protocols, returning structured data including asset values and quantities for investment products within each protocol. Suitable for building DeFi portfolio management dashboards and other analytical tools. - **Position Distribution**: Pass the user's wallet addresses (supporting multiple chains and wallets) to retrieve position overview across DeFi protocols. - **Position Details**: Returns summary information including protocol names, total assets, and chain-level distribution. Also supports retrieving claimable rewards lists and lending market supply and borrow information. - [API Reference](https://web3.okx.com/onchainos/dev-docs/wallet/defi-user-asset-api-reference.md) # API Reference - [Holdings Overview](https://web3.okx.com/onchainos/dev-docs/wallet/defi-user-asset-platform-list.md) # Holdings Overview Call this endpoint when a user wants to view their overall holdings across DeFi protocols. Pass the user's wallet address list (one wallet per chain, supports multiple chains simultaneously), and it returns the holdings overview for each DeFi protocol (protocol name, total assets in USD, number of investment products, etc.). After obtaining the `analysisPlatformId`, you can call `/api/v6/defi/user/asset/platform/detail` to view detailed holdings. **URL**: POST `/api/v6/defi/user/asset/platform/list` ## Request Parameters | Field | Type | Required | Explanation | | --- | --- | --- | --- | | walletAddressList | Array | Yes | Wallet address list | | > chainIndex | String | Yes | Chain ID | | > walletAddress | String | Yes | Wallet address | | > pubKey | String | No | Public key (only used for BTC investment products) | | tag | String | No | Custom tag | ## Request Examples ### Example 1: Query a single wallet's protocol holdings on ETH ```json { "walletAddressList": [ { "chainIndex": "1", "walletAddress": "0x7f429edeff8afc7bb3a2cf7db832fc86f6fa99da" } ] } ``` ### Example 2: Query multiple wallets' protocol holdings across multiple chains ```json { "walletAddressList": [ { "chainIndex": "1", "walletAddress": "0x1234567890123456789012345678901234567890" }, { "chainIndex": "56", "walletAddress": "0x1234567890123456789012345678901234567890" }, { "chainIndex": "137", "walletAddress": "0x1234567890123456789012345678901234567890" } ], "tag": "portfolio_check" } ``` ## Response Parameters | Field | Type | Explanation | | --- | --- | --- | | walletIdPlatformList | Array | Protocol list by wallet | | > platformList | Array | Protocol list | | > > platformName | String | Protocol name | | > > analysisPlatformId | String | Protocol ID | | > > platformLogo | String | Protocol Logo | | > > currencyAmount | String | Protocol total assets (USD) | | > > isSupportInvest | Boolean | Whether investment is supported | | > > platformUrl | String | Protocol URL | | > > networkBalanceList | Array | Assets by chain | | > > > network | String | Chain name | | > > > networkLogo | String | Chain logo | | > > > chainIndex | String | Chain chainId | | > > > currencyAmount | String | Protocol total assets on this chain (USD) | | > > > investmentCount | Integer | Number of investment products | | > > investmentCount | Integer | Number of investment products | | > walletId | String | Wallet ID | | > accountId | String | Account ID | | > totalAssets | String | Wallet total assets (USD) | | updateAt | String | Update timestamp (milliseconds) | | assetStatus | int | Asset status: 1=updated, 2=updating | ## Response Example **Base chain single wallet query** ```json { "code": 0, "msg": "", "data": { "walletIdPlatformList": [ { "platformList": [ { "platformName": "Aave V3", "analysisPlatformId": "10", "platformLogo": "https://static.coinall.ltd/cdn/web3/protocol/logo/aave-v3.png/type=png_350_0?v=1774419400100", "currencyAmount": "1.842485290389950657798412062008333407", "isSupportInvest": true, "platformUrl": "https://app.aave.com", "networkBalanceList": [ { "network": "BASE", "networkLogo": "https://static.coinall.ltd/cdn/web3/invest/network/logo/base_new.png", "chainIndex": "8453", "currencyAmount": "1.842485290389950657798412062008333407", "investmentCount": 3 } ], "investmentCount": 3 }, { "platformName": "Morpho", "analysisPlatformId": "119170", "platformLogo": "https://static.coinall.ltd/cdn/web3/protocol/logo/morphoblue-none.png/type=png_350_0?v=1774419195442", "currencyAmount": "1.01000616616", "isSupportInvest": true, "platformUrl": "https://app.morpho.org", "networkBalanceList": [ { "network": "BASE", "networkLogo": "https://static.coinall.ltd/cdn/web3/invest/network/logo/base_new.png", "chainIndex": "8453", "currencyAmount": "1.01000616616", "investmentCount": 1 } ], "investmentCount": 1 }, { "platformName": "Compound V3", "analysisPlatformId": "144", "platformLogo": "https://static.coinall.ltd/cdn/web3/protocol/logo/compound-v3.png/type=png_350_0?v=1774418057245", "currencyAmount": "0.358024146564053025", "isSupportInvest": true, "platformUrl": "https://v3-app.compound.finance", "networkBalanceList": [ { "network": "BASE", "networkLogo": "https://static.coinall.ltd/cdn/web3/invest/network/logo/base_new.png", "chainIndex": "8453", "currencyAmount": "0.358024146564053025", "investmentCount": 3 } ], "investmentCount": 3 } ], "walletId": "a11a9be9-00b9-43de-b450-6e090a58297a", "accountId": "a11a9be9-00b9-43de-b450-6e090a58297a", "totalAssets": "3.216207599599296551158095653123634461" } ], "updateAt": 1774429492000, "assetStatus": 1 } } ``` > The actual response returns 4 protocols; only the first 3 are shown here. `currencyAmount` is denominated in USD, and `assetStatus=1` indicates that data has been fully updated. - [Holdings Detail](https://web3.okx.com/onchainos/dev-docs/wallet/defi-user-asset-platform-detail.md) # Holdings Detail Call this endpoint when a user wants to view detailed holdings in a specific DeFi protocol. Requires wallet address list and target protocol information (`analysisPlatformId` obtained from the previous protocol list endpoint). The response includes detailed asset information for each investment product, V3 position information, claimable rewards, etc. Based on the returned `investmentId` and position information, you can further call the transaction execution API to redeem or claim rewards. **URL**: POST `/api/v6/defi/user/asset/platform/detail` ## Request Parameters | Field | Type | Required | Explanation | | --- | --- | --- | --- | | walletAddressList | Array | Yes | Wallet list | | > chainIndex | String | Yes | Chain ID | | > walletAddress | String | Yes | Wallet address | | > pubKey | String | No | Public key (only used for BTC investment products) | | platformList | Array | Yes | DeFi protocols to query | | > chainIndex | String | No | Chain ID | | > analysisPlatformId | String | No | Protocol ID | ## Request Example ### Example 1: Query by protocol ID ```json { "walletAddressList": [ { "chainIndex": "1", "walletAddress": "0x7f429edeff8afc7bb3a2cf7db832fc86f6fa99da" } ], "platformList": [ { "chainIndex": "1", "analysisPlatformId": "44" } ] } ``` ## Response Parameters | Field | Type | Explanation | | --- | --- | --- | | walletIdPlatformDetailList | Array | Holdings by wallet | | > networkHoldVoList | Array | Holdings by network | | > > network | String | Network name | | > > chainIndex | String | Chain ID | | > > isSupportInvest | Boolean | Whether investment is supported | | > > totalAssert | String | Total assets (USD) | | > > investTokenBalanceVoList | Array | Holdings by investment product | | > > > investmentName | String | Investment product name | | > > > validatorName | String | Validator name | | > > > currentPrice | String | Current price (e.g., 1 DAI - 1.0393 USDC) | | > > > investmentId | String | Investment product ID | | > > > specialPositionAssetKey | String | Special position asset key | | > > > sourceInvestmentId | String | Source investment product ID | | > > > feeRate | String | Fee rate (used by Uni V3, e.g., 0.0003) | | > > > aggregateProductId | String | Aggregate product ID | | > > > isInvestTypeSupport | Boolean | Whether the investment type is supported | | > > > investType | Integer | Investment type (1:save, 2:pool, 3:farm, 4:vaults, 5:stake, 6:borrow, 7:staking, 8:locked, 9:deposit, 10:vesting) | | > > > investName | String | Investment type description | | > > > investLogo | Object | Investment product logo information | | > > > positionList | Array | Position detail list | | > > > > range | String | Price range (e.g., 0.892 - 0.992 USDC per DAI) | | > > > > reverseRange | String | Reverse price range | | > > > > rangeInfo | Object | Price range details | | > > > > tokenId | String | NFT tokenId (e.g., 93828) | | > > > > positionName | String | Position name | | > > > > nftLogo | String | NFT Logo | | > > > > positionStatus | String | Position status (ACTIVE, INACTIVE) | | > > > > assetsTokenList | Array | Asset token list | | > > > > showIncreaseLiquidity | boolean | Whether to show increase liquidity | | > > > > rewardDefiTokenInfo | Array | Compound rewards (same structure as availableRewards element) | | > > > > unclaimFeesDefiTokenInfo | Array | Uni V3 fees (same structure as availableRewards element) | | > > > > totalValue | String | Total value (USD) | | > > > > isNarrow | Boolean | Whether the range is too narrow | | > > > > needInvest | Boolean | Whether investment is needed (true: needs investment, false: already invested) | | > > > > settlementTime | String | Settlement time (second-level timestamp) | | > > > > assetPositionType | String | Position type (0: Uni V3 position, 1: position with expiration) | | > > > > positionExtInfoList | Array | Position extended information list | | > > > assetsTokenList | Array | Asset token list | | > > > borrowTokenList | Array | Borrow token list (LSDFI) | | > > > rewardDefiTokenInfo | Array | Compound rewards (same structure as availableRewards element) | | > > > fundsInfo | Array | Funds information (same structure as availableRewards element) | | > > > extraData | Object | Detail page extended data | | > > > totalValue | String | Total value (USD) | | > > > overflowTotalValue | String | Overflow total value (USD) | | > > > collateralRatioInfo | Object | Collateral ratio information (LSDFI) | | > > > rewardAddress | String | BTC reward receiving address | | > > > maturityTime | String | Pendle maturity time | | > > > fixedApy | String | Pendle fixed APY | | > > > browserUrl | String | OKLink explorer URL | | > > > poolId | String | Pool ID | | > > > poolAddress | String | Pool address | | > > > tagList | Array | Tag list | | > > > investNameTagList | Array | Investment name tag list | | > > > extraFieldList | Array | Extra display field list | | > > > subTitle | String | Subtitle (e.g., ID: 205c8e01aa#12) | | > > > investmentCategory | Integer | Investment category (0: Earn, 1: Brc20, 2: LSDFI) | | > > > investmentClassify | String | Investment classification | | > > > nonPoolPositionList | Array | Non-UniV3 investment product position list | | > > > investmentKey | String | Investment key | | > > > marketId | String | Lending market ID | | > > > perpetual | Object | Perpetual contract information | | > > > detailPath | String | Web detail page redirect path | | > > > yieldYesterday | BigDecimal | Yesterday's yield (USD) | | > > > totalEarnings | BigDecimal | Total earnings (USD) | | > > investMarketTokenBalanceVoList | Array | Holdings by lending market | | > > > assetMap | Object | Asset data mapping (includes supply and borrow, value structure same as investTokenBalanceVoList element) | | > > > marketId | String | Market identifier | | > > > healthRate | Object | Market health rate (non-null when there are borrows) | | > > > marketRewards | Array | Market rewards (same structure as availableRewards element) | | > > > totalValue | String | Total value (USD) | | > > availableRewards | Array | Claimable rewards | | > > > baseDefiTokenInfos | Array | Reward token element list | | > > > buttonType | Integer | Button type (0: hidden, 1: requires authorization, 2: disabled, 3: enabled) | | > > > callDataExtJson | String | CallData extended JSON | | > > > claimMode | Integer | Claim mode (null=normal, 0=stake OKT, 1=redirect to secondary page) | | > > > extraData | Array | Reward detail extended data | | > > > > coinAmount | String | Claimable amount (string precision value) | | > > > > principalIndex | String | Principal batch/index identifier; can be passed in the claim API when rewardType is UNLOCKED_PRINCIPAL | | > > > > claimable | Boolean | Whether claimable (true/false) | | > > > > status | String | Claim status (e.g., CLAIMABLE means claimable) | | > > > rewardType | String | Reward type string (REWARD\_INVESTMENT, REWARD\_PLATFORM, V3\_FEE, REWARD\_OKX\_BONUS, REWARD\_MERKLE\_BONUS, UNLOCKED\_PRINCIPAL) | | > > > unclaimedTokenList | Array | Merkl bonus unclaimed token list (by chain) | | > > > network | String | Network name | | > > > chainIndex | String | Chain ID | | > > > urlInfo | Object | URL redirect information | | > > > currencyAmount | String | Currency amount | | > > fundsInfo | Array | Funds information (same structure as availableRewards element) | | > > airDropRewardInfo | Array | Airdrop rewards (same structure as availableRewards element) | | > > extraData | Object | Extended data | | > walletId | String | Wallet ID | | platformName | String | Protocol name | | analysisPlatformId | String | Analysis group protocol ID | | platformLogo | String | Protocol Logo | | platformUrl | String | Protocol URL | ## Response Example ```json { "code": "0", "msg": "", "data": [ { "walletIdPlatformDetailList": [ { "networkHoldVoList": [ { "network": "Ethereum", "chainIndex": "1", "isSupportInvest": true, "totalAssert": "0.8152800000000020382", "investTokenBalanceVoList": [ { "investmentName": "ETH", "investmentId": 22850, "specialPositionAssetKey": "1-0x308861a430be4cce5502d0a12724771fc6daf216-0x35fa164735182de50811e8e2e824cfb9b6118ac25", "aggregateProductId": 73676, "isInvestTypeSupport": true, "investType": 5, "investName": "Stake", "investLogo": { "middleLogoList": [ { "tokenLogo": "https://static.coinall.ltd/cdn/wallet/logo/ETH-20220328.png", "tokenName": "ETH" } ], "bottomRightLogoList": [ { "tokenLogo": "https://static.coinall.ltd/cdn/invest/platform/EtherFi.png", "tokenName": "ether.fi" } ], "topRightLogoList": [ { "tokenLogo": "https://static.coinall.ltd/cdn/wallet/logo/ETH-20220328.png", "tokenName": "ETH" } ], "topLeftLogoList": [] }, "assetsTokenList": [ { "tokenSymbol": "ETH", "tokenLogo": "https://static.coinall.ltd/cdn/wallet/logo/ETH-20220328.png", "coinAmount": "0.000000000000000001", "currencyAmount": "0.0000000000000020382", "tokenPrecision": 18, "tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "network": "ETH" } ], "rewardDefiTokenInfo": [], "fundsInfo": [ { "baseDefiTokenInfos": [ { "tokenSymbol": "ETH", "tokenLogo": "https://static.coinall.ltd/cdn/wallet/logo/ETH-20220328.png", "coinAmount": "0.0002", "currencyAmount": "0.40764", "tokenPrecision": 18, "tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "network": "ETH", "buttonType": 3, "callDataExtJson": "{\"isExtraReward\":true}" } ], "callDataExtJson": "{\"isExtraReward\":true}", "extraData": { "claimDetails": [ { "coinAmount": "0.000100000000000000", "principalIndex": "72021", "claimable": true, "status": "CLAIMABLE" }, { "coinAmount": "0.000100000000000000", "principalIndex": "72452", "claimable": true, "status": "CLAIMABLE" } ] }, "rewardType": "UNLOCKED_PRINCIPAL" } ], "extraData": {}, "totalValue": "0.4076400000000020382", "investmentCategory": 0, "investmentKey": "1-0x308861a430be4cce5502d0a12724771fc6daf216-0x35fa164735182de50811e8e2e824cfb9b6118ac2", "marketId": "", "detailPath": "ether-fi-ethereum-eth-22850" }, { "investmentName": "ETH", "specialPositionAssetKey": "1-0x7d5706f6ef3f89b3951e23e557cdfbc3239d4e2c-72021-08", "isInvestTypeSupport": false, "investType": 8, "investName": "Locked Staking", "investLogo": { "middleLogoList": [ { "tokenLogo": "https://static.coinall.ltd/cdn/wallet/logo/ETH-20220328.png", "tokenName": "ETH" } ] }, "assetsTokenList": [ { "tokenSymbol": "ETH", "tokenLogo": "https://static.coinall.ltd/cdn/wallet/logo/ETH-20220328.png", "coinAmount": "0.0001", "currencyAmount": "0.20382", "tokenPrecision": 18, "tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "network": "ETH" } ], "rewardDefiTokenInfo": [], "extraData": {}, "totalValue": "0.20382", "investmentCategory": 0, "investmentKey": "1-0x7d5706f6ef3f89b3951e23e557cdfbc3239d4e2c-72021-0", "marketId": "" }, { "investmentName": "ETH", "specialPositionAssetKey": "1-0x7d5706f6ef3f89b3951e23e557cdfbc3239d4e2c-72452-08", "isInvestTypeSupport": false, "investType": 8, "investName": "Locked Staking", "investLogo": { "middleLogoList": [ { "tokenLogo": "https://static.coinall.ltd/cdn/wallet/logo/ETH-20220328.png", "tokenName": "ETH" } ] }, "assetsTokenList": [ { "tokenSymbol": "ETH", "tokenLogo": "https://static.coinall.ltd/cdn/wallet/logo/ETH-20220328.png", "coinAmount": "0.0001", "currencyAmount": "0.20382", "tokenPrecision": 18, "tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "network": "ETH" } ], "rewardDefiTokenInfo": [], "extraData": {}, "totalValue": "0.20382", "investmentCategory": 0, "investmentKey": "1-0x7d5706f6ef3f89b3951e23e557cdfbc3239d4e2c-72452-0", "marketId": "" } ], "investMarketTokenBalanceVoList": [], "availableRewards": [], "airDropRewardInfo": [], "extraData": {} } ], "walletId": "1a33c32f-2b8d-426e-9be2-33445f0fcd87" } ], "platformName": "ether.fi", "analysisPlatformId": "260", "platformLogo": "https://static.coinall.ltd/cdn/invest/platform/EtherFi.png", "platformUrl": "https://app.ether.fi" } ] } ``` - [Error Codes](https://web3.okx.com/onchainos/dev-docs/wallet/defi-error-code.md) # Error Codes | Error Code | HTTP Status Code | Explanation | | --- | --- | --- | | 0 | 200 | Success | | 50011 | 429 | Rate limit exceeded. Please refer to the API documentation and reduce your request frequency | | 50014 | 400 | Parameter 0 cannot be empty | | 50026 | 500 | System error. Please try again later | | 50103 | 401 | Request header "OK-ACCESS-KEY" cannot be empty | | 50104 | 401 | Request header "OK-ACCESS-PASSPHRASE" cannot be empty | | 50105 | 401 | Request header "OK-ACCESS-PASSPHRASE" is incorrect | | 50106 | 401 | Request header "OK-ACCESS-SIGN" cannot be empty | | 50107 | 401 | Request header "OK-ACCESS-TIMESTAMP" cannot be empty | | 50111 | 401 | Invalid OK-ACCESS-KEY | | 50112 | 401 | Invalid OK-ACCESS-TIMESTAMP | | 50113 | 401 | Invalid signature | | 84000 | 400 | Parameter error | | 84001 | 200 | Protocol not supported | | 84003 | 200 | Protocol not supported | | 84007 | 200 | Investment product not supported | | 84010 | 200 | Token not supported | | 84011 | 200 | Protocol logo is empty | | 84013 | 200 | Swap not supported | | 84014 | 200 | Balance validation failed | | 84016 | 200 | Smart contract execution failed | | 84017 | 200 | Staking rate validation failed | | 84018 | 200 | Rebalancing failed | | 84019 | 200 | Address format mismatch | | 84021 | 200 | Syncing assets | | 84022 | 200 | Authorization type not supported | | 84023 | 200 | External service call error | | 84024 | 200 | Investment product does not exist | | 84025 | 200 | No claimable rewards | | 84026 | 200 | Investment product status abnormal | | 84027 | 200 | Transaction data construction failed | | 84028 | 200 | Asset query failed | | 84029 | 200 | Principal is still in lock-up period and cannot be claimed | | 84030 | 200 | Principal claim has expired | | 84031 | 200 | This product type does not support this time range | | 84032 | 200 | This API is only supported for V3 DEX Pool products | | 84998 | 200 | Investment error | | 84999 | 500 | Default error | - [Features and Services](https://web3.okx.com/onchainos/dev-docs/payments/x402-introduction.md) # Features and Services Onchain OS Payment provides protocol-native on-chain payment capabilities for APIs, MCP tools, and AI Agents. Built on the x402 open protocol, running on the X Layer network. ## Who Is It For? **Seller** Can be an API service provider, an MCP tool provider, or an Agent that offers external services. Typical scenarios: - Paid APIs such as weather, exchange rates, and on-chain data: charged per call, deducted upon invocation - MCP tools such as code generation, translation, and image recognition: automatic payment when called by an Agent - Agent services providing strategy signals and risk scoring: Agent-to-Agent transactions with automatic pricing and settlement **Buyer** Can be an ordinary user's Agent, or a developer providing App services on behalf of the Buyer. Typical scenarios: - Purchase paid data sources on demand through an Agent, with automatic payment and data retrieval - Call and purchase on-chain analytics APIs through an Agent, making autonomous decisions based on results - Integrate paid services in your App backend; users initiate payment, and the backend handles payment automatically ## How It Works The core interaction of Onchain OS Payment is a four-step flow: 1. Buyer requests a resource 2. Seller returns payment requirements (amount, token, network) 3. Buyer re-requests with a signed credential attached 4. Seller verifies and returns the resource ![Payment](../images/flow.jpeg) No account registration required, no manual intervention. ## Payment Methods The only difference between payment methods lies in the settlement rhythm: Instant Payment settles on-chain immediately after each signature, while Batch Payment allows the Buyer to sign multiple times to access resources first, and then the Seller batches multiple transactions into a single on-chain settlement. Choose the payment method that fits your business scenario: | **Payment Method** | **Use Case** | **Settlement Method** | **Compatible Protocol** | |:---:|:---:|:---:|:---: | **Instant Payment** | Single API call, content purchase, low-frequency high-value | Independent on-chain settlement per request |x402 | | **Batch Payment** | High-frequency micro-payments, micropayments, Agent autonomous transactions | Buyer signs multiple times, Seller batches and settles on-chain | x402 | > Not sure which one to choose? Start with [One-time Payment](./methods-onetime) -- integration takes just 5 minutes. ## Why Choose Onchain OS Payment **Flexible Payment Methods** -- Instant Payment and Batch Payment cover the vast majority of payment scenarios. **Zero Gas** -- Transfers and payments using USDG / USDT on X Layer incur zero Gas fees. Off-chain signing in Batch Payment mode also means zero Gas. **Multi-Token Support** -- Supports major stablecoins including USDT and USDG. **SDK** -- SDKs available in Node.js, Rust, and Go. **Built-in Compliance** -- KYT (Know Your Transaction) risk identification is built into every payment, with no additional integration required. **Open Standard** -- Built on the x402 protocol, not locked into any single platform. - [Core Concepts](https://web3.okx.com/onchainos/dev-docs/payments/core-concept.md) # Core Concepts ## HTTP 402 **What is HTTP 402?** HTTP 402 is a reserved status code in the HTTP specification, meaning "Payment Required" -- the client must pay to access the resource. It was defined in the HTTP/1.1 specification (RFC 2616) back in 1999, but since there was no accompanying payment mechanism at the time, it remained in a "reserved but unused" state for over twenty years. **Why has 402 never been put to use?** Because the HTTP specification only defined the semantics of the status code ("payment required"), but did not define how to pay, whom to pay, or how to verify payment. Without a standardized payment flow, browsers and clients had no idea what to do upon receiving a 402. The x402 protocol was created to fill this gap -- it defines a complete payment interaction flow based on 402. See the x402 Protocol FAQ for details. **Why use 402 instead of a custom status code?** Because 402's semantics already mean "payment required" -- this is part of the HTTP standard, and all HTTP clients, proxies, CDNs, and load balancers can correctly transmit this status code. Using a standard status code means no modifications are needed to any intermediate layer of network infrastructure, and the payment protocol can run directly on top of the existing HTTP ecosystem. ## x402 Protocol **What is x402?** x402 is an open payment protocol standard based on the HTTP 402 status code. It defines a complete request-pay-deliver flow: the server returns 402 + payment requirements -> the client pays on-chain -> the client retries with a payment credential -> the server verifies and returns the resource. **What are the roles in the x402 protocol?** - **Buyer**: The party that initiates the request and makes the payment, typically an AI Agent or application client. The Buyer signs and constructs a payment credential, submitting it to the Seller via an HTTP request header. - **Seller**: The party that provides paid APIs or resources. The Seller returns 402 + payment requirements on unpaid requests, and delivers the resource upon receiving a valid payment credential. - **Facilitator**: A third-party service responsible for payment Verification and on-chain Settlement. The Facilitator frees the Seller from maintaining blockchain nodes, managing Gas, and submitting transactions -- all of which are handled by the Facilitator. The core role of Onchain OS Payment is the Facilitator. **Who proposed x402?** x402 was proposed and open-sourced by Coinbase, and is currently being advanced by the x402 Foundation (co-governed by Coinbase and Cloudflare). It is an open standard that anyone can implement. **Is x402 only for AI Agents?** No. x402 is a general-purpose HTTP payment protocol that can be used by browsers, mobile apps, CLIs, and automation scripts. AI Agents are currently the most typical use case, because Agents need to autonomously complete paid API calls without human intervention. ## Facilitator **What is a Facilitator?** A Facilitator is a third-party role in the x402 protocol, responsible for payment Verification and on-chain Settlement. In x402's Buyer-Seller-Facilitator three-party architecture, the Facilitator serves as the trust layer in between: after the Buyer signs a payment, the Facilitator verifies the validity of the payment credential and submits the on-chain transaction, so the Seller does not need to maintain blockchain infrastructure on its own. **Why is a Facilitator needed? Can't the Buyer just transfer directly to the Seller?** Technically yes, but the Facilitator solves several practical problems: **Seller doesn't need to run nodes**: The Facilitator handles on-chain interactions for the Seller (RPC connections, Gas management, transaction submission), and the Seller only needs a receiving address. **Verification and Settlement are separated**: The Facilitator first performs cryptographic verification (~100ms, off-chain), and only submits the on-chain Settlement after confirming the payment credential is valid. This makes verification extremely fast while ensuring reliable settlement. **Unified Compliance entry point**: Compliance checks such as KYT screening can be executed uniformly at the Facilitator layer, rather than each Seller implementing them individually. **Is Onchain OS a Facilitator?** Yes. The core role of Onchain OS Payment is the Facilitator -- receiving the Buyer's payment credential, verifying its validity, performing KYT screening, submitting on-chain Settlement, and confirming payment completion to the Seller. Coinbase also provides its own Facilitator service (CDP Facilitator); both are different implementations of the same role. **Does the Facilitator have access to my funds?** The Facilitator submits on-chain transactions, but funds transfer directly from the Buyer to the Seller's receiving address. The Facilitator does not custody funds, nor does it act as an intermediary account. Its role is more like a "notary" -- it verifies and executes, but does not hold funds. **Can I build my own Facilitator?** x402 is an open protocol, and in theory anyone can implement their own Facilitator. However, building your own means you need to maintain the full suite of infrastructure: blockchain node connections, Gas management, transaction signing and broadcasting, KYT Compliance, and more. Using the Onchain OS Payment Facilitator service can save you from all of this. ## Settlement **What is Settlement?** Settlement is the on-chain execution process where, after the Buyer's payment credential is verified by the Facilitator, funds are actually transferred from the Buyer's address to the Seller's receiving address. In the x402 flow, Settlement is handled by the Facilitator -- the Seller does not need to submit on-chain transactions on its own. In simple terms: Verification answers "is this payment valid?", while Settlement answers "when do the funds arrive?". Onchain OS supports both Synchronous Settlement and Asynchronous Settlement modes, which differ in whether the Seller waits for fund confirmation before delivering the resource, or delivers first with the funds arriving shortly after. **What is Synchronous Settlement?** Synchronous Settlement (`syncSettle = true`) means the Facilitator submits the on-chain transaction and waits for final confirmation before notifying the Seller to deliver the resource. "Confirm first, deliver second" -- no bad debt risk, but requires waiting for on-chain block confirmation. **What is Asynchronous Settlement?** Asynchronous Settlement (`syncSettle = false`) means the Facilitator returns a transaction hash immediately after verifying the payment credential, and the Seller delivers the resource right away, while on-chain confirmation completes asynchronously in the background. "Deliver first, confirm later" -- near-zero latency, suitable for high-frequency, low-value scenarios. **Is Asynchronous Settlement safe? Is there bad debt risk?** Extremely low. Once a transaction is broadcast to the chain, it is virtually impossible to roll back (especially under X Layer's finality mechanism). Onchain OS checks transaction parameters and broadcast status during the verification step, leaving an extremely narrow window for fraud. For high-frequency, low-value calls (e.g., an inference API at $0.001 per call), the risk-reward ratio of Asynchronous Settlement is far better than the latency cost of Synchronous Settlement. **Which mode should I choose for my use case?** A simple rule of thumb: if the value per call is less than $1 and the call frequency is high, choose asynchronous; if the value per call is high or you have strict requirements for fund confirmation, choose synchronous. Most AI Agent scenarios are suitable for Asynchronous Settlement. **What happens if Asynchronous Settlement fails?** If an on-chain transaction ultimately fails to confirm (extremely rare), the Seller can track it through Onchain OS's settlement status API. At the protocol level, an unconfirmed transaction means the Buyer was not actually charged, and the loss is borne by the Seller -- but the probability is extremely low. ## Gas Subsidy **What is Gas Subsidy?** Gas Subsidy is the fee waiver provided by OKX for payment transactions on X Layer. Normally, on-chain transactions require paying Gas fees (miner/validator processing fees), but when making x402 payments with USDG or USDT on X Layer, the Gas fee is zero -- covered by OKX. **Does Gas Subsidy apply to all chains?** No. Gas Subsidy currently only applies to payment transactions using USDG and USDT on X Layer. When paying on other chains, Gas fees are borne by the Buyer at the standard rate. **What does zero Gas mean for micropayments?** It means any amount, no matter how small, is economically viable. On chains with Gas fees, a $0.001 payment with a $0.01 Gas fee is clearly unreasonable. With zero Gas on X Layer, the Buyer's actual cost = the Seller's listed price, with no additional overhead. This is a foundational requirement for high-frequency, low-value AI Agent call scenarios. **Will Gas Subsidy be discontinued?** The Gas Subsidy policy depends on OKX's operational strategy. It is recommended to follow Onchain OS official announcements for the latest information. Even if the policy is adjusted in the future, X Layer's Gas fee rate is still far lower than high-cost chains like Ethereum mainnet. ## KYT **What is KYT?** KYT (Know Your Transaction) is a transaction-level Compliance screening technology. It analyzes on-chain fund flows to identify transactions associated with high-risk entities such as sanctioned addresses, mixers, darknet markets, and stolen funds. **What is the difference between KYT and KYC?** KYC (Know Your Customer) is identity verification of "people" -- who you are, where you live, your ID number. KYT is risk assessment of "transactions" -- where the funds came from, and whether they are associated with high-risk activities. The x402 protocol does not require user registration or KYC, but Onchain OS achieves Compliance at the transaction level through KYT, filtering illicit funds while preserving anonymity. **Does KYT screening slow down payments?** Not noticeably. KYT screening is executed in parallel with transaction verification, and its impact on end-to-end latency is on the order of milliseconds. **What if my transaction is flagged by KYT?** A flagged transaction will not pass verification, the server will not return the paid resource, and the Buyer will not be charged. The specific rejection reason will be returned via an error code. If you believe it is a false positive, you can contact the Onchain OS support team. **As a Seller, do I need to perform KYT myself?** No. Onchain OS automatically performs KYT checks during the transaction verification step, completely transparent to the Seller. This is one of the core differentiators of Onchain OS compared to the bare x402 protocol. - [Supported Networks and Currencies](https://web3.okx.com/onchainos/dev-docs/payments/supported-networks.md) # Supported Networks and Currencies Currently supported network: **X Layer** (ChainIndex: 196). Supported currencies: | Currency | Contract Address | |----------|--------------------------------------------------------| | USDG | 0x4ae46a509f6b1d9056937ba4500cb143933d2dc8 | | USDT | 0x779ded0c9e1022225f8e0630b35a9b54be713736 | - [Overview](https://web3.okx.com/onchainos/dev-docs/payments/quickstart-overview.md) # Overview Onchain OS Payment enables any Buyer and Seller to initiate and receive on-chain payments. The Seller declares a charge requirement, the Buyer completes the payment, and the Seller returns the resource immediately after verification — the entire process is completed within a single HTTP request. This quick start guide uses a single payment as an example to help you complete your first on-chain payment in 5 minutes. **Choose your starting point:** - [Seller Quickstart](https://web3.okx.com/onchainos/dev-docs/payments/payment-use-seller.md) # Seller Quickstart If you are a seller, you can quickly get set up via an AI agent (coming soon) or via API. Once complete, your service will be able to charge buyers and AI Agents for access through the x402 protocol. - [Build with Agent](https://web3.okx.com/onchainos/dev-docs/payments/payment-use-seller-ai.md) # Build with Agent Configure payment collection capabilities for Onchain OS Payment through AI. Simply send the prompt to an AI to generate the complete 402 payment integration code -- no need to manually implement the 402 response or transaction verification. ## Prerequisites - Payment Wallet: Any EVM-compatible wallet (e.g., OKX Wallet, [OKX Agentic Wallet](https://web3.okx.com/zh-hans/onchainos/dev-docs/wallet/agentic-wallet)) - API Key: Apply through the [OKX Developer Portal](https://web3.okx.com/zh-hans/onchainos/dev-portal) - Business Backend: Your own API service or backend server ## Configuration Send the following prompt to an AI to generate the complete integration code. The weather query API below is for reference only: ``` // TS version Reference https://github.com/okx/payments/blob/main/typescript/SELLER.md // Rust version Reference https://github.com/okx/payments/blob/main/rust/SELLER.md // Go version Reference https://github.com/okx/payments/blob/main/go/SELLER.md I have a weather query API (/weather). Help me deploy it to localhost:4021 and add payment functionality using onchain-payment-sdk. Charge 0.1 USDT per call, use X Layer network (eip155:196), and the payment address is 0xMyWalletAddress. ``` > During the process, the AI will prompt you to configure your recipient wallet and API Key. ## Verification Use the following code to request your paid resource: ```shell curl -i http://localhost:4021/weather ``` After the request, you will see a `402` + `PAYMENT-REQUIRED` response header, indicating that the integration was successful: ```http HTTP/1.1 402 Payment Required // 402状态码 content-type: application/json payment-required: eyJ4NDAyVmVy.....jAifX1dfQ== // 支付信息(base64 encode编码) ``` The base64-decoded `payment-required` payment information will also be returned: ```json { "x402Version": 2, "resource": { "url": "/weather", "description": "Get current weather data for any location", "mimeType": "application/json" }, "accepts": [ { "scheme": "exact", "network": "eip155:196", "asset": "0x779ded0c9e1022225f8e0630b35a9b54be713736", "amount": "1000", "payTo": "0xb483abdb92f8061e9a3a082a4aaaa6b88c381308", "maxTimeoutSeconds": 600000, "extra": { "name": "USD₮0", "version": "1" } }, { "scheme": "aggr_deferred", "network": "eip155:196", "asset": "0x779ded0c9e1022225f8e0630b35a9b54be713736", "amount": "1000", "payTo": "0xb483abdb92f8061e9a3a082a4aaaa6b88c381308", "maxTimeoutSeconds": 600000, "extra": { "version": "1", "name": "USD₮0" } } ] } ``` - [Build with SDK](https://web3.okx.com/onchainos/dev-docs/payments/payment-use-seller-api.md) # Build with SDK Integrate Onchain OS Payment collection capabilities via SDK. Built-in 402 protocol response and on-chain transaction verification — no need to implement it yourself through the API. ## Prerequisites - Payment Wallet: Any EVM-compatible wallet (e.g., OKX Wallet, [OKX Agentic Wallet](https://web3.okx.com/zh-hans/onchainos/dev-docs/wallet/agentic-wallet)) - API Key: Apply through the [OKX Developer Portal](https://web3.okx.com/zh-hans/onchainos/dev-portal) - Business Backend: Your own API service or backend server ## Install SDK **Node.js** ```shell npm install express @okxweb3/x402-express @okxweb3/x402-core @okxweb3/x402-evm npm install -D typescript tsx @types/express @types/node ``` **Go** ```shell go get github.com/okx/payments/go ``` **Rust** ```toml # Cargo.toml configuration [dependencies] x402-axum = { git = "https://github.com/okx/payments" } x402-core = { git = "https://github.com/okx/payments" } x402-evm = { git = "https://github.com/okx/payments" } ``` ## Integrate Service **Node.js** ```typescript import express from "express"; import { paymentMiddleware, x402ResourceServer, } from "@okxweb3/x402-express"; import { ExactEvmScheme } from "@okxweb3/x402-evm/exact/server"; import { OKXFacilitatorClient } from "@okxweb3/x402-core"; const app = express(); const NETWORK = "eip155:196"; // X Layer Mainnet const PAY_TO = process.env.PAY_TO_ADDRESS || "0xYourWalletAddress"; // OKX Facilitator Client (requires OKX API credentials) const facilitatorClient = new OKXFacilitatorClient({ apiKey: "OKX_API_KEY", secretKey: "OKX_SECRET_KEY", passphrase: "OKX_PASSPHRASE", }); // Create resource server and register EVM exact scheme const resourceServer = new x402ResourceServer(facilitatorClient); resourceServer.register(NETWORK, new ExactEvmScheme()); // Mount x402 payment middleware app.use( paymentMiddleware( { "GET /generateImg": { accepts: [{ scheme: "exact", network: NETWORK, payTo: PAY_TO, price: "$0.01", // USDT 0.01 }], description: "AI Image Generation Service", mimeType: "application/json", }, }, resourceServer, ), ); // Protected image generation route (only executed after payment is verified) app.get("/generateImg", (_req, res) => { console.log("[Seller] Payment verified, generating image..."); res.json({ success: true, imageUrl: "https://placehold.co/512x512/png?text=AI+Generated", prompt: "a sunset over mountains", timestamp: new Date().toISOString(), }); }); app.listen(4000, () => { console.log("[Seller] Image generation service listening at http://localhost:4000"); console.log("[Seller] Protected route: GET http://localhost:4000/generateImg"); console.log(`[Seller] Network: ${NETWORK}, PayTo: ${PAY_TO}`); }); ``` **Go** ```go package main import ( "net/http" "os" "time" ginfw "github.com/gin-gonic/gin" x402http "github.com/okx/payments/go/http" ginmw "github.com/okx/payments/go/http/gin" evm "github.com/okx/payments/go/mechanisms/evm/exact/server" ) func main() { // 1. Create OKX Facilitator client facilitator, _ := x402http.NewOKXFacilitatorClient(&x402http.OKXFacilitatorConfig{ Auth: x402http.OKXAuthConfig{ APIKey: os.Getenv("OKX_API_KEY"), SecretKey: os.Getenv("OKX_SECRET_KEY"), Passphrase: os.Getenv("OKX_PASSPHRASE"), }, }) // 2. Define payment-protected routes routes := x402http.RoutesConfig{ "GET /generateImg": { Accepts: x402http.PaymentOptions{ { Scheme: "exact", Price: "$0.01", Network: "eip155:196", PayTo: "0xYourWalletAddress", }, }, Description: "AI-generated image", MimeType: "image/png", }, } // 3. Create Gin router with payment middleware r := ginfw.Default() r.Use(ginmw.X402Payment(ginmw.Config{ Routes: routes, Facilitator: facilitator, Schemes: []ginmw.SchemeConfig{ {Network: "eip155:196", Server: evm.NewExactEvmScheme()}, }, Timeout: 30 * time.Second, })) r.GET("/genarateImg", func(c *ginfw.Context) { c.JSON(http.StatusOK, ginfw.H{"image": "https://placehold.co/512x512/png?text=AI+Generated"}) }) r.Run(":4000") } ``` **Rust** ```rust use std::collections::HashMap; use axum::{routing::get, Json, Router}; use serde_json::{json, Value}; use x402_axum::{payment_middleware, AcceptConfig, RoutePaymentConfig}; use x402_core::http::OkxHttpFacilitatorClient; use x402_core::server::X402ResourceServer; use x402_evm::{AggrDeferredEvmScheme, ExactEvmScheme}; #[tokio::main] async fn main() { // Initialize tracing (see Facilitator request/response logs in terminal) tracing_subscriber::fmt::init(); // Read configuration from environment variables let api_key = std::env::var("OKX_API_KEY").expect("OKX_API_KEY is required"); let secret_key = std::env::var("OKX_SECRET_KEY").expect("OKX_SECRET_KEY is required"); let passphrase = std::env::var("OKX_PASSPHRASE").expect("OKX_PASSPHRASE is required"); let pay_to = std::env::var("PAY_TO_ADDRESS") .unwrap_or_else(|_| "0xb483abdb92...aa6b88c381308".to_string()); // 1. Configure OKX Facilitator let facilitator = match std::env::var("FACILITATOR_URL") { Ok(url) => OkxHttpFacilitatorClient::with_url(&url, &api_key, &secret_key, &passphrase), Err(_) => OkxHttpFacilitatorClient::new(&api_key, &secret_key, &passphrase), } .expect("Failed to create facilitator client"); // 2. Create Server and register payment schemes let mut server = X402ResourceServer::new(facilitator) .register("eip155:196", ExactEvmScheme::new()) .register("eip155:196", AggrDeferredEvmScheme::new()); // 3. Must initialize (fetches supported schemes from facilitator) server .initialize() .await .expect("Failed to initialize: check facilitator connectivity"); // 4. Configure which routes require payment let routes = HashMap::from([( "GET /api/joke".to_string(), RoutePaymentConfig { accepts: vec![AcceptConfig { scheme: "exact".into(), price: "$0.001".into(), network: "eip155:196".into(), pay_to: pay_to.clone(), max_timeout_seconds: None, extra: None, }], description: "Get a random joke".into(), mime_type: "application/json".into(), sync_settle: None, }, )]); // 5. Build Axum router let app = Router::new() .route("/health", get(health)) .route("/api/joke", get(joke)) .layer(payment_middleware(routes, server)); // 6. Start server let listener = tokio::net::TcpListener::bind("0.0.0.0:3000") .await .unwrap(); println!("========================================"); println!(" Your paid API is running!"); println!(" Free endpoint: http://localhost:3000/health"); println!(" Paid endpoint: http://localhost:3000/api/joke ($0.001)"); println!("========================================"); axum::serve(listener, app).await.unwrap(); } // Free endpoint async fn health() -> Json { Json(json!({ "status": "ok" })) } // Paid endpoint - requires $0.001 payment to access async fn joke() -> Json { Json(json!({ "joke": "Why do programmers always confuse Halloween and Christmas? Because Oct 31 = Dec 25", "price": "$0.001" })) } ``` ## Test Service 1. Use Onchain OS to request your service endpoint. You can refer to [Buyer Quickstart](https://web3.okx.com/onchainos/dev-docs/payments/payment-use-buyer). ``` Use onchainOS to access http://localhost:4000/genarateImg ``` 2. The server returns a 402 status code with `PAYMENT-REQUIRED` in the response header. 3. Complete the payment using Agentic Wallet. 4. Agentic Wallet automatically retries the request. 5. The server verifies the payment result with the Facilitator and returns the corresponding resource. - [Buyer Quickstart](https://web3.okx.com/onchainos/dev-docs/payments/payment-use-buyer.md) # Buyer Quickstart Integrate Onchain OS payment capabilities to enable your AI Agent to directly purchase services and resources. - [Build with Agent](https://web3.okx.com/onchainos/dev-docs/payments/payment-use-buyer-ai.md) # Build with Agent After installing the payment Skill for your Agent, it can recognize 402 payment requests, sign transactions, and complete payments without human intervention. ## Configuration Send the following prompt to the AI to install Onchain OS Skills and configure an Agentic Wallet for your Agent: ``` Run npx skills add okx/onchainos-skills to install Onchain OS skills Note: Please install to the skill directory corresponding to the current Agent Also, help me install the latest version of the CLI based on this documentation https://github.com/okx/onchainos-skills ``` ## Verification The following example uses "query weather" as a demonstration. Please test with an actual online x402 paid service as needed. Log in: ``` onchainos wallet login ``` Request the seller's service/resource: ``` // Not a production service, for reference only Access the service at http://localhost:4021/weather ``` If payment information is returned, the request was successful: ``` The service returned an x402 payment requirement response (HTTP 402). Details: - x402 Version: 2 - Resource: /weather — Get current weather data for any location, returns application/json - Payment methods (two schemes): - exact — One-time payment - aggr_deferred — Deferred payment - Network: eip155:196 (OKX X Layer) - Token: USD₮0 (0x779ded0c9e1022225f8e0630b35a9b54be713736) - Amount: 1000 (smallest unit) - Pay to: 0xb483abdb92f8061e9a3a082a4aaaa6b88c381308 - Timeout: 600,000 seconds This endpoint requires payment via the x402 protocol to access. Would you like me to initiate payment to get the weather data? ``` Confirm the payment, sign the transaction data, and replay the request to the seller: ``` Signature successful, replaying request: Bash(PAYMENT_PAYLOAD=$(python3 -c " import json, base64 payload = { 'x402Version': 2, 'resource': {'url': '/weather', 'description': 'Get current weather data for any location', 'mimeType': 'application/json'}, 'accepted': {'scheme': 'exact', 'network': 'eip155:196', 'asset': '0x779ded0...4be713736', 'amount': '1000', 'payTo': '0xb483abd....aa6b88c381308', 'maxTimeoutSeconds': 600000, 'extra': {'name': 'USD₮0', 'version': '1'}}, 'payload': { 'signature': '0x3d1907a6ba9f592c...35868ea11b', 'authorization': {'from': '0xbda9fde...99763', 'nonce': '0x20862cc...06e48', 'to': '0xb483abd...81308', 'validAfter': '0', 'validBefore': '1775837508', 'value': '1000'} } } print(base64.b64encode(json.dumps(payload, separators=(',', ':')).encode()).decode()) ") curl -s -D - http://localhost:4021/weather -H "PAYMENT-SIGNATURE: $PAYMENT_PAYLOAD") ⎿ HTTP/1.1 200 OK ``` The resource returned by the seller is received: ``` ⏺ Payment successful! Weather data returned: {"report": {"temperature": 70, "weather": "sunny"}} - Temperature: 70°F - Weather: Sunny ☀️ ``` - [Overview](https://web3.okx.com/onchainos/dev-docs/payments/methods-overview.md) # Overview Onchain OS Payment offers two payment methods: One-Time Payment and Batch Payment. - **One-Time Payment**: One request, one settlement, each transaction submitted on-chain individually. Suitable for high-value scenarios that require immediate on-chain confirmation. - **Batch Payment**: Confirmed immediately upon request; on-chain settlement is completed in batches in the background. Suitable for high-frequency, low-value continuous calls by AI Agents. Both methods support the X Layer network, accept USDG and USDT, with zero Gas fees. ## How It Works Both payment methods share the same x402 protocol framework and API interface. The difference lies in the signature method and settlement timing. ### One-Time Payment Each request independently completes a full payment: ![Payment](../images/one-time-EN.jpeg) - The Buyer's payment signature is an EOA signature (converted via signConvert), which can be directly accepted by on-chain contracts - After the Seller calls `/settle`, the Facilitator submits the transaction on-chain - Supports both synchronous settlement (returns after on-chain confirmation) and asynchronous settlement (returns immediately after submission) → For detailed integration guide, see ### Batch Payment The Seller receives confirmation immediately after the Buyer signs; on-chain settlement is completed asynchronously in batches in the background: ![Payment](../images/batch-EN.jpeg) - The Buyer signs directly with a session key (skipping signConvert); the signature cannot be directly accepted by on-chain contracts - After the Seller calls `/settle`, the Facilitator stores the signature in the database and **immediately returns `status: "success"`** - In the background, the TEE (Trusted Execution Environment) compresses multiple signatures into a single on-chain transaction, significantly reducing Gas costs - Security guarantee: session key signatures are settled collectively by the TEE; Sellers cannot bypass the Facilitator to submit on-chain independently → For detailed integration guide, see ## Use Cases Choose the appropriate method based on your business scenario: | **Your Scenario** | **Recommended Method** | |:---:|:---:| | Each call has a clear price; delivery is irrevocable once completed (e.g., report generation, file download) | **One-Time Payment** | | Resources should only be delivered after receiving on-chain confirmation | **One-Time Payment** | | API is called at high frequency by AI Agents continuously, with very small per-call amounts (e.g., tool-chain orchestration, streaming billing) | **Batch Payment** | | Latency-sensitive; millisecond-level response takes priority over immediate settlement confirmation | **Batch Payment** | If your business covers multiple scenarios above, you do not need to choose one over the other. Return both the `exact` and `aggr_deferred` schemes in the 402 response, and the system will automatically match based on the Buyer's capabilities. - [One-Time Payment](https://web3.okx.com/onchainos/dev-docs/payments/methods-onetime.md) # One-Time Payment ## Overview One-Time Payment is the most fundamental payment mode in Onchain OS Payment: each time a buyer requests a paid resource, a complete payment flow is executed independently. One request, instant settlement, instant delivery. ## Use Cases - Each API call has a clear price and delivery is irreversible once completed (e.g., report generation, file download) - Resources should only be delivered after on-chain confirmation (txHash) is received - High-value API calls that require the certainty of immediate on-chain settlement ## Seller Integration **Node.js** ```typescript import { x402ResourceServer } from "@okxweb3/x402-core/server"; import { ExactEvmScheme } from "@okxweb3/x402-evm/exact/server"; import { OKXFacilitatorClient } from "@okxweb3/x402-core"; const facilitator = new OKXFacilitatorClient({ apiKey: "xxx", secretKey: "xxx", passphrase: "xxx", syncSettle: false, }); const server = new x402ResourceServer(facilitator); // Register one-time payment scheme server.register("eip155:196", new ExactEvmScheme()); // Configure payment routes const routes = { "GET /api/data": { accepts: [{ scheme: "exact", network: "eip155:196", payTo: "0xSellerWallet", price: "$0.01", }], description: "Premium data endpoint", mimeType: "application/json", }, }; app.use(paymentMiddleware(routes, server)); ``` **Go** ```go package main import ( "fmt" "net/http" "os" "time" x402http "github.com/okx/payments/go/http" ginmw "github.com/okx/payments/go/http/gin" exact "github.com/okx/payments/go/mechanisms/evm/exact/server" ginfw "github.com/gin-gonic/gin" ) func main() { syncClient, err := x402http.NewOKXFacilitatorClient(&x402http.OKXFacilitatorConfig{ Auth: x402http.OKXAuthConfig{ APIKey: "OKX_API_KEY", SecretKey: "OKX_SECRET_KEY", Passphrase: "OKX_PASSPHRASE", }, BaseURL: "https://web3.okx.com", }) if err != nil { fmt.Printf("Failed to create client: %v\n", err) os.Exit(1) } routes := x402http.RoutesConfig{ "GET /api/data": { Accepts: x402http.PaymentOptions{ {Scheme: "exact", Price: "$0.01", Network: "eip155:196", PayTo: "SellerWallet"}, }, Description: "Premium data endpoint", MimeType: "application/json", }, } schemes := []ginmw.SchemeConfig{ {Network: "eip155:196", Server: exact.NewExactEvmScheme()}, } r := ginfw.Default() apiGroup := r.Group("/") apiGroup.Use(ginmw.X402Payment(ginmw.Config{ Routes: routes, Facilitator: syncClient, Schemes: schemes, Timeout: 30 * time.Second, })) apiGroup.GET("/api/data", func(c *ginfw.Context) { c.JSON(http.StatusOK, ginfw.H{ "data": "premium content", "price": "$0.01", }) }) r.Run(":3000") } ``` **Rust** ```rust use std::collections::HashMap; use axum::{routing::get, Json, Router}; use serde_json::{json, Value}; use x402_axum::{payment_middleware, AcceptConfig, RoutePaymentConfig}; use x402_core::http::OkxHttpFacilitatorClient; use x402_core::server::X402ResourceServer; use x402_evm::ExactEvmScheme; #[tokio::main] async fn main() { // 1. Configure OKX Facilitator client with API credentials let facilitator = OkxHttpFacilitatorClient::new( "OKX_API_KEY", "OKX_SECRET_KEY", "OKX_PASSPHRASE", ) .expect("Failed to create facilitator client"); // 2. Create resource server and register the "exact" payment scheme on X Layer let mut server = X402ResourceServer::new(facilitator) .register("eip155:196", ExactEvmScheme::new()); // 3. Initialize server (fetches supported schemes from facilitator) server .initialize() .await .expect("Failed to initialize: check facilitator connectivity"); // 4. Define which routes require payment and their pricing let routes = HashMap::from([( "GET /api/data".to_string(), RoutePaymentConfig { accepts: vec![AcceptConfig { scheme: "exact".into(), price: "$0.01".into(), // $0.01 per request network: "eip155:196".into(), // X Layer network pay_to: "SellerWallet".into(), // Seller's wallet address max_timeout_seconds: None, // Default: 300s (5 min) extra: None, }], description: "Premium data endpoint".into(), mime_type: "application/json".into(), sync_settle: None, // Default: async settle }, )]); // 5. Build Axum router with payment middleware let app = Router::new() .route("/api/data", get(|| async { Json(json!({"data": "premium"})) })) .layer(payment_middleware(routes, server)); // 6. Start the server let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); axum::serve(listener, app).await.unwrap(); } ``` ### Synchronous Settlement vs Asynchronous Settlement After calling `/settle`, the Facilitator submits the transaction on-chain. The `syncSettle` field in the route configuration controls the settlement behavior: | Mode | Parameter Value | Facilitator Behavior | Use Case | |:---:|:---:|:---:|:---:| | Synchronous | `true` | Submits the transaction and waits for on-chain confirmation before returning txHash | High-value transactions where resources should only be delivered after payment is confirmed | | Asynchronous | `false` | Returns txHash immediately after submitting the transaction, without waiting for confirmation | Medium-value transactions where response speed matters | > Asynchronous Settlement carries timing risk: resources may be delivered before on-chain payment is finalized. Synchronous Settlement is recommended for high-value transactions. ## Buyer Integration After installing the OKX Agentic Wallet, the Agent automatically handles the 402 negotiation and payment signing. For details, see [Buyer Quickstart](./payment-use-buyer). - [Batch Payment](https://web3.okx.com/onchainos/dev-docs/payments/methods-batch.md) # Batch Payment ## Overview Batch Payment is a payment mode designed by Onchain OS Payment for high-frequency, low-value scenarios. Unlike One-Time Payment, Batch Payment **does not require each transaction to be settled on-chain immediately** -- after the buyer signs, the seller receives confirmation and delivers the resource right away, while on-chain settlement is completed asynchronously in batches by OKX in the background. ## Why Batch Payment In One-Time Payment, every transaction must go through the full "verify -> on-chain settlement -> delivery" flow. This is reasonable for high-value transactions, but in scenarios where AI Agents make high-frequency calls, settling each transaction individually on-chain introduces two problems: - **Latency**: Even with asynchronous settlement, the Facilitator still needs extra time to submit transactions - **Throughput**: In high-frequency scenarios, per-transaction on-chain settlement is limited by on-chain confirmation speed, and a large number of concurrent requests creates a settlement bottleneck Batch Payment specifically addresses both issues: the settle call returns confirmation immediately (solving the latency problem), and multiple transactions are compressed into a single on-chain transaction (solving the throughput problem). ## Prerequisites > Batch Payment requires the buyer to install and use the [OKX Agentic Wallet](https://web3.okx.com/zh-hans/onchainos/dev-docs/wallet/agentic-wallet). Regular EVM wallets cannot use this mode. This is because Batch Payment relies on two key pieces of infrastructure: - **Session Key**: A temporary signing key generated by the Agentic Wallet that allows the Agent to sign autonomously within the authorized scope, without invoking the primary private key each time - **TEE (Trusted Execution Environment)**: A hardware-level security isolation technology. OKX performs batch settlement inside a TEE, ensuring that signing data cannot be tampered with or stolen -- even if the server is compromised, settlement transactions cannot be forged ## Use Cases - **Continuous AI Agent calls**: An Agent frequently calls multiple paid APIs during a single task (e.g., search -> analyze -> generate) - **Streaming billing**: High-frequency micropayments charged per token, per character, or per request - **Bulk data queries**: A large volume of on-chain data or market data queries in a short period - **Tool-chain orchestration**: An Agent automatically orchestrates multiple tool calls, each with a very small amount ## Seller Integration **Node.js** ```typescript import { OKXFacilitatorClient } from "@okxweb3/x402-core"; import { x402ResourceServer } from "@okxweb3/x402-core/server"; import { AggrDeferredEvmScheme } from "@okxweb3/x402-evm/deferred/server"; const facilitator = new OKXFacilitatorClient({ apiKey: "xxx", secretKey: "xxx", passphrase: "xxx", }); const server = new x402ResourceServer(facilitator); server.register("eip155:196", new AggrDeferredEvmScheme()); const routes = { "GET /api/data": { accepts: [{ scheme: "aggr_deferred", network: "eip155:196", payTo: "0xSellerWallet", price: "$0.001", }], description: "Data endpoint with deferred settlement", mimeType: "application/json", }, }; app.use(paymentMiddleware(routes, server)); ``` **Go** ```go package main import ( "fmt" "net/http" "os" "time" x402http "github.com/okx/payments/go/http" ginmw "github.com/okx/payments/go/http/gin" deferred "github.com/okx/payments/go/mechanisms/evm/deferred/server" ginfw "github.com/gin-gonic/gin" ) func main() { syncClient, err := x402http.NewOKXFacilitatorClient(&x402http.OKXFacilitatorConfig{ Auth: x402http.OKXAuthConfig{ APIKey: "OKX_API_KEY", SecretKey: "OKX_SECRET_KEY", Passphrase: "OKX_PASSPHRASE", }, BaseURL: "https://beta.okex.org", }) if err != nil { fmt.Printf("Failed to create client: %v\n", err) os.Exit(1) } routes := x402http.RoutesConfig{ "GET /api/data": { Accepts: x402http.PaymentOptions{ {Scheme: "aggr_deferred", Price: "$0.01", Network: "eip155:196", PayTo: "SellerWallet"}, }, Description: "Premium data endpoint", MimeType: "application/json", }, } schemes := []ginmw.SchemeConfig{ {Network: "eip155:196", Server: deferred.NewAggrDeferredEvmScheme()}, } r := ginfw.Default() apiGroup := r.Group("/") apiGroup.Use(ginmw.X402Payment(ginmw.Config{ Routes: routes, Facilitator: syncClient, Schemes: schemes, Timeout: 30 * time.Second, })) apiGroup.GET("/api/data", func(c *ginfw.Context) { c.JSON(http.StatusOK, ginfw.H{ "data": "premium content", "price": "$0.01", }) }) r.Run(":3000") } ``` **Rust** ```rust use axum::{Router, Json, routing::get}; use serde_json::json; use std::collections::HashMap; use x402_axum::{payment_middleware, RoutePaymentConfig, AcceptConfig}; use x402_core::http::OkxHttpFacilitatorClient; use x402_core::server::X402ResourceServer; use x402_evm::AggrDeferredEvmScheme; #[tokio::main] async fn main() { // 1. Configure OKX Facilitator client with API credentials let facilitator = OkxHttpFacilitatorClient::new( &std::env::var("OKX_API_KEY").unwrap(), &std::env::var("OKX_SECRET_KEY").unwrap(), &std::env::var("OKX_PASSPHRASE").unwrap(), ) .expect("Failed to create facilitator client"); // 2. Create resource server and register aggr_deferred scheme on X Layer let mut server = X402ResourceServer::new(facilitator) .register("eip155:196", AggrDeferredEvmScheme::new()); // 3. Initialize server (fetches supported schemes from facilitator) server .initialize() .await .expect("Failed to initialize: check facilitator connectivity"); // 4. Define which routes require payment and their pricing let routes = HashMap::from([( "GET /api/data".to_string(), RoutePaymentConfig { accepts: vec![AcceptConfig { scheme: "aggr_deferred".into(), price: "$0.01".into(), // $0.01 per request network: "eip155:196".into(), // X Layer network pay_to: "0xSellerWallet".into(), // Seller's wallet address max_timeout_seconds: None, // Default: 300s (5 min) extra: None, }], description: "Premium data endpoint".into(), mime_type: "application/json".into(), sync_settle: None, // Default: async settle }, )]); // 5. Build Axum router with payment middleware let app = Router::new() .route("/api/data", get(|| async { Json(json!({"data": "premium content"})) })) .layer(payment_middleware(routes, server)); // 6. Start the server let listener = tokio::net::TcpListener::bind("0.0.0.0:4021").await.unwrap(); axum::serve(listener, app).await.unwrap(); } ``` ## Buyer Integration After the buyer installs the OKX Agentic Wallet, the Agent automatically handles the 402 negotiation and signed payment. For details, please refer to [Buyer Quickstart](.payment-use-buyer). - [Node SDK Reference](https://web3.okx.com/onchainos/dev-docs/payments/sdk-nodejs.md) # Node SDK Reference ## **Packages** | Package | Description | |:---:|:---:| | `@okxweb3/x402-core` | Core: server, facilitator, types | | `@okxweb3/x402-evm` | EVM mechanisms: exact, aggr_deferred | | `@okxweb3/x402-express` | Express middleware (seller) | | `@okxweb3/x402-next` | Next.js middleware (seller) | | `@okxweb3/x402-hono` | Hono middleware (seller) | | `@okxweb3/x402-fastify` | Fastify middleware (seller) | --- ## **Core Types** ### **Network** ```typescript type Network = `${string}:${string}`; // CAIP-2 format, e.g., "eip155:196" ``` ### **Money / Price / AssetAmount** ```typescript type Money = string | number; // User-friendly amount, e.g., "$0.01", "0.01", 0.01 type AssetAmount = { asset: string; // Token contract address amount: string; // Amount in token's smallest unit (e.g., "10000" for 0.01 USDC) extra?: Record; // Scheme-specific data (e.g., EIP-712 domain) }; type Price = Money | AssetAmount; // Either a user-friendly amount or a specific token amount ``` ### **ResourceInfo** ```typescript interface ResourceInfo { url: string; // Resource URL path description?: string; // Human-readable description mimeType?: string; // Response content type (e.g., "application/json") } ``` ### **PaymentRequirements** Describes what the seller accepts for payment. ``` type PaymentRequirements = { scheme: string; // Payment scheme: "exact" | "aggr_deferred" network: Network; // CAIP-2 network identifier asset: string; // Token contract address amount: string; // Price in token's smallest unit payTo: string; // Recipient wallet address maxTimeoutSeconds: number; // Payment authorization validity window extra: Record; // Scheme-specific data }; ``` **`extra` fields by scheme:** | Scheme | Extra Field | Type | Description | |:---:|:---:|:---:|:---:| | `exact` (EIP-3009) | `extra.eip712.name` | string | EIP-712 domain name (e.g., "USD Coin") | | `exact` (EIP-3009) | `extra.eip712.version` | string | EIP-712 domain version (e.g., "2") | ### **PaymentRequired** The HTTP 402 response body sent to clients. ```typescript type PaymentRequired = { x402Version: number; // Protocol version (currently 2) error?: string; // Optional error message resource: ResourceInfo; // Protected resource metadata accepts: PaymentRequirements[]; // List of accepted payment options }; ``` ### **PaymentPayload** The client's signed payment submitted in the retry request. ```typescript type PaymentPayload = { x402Version: number; // Must match server's version resource?: ResourceInfo; // Optional resource reference accepted: PaymentRequirements; // The chosen payment option from `accepts` payload: Record; // Scheme-specific signed data (see below) extensions?: Record; // Extension data }; ``` **`payload` fields by scheme:** For **exact (EIP-3009)**: ```typescript { signature: `0x${string}`; // EIP-712 signature authorization: { from: `0x${string}`; // Buyer wallet address to: `0x${string}`; // Seller wallet address value: string; // Amount in smallest unit validAfter: string; // Unix timestamp (start validity) validBefore: string; // Unix timestamp (end validity) nonce: `0x${string}`; // 32-byte unique nonce }; } ``` For **aggr_deferred**: ```typescript { signature: `0x${string}`; // Session key signature authorization: { /* same as EIP-3009 */ }; } ``` ### **VerifyResponse** ```typescript type VerifyResponse = { isValid: boolean; // Whether signature is valid invalidReason?: string; // Machine-readable reason code invalidMessage?: string; // Human-readable error message payer?: string; // Recovered payer address extensions?: Record; }; ``` ### **SettleResponse** ```typescript type SettleResponse = { success: boolean; // Whether settlement succeeded status?: "pending" | "success" | "timeout"; // OKX extension errorReason?: string; // Machine-readable error code errorMessage?: string; // Human-readable error message payer?: string; // Payer address transaction: string; // On-chain transaction hash (empty for aggr_deferred) network: Network; // Settlement network amount?: string; // Actual settled amount (may differ for "upto") extensions?: Record; }; ``` ### **SupportedKind / SupportedResponse** ```typescript type SupportedKind = { x402Version: number; scheme: string; network: Network; extra?: Record; }; type SupportedResponse = { kinds: SupportedKind[]; extensions: string[]; // Supported extension keys signers: Record; // CAIP family → signer addresses }; ``` --- ## **Server API (`x402ResourceServer`)** ### **Constructor** ```typescript import { x402ResourceServer } from "@okxweb3/x402-core/server"; const server = new x402ResourceServer(facilitatorClients?); // facilitatorClients: FacilitatorClient | FacilitatorClient[] // Can pass a URL string shorthand: new x402ResourceServer("https://x402.org/facilitator") ``` ### **register(network, server)** Register a server-side scheme. Chainable. ```typescript server .register("eip155:196", new ExactEvmScheme()) .register("eip155:196", new AggrDeferredEvmScheme()); ``` ### **registerExtension(extension)** ```typescript interface ResourceServerExtension { key: string; enrichDeclaration?: (declaration: unknown, transportContext: unknown) => unknown; enrichPaymentRequiredResponse?: ( declaration: unknown, context: PaymentRequiredContext, ) => Promise; enrichSettlementResponse?: ( declaration: unknown, context: SettleResultContext, ) => Promise; } ``` ### **initialize()** Fetch supported kinds from the facilitator. Call once at startup. ```typescript await server.initialize(); ``` ### **buildPaymentRequirements(config) → PaymentRequirements[] ```typescript interface ResourceConfig { scheme: string; // "exact" | "aggr_deferred" | "upto" payTo: string; // Recipient wallet address price: Price; // "$0.01" or AssetAmount network: Network; // "eip155:196" maxTimeoutSeconds?: number; // Default: 60 extra?: Record; } const reqs = await server.buildPaymentRequirements({ scheme: "exact", payTo: "0xSeller", price: "$0.01", network: "eip155:196", }); ``` ### **buildPaymentRequirementsFromOptions(options, context) → PaymentRequirements[] Dynamic pricing and payTo. Functions receive the context parameter. ```typescript const reqs = await server.buildPaymentRequirementsFromOptions( [ { scheme: "exact", network: "eip155:196", payTo: (ctx) => ctx.sellerId === "A" ? "0xWalletA" : "0xWalletB", price: (ctx) => ctx.premium ? "$0.10" : "$0.01", }, ], requestContext ); ``` ### **verifyPayment(payload, requirements) → VerifyResponse ```typescript const result = await server.verifyPayment(paymentPayload, requirements); // result.isValid: boolean ``` ### **settlePayment(payload, requirements, ...) → SettleResponse ```typescript const result = await server.settlePayment( paymentPayload, requirements, declaredExtensions?, // Extension data from 402 response transportContext?, // HTTP transport context settlementOverrides?, // { amount: "$0.05" } for upto scheme ); ``` ### **Server Lifecycle Hooks** | Hook | Context | Can Abort/Recover | |:---:|:---:|:---:| | `onBeforeVerify` | `{ paymentPayload, requirements }` | `{ abort: true, reason, message? }` | | `onAfterVerify` | `{ paymentPayload, requirements, result }` | No | | `onVerifyFailure` | `{ paymentPayload, requirements, error }` | `{ recovered: true, result }` | | `onBeforeSettle` | `{ paymentPayload, requirements }` | `{ abort: true, reason, message? }` | | `onAfterSettle` | `{ paymentPayload, requirements, result, transportContext? }` | No | | `onSettleFailure` | `{ paymentPayload, requirements, error }` | `{ recovered: true, result }` | ```typescript server.onBeforeVerify(async (ctx) => { // Log or gate verification }); server.onAfterSettle(async (ctx) => { console.log(`Settled: ${ctx.result.transaction} on ${ctx.result.network}`); }); server.onSettleFailure(async (ctx) => { if (ctx.error.message.includes("timeout")) { return { recovered: true, result: { success: true, transaction: "", network: "eip155:196" } }; } }); ``` --- ## **HTTP Resource Server (`x402HTTPResourceServer`)** Higher-level wrapper that handles route matching, paywall, and HTTP-specific logic. ### **Constructor** ```typescript import { x402HTTPResourceServer } from "@okxweb3/x402-core/http"; const httpServer = new x402HTTPResourceServer(resourceServer, routes); ``` ### **RoutesConfig** ```typescript type RoutesConfig = Record | RouteConfig; interface RouteConfig { accepts: PaymentOption | PaymentOption[]; // Accepted payment methods resource?: string; // Override resource name description?: string; // Human-readable description mimeType?: string; // Response MIME type customPaywallHtml?: string; // Custom HTML for browser 402 page unpaidResponseBody?: (ctx: HTTPRequestContext) => HTTPResponseBody | Promise; settlementFailedResponseBody?: (ctx, result) => HTTPResponseBody | Promise; extensions?: Record; } interface PaymentOption { scheme: string; // "exact" | "aggr_deferred" | "upto" payTo: string | DynamicPayTo; // Static or dynamic recipient price: Price | DynamicPrice; // Static or dynamic price network: Network; maxTimeoutSeconds?: number; extra?: Record; } // Dynamic functions receive HTTPRequestContext type DynamicPayTo = (context: HTTPRequestContext) => string | Promise; type DynamicPrice = (context: HTTPRequestContext) => Price | Promise; ``` ### **PaywallConfig** ```typescript interface PaywallConfig { appName?: string; // Application name for paywall UI appLogo?: string; // Logo URL sessionTokenEndpoint?: string; currentUrl?: string; testnet?: boolean; // Show testnet branding } ``` ### **onSettlementTimeout(hook)** ```typescript type OnSettlementTimeoutHook = (txHash: string, network: string) => Promise<{ confirmed: boolean }>; httpServer.onSettlementTimeout(async (txHash, network) => { // Custom recovery logic return { confirmed: false }; }); ``` ### onProtectedRequest(hook) ```typescript type ProtectedRequestHook = ( context: HTTPRequestContext, routeConfig: RouteConfig, ) => Promise; httpServer.onProtectedRequest(async (ctx, config) => { // Grant free access for certain users if (ctx.adapter.getHeader("x-api-key") === "internal") { return { grantAccess: true }; } }); ``` --- ## Middleware Reference ### Express (`@okxweb3/x402-express`) ```typescript import { paymentMiddleware, paymentMiddlewareFromConfig, paymentMiddlewareFromHTTPServer, setSettlementOverrides, } from "@okxweb3/x402-express"; // From pre-configured server (recommended) app.use(paymentMiddleware(routes, server, paywallConfig?, paywall?, syncFacilitatorOnStart?)); // From config (creates server internally) app.use(paymentMiddlewareFromConfig(routes, facilitatorClients?, schemes?, paywallConfig?, paywall?, syncFacilitatorOnStart?)); // From HTTP server (most control) app.use(paymentMiddlewareFromHTTPServer(httpServer, paywallConfig?, paywall?, syncFacilitatorOnStart?)); // Settlement override in handler (for "upto" scheme) app.post("/api/generate", (req, res) => { setSettlementOverrides(res, { amount: "$0.05" }); res.json({ result: "..." }); }); ``` | Parameter | Type | Default | Description | |:---:|:---:|:---:|:---:| | `routes` | `RoutesConfig` | required | Route → payment config mapping | | `server` | `x402ResourceServer` | required | Pre-configured resource server | | `paywallConfig` | `PaywallConfig` | `undefined` | Browser paywall settings | | `paywall` | `PaywallProvider` | `undefined` | Custom paywall renderer | | `syncFacilitatorOnStart` | `boolean` | `true` | Fetch supported kinds on first request | ### Next.js (`@okxweb3/x402-next`) ```typescript import { paymentProxy, paymentProxyFromConfig, paymentProxyFromHTTPServer, withX402, withX402FromHTTPServer, } from "@okxweb3/x402-next"; // As global middleware (middleware.ts) const proxy = paymentProxy(routes, server, paywallConfig?, paywall?, syncFacilitatorOnStart?); export async function middleware(request: NextRequest) { return proxy(request); } export const config = { matcher: ["/api/:path*"] }; // Per-route wrapper (app/api/data/route.ts) export const GET = withX402(handler, routeConfig, server, paywallConfig?, paywall?, syncFacilitatorOnStart?); export const GET = withX402FromHTTPServer(handler, httpServer, paywallConfig?, paywall?, syncFacilitatorOnStart?); ``` ### Hono (`@okxweb3/x402-hono`) ```typescript import { paymentMiddleware, paymentMiddlewareFromConfig, paymentMiddlewareFromHTTPServer } from "@okxweb3/x402-hono"; app.use("/*", paymentMiddleware(routes, server, paywallConfig?, paywall?, syncFacilitatorOnStart?)); ``` ### Fastify (`@okxweb3/x402-fastify`) ```typescript import { paymentMiddleware, paymentMiddlewareFromConfig, paymentMiddlewareFromHTTPServer } from "@okxweb3/x402-fastify"; // NOTE: Fastify registers hooks directly, returns void paymentMiddleware(app, routes, server, paywallConfig?, paywall?, syncFacilitatorOnStart?); ``` --- ## EVM Mechanism Types ### ExactEvmScheme (Server) ```typescript import { ExactEvmScheme } from "@okxweb3/x402-evm/exact/server"; const scheme = new ExactEvmScheme(); // No constructor args for server-side scheme.scheme; // "exact" // Automatically handles price parsing, EIP-712 domain injection ``` ### AggrDeferredEvmScheme (Server) ```typescript import { AggrDeferredEvmScheme } from "@simongtest/x402-evm/deferred/server"; const scheme = new AggrDeferredEvmScheme(); scheme.scheme; // "aggr_deferred" // Delegates to ExactEvmScheme for price parsing ``` --- ## Error Classes ```typescript class VerifyError extends Error { readonly invalidReason?: string; readonly invalidMessage?: string; readonly payer?: string; readonly statusCode: number; } class SettleError extends Error { readonly errorReason?: string; readonly errorMessage?: string; readonly payer?: string; readonly transaction: string; readonly network: Network; readonly statusCode: number; } class FacilitatorResponseError extends Error {} class RouteConfigurationError extends Error { readonly errors: RouteValidationError[]; } interface RouteValidationError { routePattern: string; scheme: string; network: Network; reason: "missing_scheme" | "missing_facilitator"; message: string; } ``` - [Rust SDK Reference](https://web3.okx.com/onchainos/dev-docs/payments/sdk-rust.md) # Rust SDK Reference ## Crates | Crate | Description | |:---:|:---:| | `x402-core` | Core: server, facilitator client, types, HTTP utilities, HMAC auth | | `x402-axum` | Axum middleware (Tower Layer/Service) | | `x402-evm` | EVM mechanisms: exact, aggr_deferred | > The Rust SDK currently provides **server-side (seller)** and **facilitator client** functionality. Buyer-side payment signing is planned. --- ## Core Types ### Network / Money / Price ```rust pub type Network = String; // CAIP-2 format, e.g., "eip155:196" pub type Money = String; // User-friendly amount, e.g., "$0.01", "0.01" #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] pub enum Price { Money(Money), Asset(AssetAmount), } ``` ### AssetAmount ```rust #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct AssetAmount { pub asset: String, // Token contract address pub amount: String, // Amount in token's smallest unit #[serde(default, skip_serializing_if = "Option::is_none")] pub extra: Option>, } ``` ### ResourceInfo ```rust #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ResourceInfo { pub url: String, #[serde(default, skip_serializing_if = "Option::is_none")] pub description: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub mime_type: Option, } ``` ### PaymentRequirements ```rust #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct PaymentRequirements { pub scheme: String, // "exact" | "aggr_deferred" pub network: Network, // CAIP-2 identifier pub asset: String, // Token contract address pub amount: String, // Price in token's smallest unit pub pay_to: String, // Recipient wallet address pub max_timeout_seconds: u64, // Authorization validity window #[serde(default)] pub extra: HashMap, // Scheme-specific data } ``` ### PaymentRequired 402 response body. ```rust #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct PaymentRequired { #[serde(rename = "x402Version")] pub x402_version: u32, // Protocol version (2) #[serde(default, skip_serializing_if = "Option::is_none")] pub error: Option, pub resource: ResourceInfo, pub accepts: Vec, #[serde(default, skip_serializing_if = "Option::is_none")] pub extensions: Option>, } ``` ### PaymentPayload Client's signed payment. ```rust #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct PaymentPayload { #[serde(rename = "x402Version")] pub x402_version: u32, #[serde(default, skip_serializing_if = "Option::is_none")] pub resource: Option, pub accepted: PaymentRequirements, pub payload: HashMap, // Scheme-specific signed data #[serde(default, skip_serializing_if = "Option::is_none")] pub extensions: Option>, } ``` --- ## Facilitator Types ### VerifyRequest / VerifyResponse ```rust #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct VerifyRequest { #[serde(rename = "x402Version")] pub x402_version: u32, pub payment_payload: PaymentPayload, pub payment_requirements: PaymentRequirements, } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct VerifyResponse { pub is_valid: bool, #[serde(default, skip_serializing_if = "Option::is_none")] pub invalid_reason: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub invalid_message: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub payer: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub extensions: Option>, } ``` ### SettleRequest / SettleResponse ```rust #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct SettleRequest { #[serde(rename = "x402Version")] pub x402_version: u32, pub payment_payload: PaymentPayload, pub payment_requirements: PaymentRequirements, #[serde(default, skip_serializing_if = "Option::is_none")] pub sync_settle: Option, // OKX extension: wait for on-chain confirmation } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct SettleResponse { pub success: bool, #[serde(default, skip_serializing_if = "Option::is_none")] pub error_reason: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub error_message: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub payer: Option, pub transaction: String, // Tx hash (empty for aggr_deferred) pub network: Network, #[serde(default, skip_serializing_if = "Option::is_none")] pub amount: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub status: Option, // OKX: "pending" | "success" | "timeout" #[serde(default, skip_serializing_if = "Option::is_none")] pub extensions: Option>, } ``` ### SupportedKind / SupportedResponse ```rust #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct SupportedKind { #[serde(rename = "x402Version")] pub x402_version: u32, pub scheme: String, pub network: Network, #[serde(default, skip_serializing_if = "Option::is_none")] pub extra: Option>, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SupportedResponse { pub kinds: Vec, pub extensions: Vec, pub signers: HashMap>, } ``` ### SettleStatusResponse ```rust #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct SettleStatusResponse { pub success: bool, #[serde(default, skip_serializing_if = "Option::is_none")] pub error_reason: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub error_message: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub payer: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub transaction: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub network: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub status: Option, // "pending" | "success" | "failed" } ``` --- ## Traits ### SchemeNetworkServer Server-side scheme implementation. ```rust #[async_trait] pub trait SchemeNetworkServer: Send + Sync { fn scheme(&self) -> &str; async fn parse_price( &self, price: &Price, network: &Network, ) -> Result; async fn enhance_payment_requirements( &self, payment_requirements: PaymentRequirements, supported_kind: &SupportedKind, facilitator_extensions: &[String], ) -> Result; } ``` ### FacilitatorClient Network boundary for communicating with a remote facilitator. ```rust #[async_trait] pub trait FacilitatorClient: Send + Sync { async fn get_supported(&self) -> Result; async fn verify(&self, request: &VerifyRequest) -> Result; async fn settle(&self, request: &SettleRequest) -> Result; async fn get_settle_status(&self, tx_hash: &str) -> Result; } ``` ### ResourceServerExtension ```rust #[async_trait] pub trait ResourceServerExtension: Send + Sync { fn key(&self) -> &str; async fn enrich_payment_required( &self, payment_required: PaymentRequired, context: &PaymentRequiredContext, ) -> PaymentRequired; async fn enrich_verify_extensions( &self, extensions: HashMap, payment_payload: &PaymentPayload, payment_requirements: &PaymentRequirements, ) -> HashMap; async fn enrich_settle_extensions( &self, extensions: HashMap, payment_payload: &PaymentPayload, payment_requirements: &PaymentRequirements, ) -> HashMap; } pub struct PaymentRequiredContext { pub url: String, pub method: String, } pub struct SettleResultContext { pub url: String, pub method: String, pub payment_payload: PaymentPayload, pub payment_requirements: PaymentRequirements, pub settle_response: SettleResponse, } ``` ### FacilitatorExtension ```rust #[async_trait] pub trait FacilitatorExtension: Send + Sync { fn key(&self) -> &str; fn supported_networks(&self) -> Vec; } ``` --- ## Server API (`X402ResourceServer`) ### Constructor and Registration ```rust use x402_core::server::X402ResourceServer; use x402_evm::{ExactEvmScheme, AggrDeferredEvmScheme}; // register() uses builder pattern (consumes self, returns Self) let mut server = X402ResourceServer::new(facilitator) .register("eip155:196", ExactEvmScheme::new()) .register("eip155:196", AggrDeferredEvmScheme::new()); ``` ### Methods ```rust use std::collections::HashMap; use std::time::Duration; use x402_core::error::X402Error; use x402_core::facilitator::FacilitatorClient; use x402_core::http::{PollResult, SettlementOverrides}; use x402_core::server::X402ResourceServer; use x402_core::types::{ PaymentPayload, PaymentRequirements, ResourceInfo, SchemeNetworkServer, SettleResponse, SupportedResponse, VerifyResponse, }; impl X402ResourceServer { pub fn new(facilitator: impl FacilitatorClient + 'static) -> Self; pub fn register( mut self, network: &str, scheme: impl SchemeNetworkServer + 'static, ) -> Self; pub async fn initialize(&mut self) -> Result<(), X402Error>; pub fn supported(&self) -> Option<&SupportedResponse>; pub fn facilitator(&self) -> &dyn FacilitatorClient; pub async fn build_payment_requirements( &self, scheme: &str, // "exact" network: &str, // "eip155:196" price: &str, // "$0.01" pay_to: &str, // "0xSeller" max_timeout_seconds: u64, resource: &ResourceInfo, config_extra: Option<&HashMap>, ) -> Result; pub async fn verify_payment( &self, payment_payload: &PaymentPayload, payment_requirements: &PaymentRequirements, ) -> Result; pub async fn settle_payment( &self, payment_payload: &PaymentPayload, payment_requirements: &PaymentRequirements, sync_settle: Option, settlement_overrides: Option<&SettlementOverrides>, ) -> Result; pub async fn poll_settle_status( &self, tx_hash: &str, poll_interval: Duration, // DEFAULT_POLL_INTERVAL = 1s poll_deadline: Duration, // DEFAULT_POLL_DEADLINE = 5s ) -> PollResult; } ``` ### PollResult ```rust #[derive(Debug, Clone, PartialEq, Eq)] pub enum PollResult { Success, // Transaction confirmed on-chain Failed, // Transaction failed on-chain Timeout, // Polling deadline exceeded } ``` --- ## OKX Facilitator Client (`OkxHttpFacilitatorClient`) ```rust use x402_core::http::OkxHttpFacilitatorClient; // Default URL (https://web3.okx.com) let client = OkxHttpFacilitatorClient::new( "your-api-key", "your-secret-key", "your-passphrase", )?; ``` Implements `FacilitatorClient` trait. All requests include HMAC-SHA256 authentication. **Endpoints called:** | Method | OKX Path | |:---:|:---:| | `get_supported()` | `GET /api/v6/pay/x402/supported` | | `verify(request)` | `POST /api/v6/pay/x402/verify` | | `settle(request)` | `POST /api/v6/pay/x402/settle` | | `get_settle_status(tx_hash)` | `GET /api/v6/pay/x402/settle/status?txHash=...` | OKX responses are wrapped in `{"code": 0, "data": {...}, "msg": ""}` -- the client automatically unwraps. --- ## HMAC Authentication ```rust use x402_core::http::hmac::{sign_request, build_auth_headers}; // Sign a request let signature = sign_request(secret_key, timestamp, method, request_path, body); // Message = timestamp + METHOD + requestPath + body // Signature = Base64(HMAC-SHA256(secretKey, message)) // Build all auth headers let headers = build_auth_headers(api_key, secret_key, passphrase, method, request_path, body); // Returns: OK-ACCESS-KEY, OK-ACCESS-SIGN, OK-ACCESS-TIMESTAMP, OK-ACCESS-PASSPHRASE ``` --- ## HTTP Utilities ### Header Encoding/Decoding ```rust use x402_core::http::{ encode_payment_signature_header, decode_payment_signature_header, encode_payment_required_header, decode_payment_required_header, encode_payment_response_header, decode_payment_response_header, }; let encoded = encode_payment_required_header(&payment_required)?; // -> base64 string let decoded = decode_payment_required_header(&header_value)?; // -> PaymentRequired ``` ### Constants ```rust pub const DEFAULT_POLL_INTERVAL: Duration = Duration::from_secs(1); pub const DEFAULT_POLL_DEADLINE: Duration = Duration::from_secs(5); pub const PAYMENT_SIGNATURE_HEADER: &str = "PAYMENT-SIGNATURE"; pub const PAYMENT_REQUIRED_HEADER: &str = "PAYMENT-REQUIRED"; pub const PAYMENT_RESPONSE_HEADER: &str = "PAYMENT-RESPONSE"; ``` --- ## Route Configuration ```rust use x402_core::http::{RoutesConfig, RoutePaymentConfig, AcceptConfig}; use std::collections::HashMap; pub type RoutesConfig = HashMap; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct RoutePaymentConfig { pub accepts: Vec, // Accepted payment options pub description: String, // Resource description pub mime_type: String, // Response MIME type #[serde(default, skip_serializing_if = "Option::is_none")] pub sync_settle: Option, // Enable sync settlement } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct AcceptConfig { pub scheme: String, // "exact" | "aggr_deferred" pub price: String, // "$0.01" or token amount pub network: String, // "eip155:196" pub pay_to: String, // Recipient wallet #[serde(default, skip_serializing_if = "Option::is_none")] pub max_timeout_seconds: Option, // Default: 300s (5 min) #[serde(default, skip_serializing_if = "Option::is_none")] pub extra: Option>, // Scheme-specific metadata } ``` **Example:** ```rust use std::collections::HashMap; use x402_axum::{AcceptConfig, RoutePaymentConfig}; let mut routes = HashMap::new(); routes.insert("GET /api/data".to_string(), RoutePaymentConfig { accepts: vec![ AcceptConfig { scheme: "exact".to_string(), price: "$0.01".to_string(), network: "eip155:196".to_string(), pay_to: "0xSeller".to_string(), max_timeout_seconds: None, extra: None, }, AcceptConfig { scheme: "aggr_deferred".to_string(), price: "$0.001".to_string(), network: "eip155:196".to_string(), pay_to: "0xSeller".to_string(), max_timeout_seconds: None, extra: None, }, ], description: "Premium data".to_string(), mime_type: "application/json".to_string(), sync_settle: Some(true), }); ``` --- ## Axum Middleware (`x402-axum`) ### Basic Usage ```rust use std::time::Duration; use axum::{Router, routing::get}; use x402_axum::{ payment_middleware, payment_middleware_with_poll_deadline, payment_middleware_with_timeout_hook, payment_middleware_with_timeout_hook_and_deadline, OnSettlementTimeoutHook, RoutesConfig, }; use x402_core::server::X402ResourceServer; let app = Router::new() .route("/api/data", get(handler)) .layer(payment_middleware(routes, server)); ``` ### Construction Functions ```rust use std::time::Duration; use x402_axum::{ OnSettlementTimeoutHook, PaymentLayer, RoutesConfig, }; use x402_core::server::X402ResourceServer; // Basic middleware pub fn payment_middleware( routes: RoutesConfig, server: X402ResourceServer, ) -> PaymentLayer; // With custom poll deadline pub fn payment_middleware_with_poll_deadline( routes: RoutesConfig, server: X402ResourceServer, poll_deadline: Duration, ) -> PaymentLayer; // With settlement timeout recovery hook pub fn payment_middleware_with_timeout_hook( routes: RoutesConfig, server: X402ResourceServer, timeout_hook: OnSettlementTimeoutHook, ) -> PaymentLayer; // With both pub fn payment_middleware_with_timeout_hook_and_deadline( routes: RoutesConfig, server: X402ResourceServer, timeout_hook: OnSettlementTimeoutHook, poll_deadline: Duration, ) -> PaymentLayer; ``` ### OnSettlementTimeoutHook ```rust use std::pin::Pin; use std::future::Future; use x402_axum::{OnSettlementTimeoutHook, SettlementTimeoutResult}; pub struct SettlementTimeoutResult { pub confirmed: bool, } pub type OnSettlementTimeoutHook = Box< dyn Fn(String, String) -> Pin + Send>> + Send + Sync, >; // Usage: arguments are (tx_hash, network), not (route, tx_hash) let hook: OnSettlementTimeoutHook = Box::new(|tx_hash, network| { Box::pin(async move { tracing::warn!("Timeout for tx={} network={}", tx_hash, network); SettlementTimeoutResult { confirmed: false } }) }); ``` ### Middleware Flow 1. Check if route requires payment (`find_route_config`) 2. If no `payment-signature` header -> return 402 with `PAYMENT-REQUIRED` header 3. Decode and validate payment payload 4. Match payload against route's accepted requirements 5. Verify via facilitator (`POST /verify`) 6. Call inner handler and buffer response 7. Settle via facilitator (`POST /settle`) 8. If async (`status: "pending"`) -> poll with deadline 9. If timeout -> call timeout hook if configured 10. Add `PAYMENT-RESPONSE` header to response ### Re-exports ```rust pub use x402_core::http::{ AcceptConfig, BeforeHookResult, OnAfterSettleHook, OnAfterVerifyHook, OnBeforeSettleHook, OnBeforeVerifyHook, OnProtectedRequestHook, OnSettleFailureHook, OnSettlementTimeoutHook, OnVerifyFailureHook, PaymentResolverFn, PollResult, ProtectedRequestResult, RequestContext, ResolvedAccept, RoutePaymentConfig, RoutesConfig, SettleContext, SettleRecoveryResult, SettleResultContext, SettlementOverrides, SettlementTimeoutResult, VerifyContext, VerifyRecoveryResult, VerifyResultContext, DEFAULT_POLL_DEADLINE, DEFAULT_POLL_INTERVAL, SETTLEMENT_OVERRIDES_HEADER, }; pub use x402_core::server::X402ResourceServer; ``` --- ## EVM Mechanisms (`x402-evm`) ### ExactEvmScheme ```rust use x402_evm::ExactEvmScheme; let scheme = ExactEvmScheme::new(); scheme.scheme(); // "exact" ``` Handles: - Price parsing: `"$0.01"`, `"0.01"`, `AssetAmount` - Token amount conversion with correct decimals - Default asset lookup per network (USDC on Base, USDT on X Layer) - EIP-712 domain injection into `extra` for EIP-3009 tokens ### DeferredEvmScheme ```rust use x402_evm::AggrDeferredEvmScheme; let scheme = AggrDeferredEvmScheme::new(); scheme.scheme(); // "aggr_deferred" ``` Delegates to `ExactEvmScheme` for all price/requirement logic. Identical from the seller's perspective. ### EVM Payload Types ```rust #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum AssetTransferMethod { #[serde(rename = "eip3009")] Eip3009, Permit2, } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct EIP3009Authorization { pub from: String, pub to: String, pub value: String, pub valid_after: String, pub valid_before: String, pub nonce: String, } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ExactEIP3009Payload { #[serde(default, skip_serializing_if = "Option::is_none")] pub signature: Option, pub authorization: EIP3009Authorization, } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ExactPermit2Payload { pub signature: String, pub permit2_authorization: Permit2Authorization, } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] pub enum ExactEvmPayloadV2 { EIP3009(ExactEIP3009Payload), Permit2(ExactPermit2Payload), } impl ExactEvmPayloadV2 { pub fn is_permit2(&self) -> bool; pub fn is_eip3009(&self) -> bool; } ``` ### Asset Configuration ```rust #[derive(Debug, Clone)] pub struct DefaultAssetInfo { pub address: &'static str, // Token contract address pub name: &'static str, // EIP-712 domain name pub version: &'static str, // EIP-712 domain version pub decimals: u8, // Token decimal places pub asset_transfer_method: Option<&'static str>, // "permit2" override pub supports_eip2612: bool, // EIP-2612 permit() support } #[derive(Debug, Clone)] pub struct ChainConfig { pub network: &'static str, // CAIP-2 identifier pub chain_id: u64, } // Pre-registered assets: // BASE_MAINNET_USDC: eip155:8453, 0x833589..., 6 decimals // BASE_SEPOLIA_USDC: eip155:84532, 0x036CbD..., 6 decimals // XLAYER_MAINNET_USDT: eip155:196, 0x779ded..., 6 decimals, name: "USD₮0" // XLAYER_TESTNET_USDT: eip155:195, TBD pub fn default_stablecoins() -> HashMap<&'static str, DefaultAssetInfo>; pub fn get_default_asset(network: &str) -> Option; ``` --- ## Error Types ```rust #[derive(Debug, thiserror::Error)] pub enum X402Error { #[error(transparent)] Verify(#[from] VerifyError), #[error(transparent)] Settle(#[from] SettleError), #[error(transparent)] FacilitatorResponse(#[from] FacilitatorResponseError), #[error("configuration error: {0}")] Config(String), #[error("route configuration error: {0}")] RouteConfig(String), #[error("unsupported scheme: {0}")] UnsupportedScheme(String), #[error("unsupported network: {0}")] UnsupportedNetwork(String), #[error("price parse error: {0}")] PriceParse(String), #[error("not initialized: {0}")] NotInitialized(String), #[error("http error: {0}")] Http(#[from] reqwest::Error), #[error("serialization error: {0}")] Serialization(#[from] serde_json::Error), #[error("base64 decode error: {0}")] Base64Decode(#[from] base64::DecodeError), #[error("{0}")] Other(String), } #[derive(Debug, Clone, thiserror::Error)] pub struct VerifyError { pub status_code: u16, pub invalid_reason: Option, pub invalid_message: Option, pub payer: Option, } #[derive(Debug, Clone, thiserror::Error)] pub struct SettleError { pub status_code: u16, pub error_reason: Option, pub error_message: Option, pub payer: Option, pub transaction: String, pub network: Network, } #[derive(Debug, Clone, thiserror::Error)] pub struct FacilitatorResponseError(pub String); ``` --- ## Utility Functions ```rust pub fn safe_base64_encode(data: &str) -> String; pub fn safe_base64_decode(data: &str) -> Result; // Network pattern matching: "eip155:*" matches "eip155:196" pub fn network_matches_pattern(network: &str, pattern: &str) -> bool; pub fn find_schemes_by_network<'a, T>( map: &'a HashMap>, network: &str, ) -> Option<&'a HashMap>; pub fn find_by_network_and_scheme<'a, T>( map: &'a HashMap>, scheme: &str, network: &str, ) -> Option<&'a T>; pub fn deep_equal(obj1: &serde_json::Value, obj2: &serde_json::Value) -> bool; ``` --- ## Schema Validation ```rust pub fn validate_payment_requirements(req: &PaymentRequirements) -> Result<(), X402Error>; pub fn validate_payment_payload(payload: &PaymentPayload) -> Result<(), X402Error>; pub fn validate_payment_required(required: &PaymentRequired) -> Result<(), X402Error>; ``` Validates that all required fields are non-empty. - [Go SDK Reference](https://web3.okx.com/onchainos/dev-docs/payments/sdk-go.md) # Go SDK Reference ## Packages | Package | Description | |:---:|:---:| | `github.com/anthropics/x402/go` | Core: client, server, facilitator, types | | `.../go/mechanisms/evm` | EVM mechanisms: exact, aggr_deferred | | `.../go/mechanisms/svm` | Solana mechanisms: exact | | `.../go/http/gin` | Gin middleware (seller) | | `.../go/http/echo` | Echo middleware (seller) | | `.../go/http/nethttp` | net/http middleware (seller) | | `.../go/http` | HTTP client wrapper (buyer) | --- ## Core Types ### Network ```go type Network string // CAIP-2 format, e.g., "eip155:196", "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp" func (n Network) Parse() (namespace, reference string, err error) func (n Network) Match(pattern Network) bool ``` ### Price / AssetAmount ```go type Price interface{} // Can be string ("$0.01"), number (0.01), or map (AssetAmount) type AssetAmount struct { Asset string `json:"asset"` // Token contract address Amount string `json:"amount"` // Smallest unit amount Extra map[string]interface{} `json:"extra,omitempty"` } ``` ### ResourceConfig ```go type ResourceConfig struct { Scheme string `json:"scheme"` // "exact" | "aggr_deferred" | "upto" PayTo string `json:"payTo"` // Recipient wallet Price Price `json:"price"` // "$0.01" or AssetAmount Network Network `json:"network"` // "eip155:196" MaxTimeoutSeconds int `json:"maxTimeoutSeconds,omitempty"` // Default: 60 Extra map[string]interface{} `json:"extra,omitempty"` } ``` ### VerifyResponse ```go type VerifyResponse struct { IsValid bool `json:"isValid"` InvalidReason string `json:"invalidReason,omitempty"` InvalidMessage string `json:"invalidMessage,omitempty"` Payer string `json:"payer,omitempty"` } ``` ### SettleResponse ```go type SettleResponse struct { Success bool `json:"success"` ErrorReason string `json:"errorReason,omitempty"` ErrorMessage string `json:"errorMessage,omitempty"` Payer string `json:"payer,omitempty"` Transaction string `json:"transaction"` Network Network `json:"network"` Status string `json:"status,omitempty"` // OKX: "pending" | "success" | "timeout" } ``` ### SupportedResponse ```go type SupportedKind struct { X402Version int `json:"x402Version"` Scheme string `json:"scheme"` Network Network `json:"network"` Extra map[string]interface{} `json:"extra,omitempty"` } type SupportedResponse struct { Kinds []SupportedKind `json:"kinds"` Extensions []string `json:"extensions"` Signers map[string][]string `json:"signers"` // CAIP family -> addresses } ``` ### SettlementOverrides ```go type SettlementOverrides struct { Amount string `json:"amount,omitempty"` // Atomic units, percentage, or dollar } ``` --- ## View Interfaces Unified view for V1/V2 payment data: ```go type PaymentRequirementsView interface { GetScheme() string GetNetwork() string GetAsset() string GetAmount() string GetPayTo() string GetMaxTimeoutSeconds() int GetExtra() map[string]interface{} } type PaymentPayloadView interface { GetVersion() int GetScheme() string GetNetwork() string GetPayload() map[string]interface{} } ``` --- ## Client API (`x402Client`) ### Constructor ```go import x402 "github.com/anthropics/x402/go" client := x402.Newx402Client(opts ...ClientOption) ``` ClientOption functions: | Option | Description | |:---:|:---:| | `WithPaymentSelector(selector)` | Custom payment requirements selector | | `WithPolicy(policy)` | Add a payment filtering policy | ### Register Methods (Chainable) ```go func (c *x402Client) Register(network Network, client SchemeNetworkClient) *x402Client func (c *x402Client) RegisterV1(network Network, client SchemeNetworkClientV1) *x402Client func (c *x402Client) RegisterPolicy(policy PaymentPolicy) *x402Client func (c *x402Client) RegisterExtension(ext ClientExtension) *x402Client ``` ### Payment Creation ```go // Select best payment option from requirements list func (c *x402Client) SelectPaymentRequirements( requirements []types.PaymentRequirements, ) (types.PaymentRequirements, error) // Create signed payment payload func (c *x402Client) CreatePaymentPayload( ctx context.Context, requirements types.PaymentRequirements, resource *types.ResourceInfo, extensions map[string]interface{}, ) (types.PaymentPayload, error) ``` ### Lifecycle Hooks (Chainable) ```go func (c *x402Client) OnBeforePaymentCreation(hook BeforePaymentCreationHook) *x402Client func (c *x402Client) OnAfterPaymentCreation(hook AfterPaymentCreationHook) *x402Client func (c *x402Client) OnPaymentCreationFailure(hook OnPaymentCreationFailureHook) *x402Client ``` ### Policy and Selector Types ```go type PaymentRequirementsSelector func(requirements []PaymentRequirementsView) PaymentRequirementsView type PaymentPolicy func(requirements []PaymentRequirementsView) []PaymentRequirementsView func DefaultPaymentSelector(requirements []PaymentRequirementsView) PaymentRequirementsView ``` --- ## Server API (`x402ResourceServer`) ### Constructor ```go server := x402.Newx402ResourceServer(opts ...ResourceServerOption) ``` ResourceServerOption functions: | Option | Description | |:---:|:---:| | `WithFacilitatorClient(client)` | Set facilitator client | | `WithSchemeServer(network, server)` | Register a scheme | | `WithCacheTTL(ttl)` | Set supported-kinds cache TTL | ### Register Methods (Chainable) ```go func (s *x402ResourceServer) Register(network Network, server SchemeNetworkServer) *x402ResourceServer func (s *x402ResourceServer) RegisterExtension(ext types.ResourceServerExtension) *x402ResourceServer ``` ### Initialization ```go func (s *x402ResourceServer) Initialize(ctx context.Context) error ``` ### Payment Operations ```go // Build requirements from config func (s *x402ResourceServer) BuildPaymentRequirementsFromConfig( ctx context.Context, config ResourceConfig, ) ([]types.PaymentRequirements, error) // Build single requirement func (s *x402ResourceServer) BuildPaymentRequirements( ctx context.Context, config ResourceConfig, supportedKind types.SupportedKind, extensions []string, ) (types.PaymentRequirements, error) // Create 402 response func (s *x402ResourceServer) CreatePaymentRequiredResponse( requirements []types.PaymentRequirements, resourceInfo *types.ResourceInfo, errorMsg string, extensions map[string]interface{}, ) types.PaymentRequired // Find matching requirements for a payment payload func (s *x402ResourceServer) FindMatchingRequirements( available []types.PaymentRequirements, payload types.PaymentPayload, ) *types.PaymentRequirements // Verify payment signature func (s *x402ResourceServer) VerifyPayment( ctx context.Context, payload types.PaymentPayload, requirements types.PaymentRequirements, ) (*VerifyResponse, error) // Settle payment on-chain func (s *x402ResourceServer) SettlePayment( ctx context.Context, payload types.PaymentPayload, requirements types.PaymentRequirements, overrides *SettlementOverrides, ) (*SettleResponse, error) // Check registered support func (s *x402ResourceServer) HasRegisteredScheme(network Network, scheme string) bool func (s *x402ResourceServer) HasFacilitatorSupport(network Network, scheme string) bool ``` ### Server Lifecycle Hooks (Chainable) ```go func (s *x402ResourceServer) OnBeforeVerify(hook BeforeVerifyHook) *x402ResourceServer func (s *x402ResourceServer) OnAfterVerify(hook AfterVerifyHook) *x402ResourceServer func (s *x402ResourceServer) OnVerifyFailure(hook OnVerifyFailureHook) *x402ResourceServer func (s *x402ResourceServer) OnBeforeSettle(hook BeforeSettleHook) *x402ResourceServer func (s *x402ResourceServer) OnAfterSettle(hook AfterSettleHook) *x402ResourceServer func (s *x402ResourceServer) OnSettleFailure(hook OnSettleFailureHook) *x402ResourceServer ``` --- ## Scheme Interfaces ### SchemeNetworkClient (Buyer) ```go type SchemeNetworkClient interface { Scheme() string CreatePaymentPayload(ctx context.Context, requirements types.PaymentRequirements) (types.PaymentPayload, error) } type ExtensionAwareClient interface { SchemeNetworkClient CreatePaymentPayloadWithExtensions(ctx context.Context, requirements types.PaymentRequirements, extensions map[string]interface{}) (types.PaymentPayload, error) } ``` ### SchemeNetworkServer (Seller) ```go type SchemeNetworkServer interface { Scheme() string ParsePrice(price Price, network Network) (AssetAmount, error) EnhancePaymentRequirements(ctx context.Context, requirements types.PaymentRequirements, supportedKind types.SupportedKind, extensions []string) (types.PaymentRequirements, error) } ``` ### SchemeNetworkFacilitator ```go type SchemeNetworkFacilitator interface { Scheme() string CaipFamily() string GetExtra(network Network) map[string]interface{} GetSigners(network Network) []string Verify(ctx context.Context, payload types.PaymentPayload, requirements types.PaymentRequirements, fctx *FacilitatorContext) (*VerifyResponse, error) Settle(ctx context.Context, payload types.PaymentPayload, requirements types.PaymentRequirements, fctx *FacilitatorContext) (*SettleResponse, error) } ``` ### FacilitatorClient (Network Boundary) ```go type FacilitatorClient interface { Verify(ctx context.Context, payloadBytes []byte, requirementsBytes []byte) (*VerifyResponse, error) Settle(ctx context.Context, payloadBytes []byte, requirementsBytes []byte) (*SettleResponse, error) GetSupported(ctx context.Context) (SupportedResponse, error) } ``` ### ClientExtension ```go type ClientExtension interface { Key() string EnrichPaymentPayload(ctx context.Context, payload types.PaymentPayload, required types.PaymentRequired) (types.PaymentPayload, error) } ``` ### MoneyParser ```go type MoneyParser func(amount float64, network Network) (*AssetAmount, error) ``` --- ## Middleware Reference All Go middleware packages provide three construction levels plus builder shortcuts. ### Gin (`go/http/gin`) ```go import x402gin "github.com/anthropics/x402/go/http/gin" // Standard (recommended) r.Use(x402gin.PaymentMiddleware(routes, server, opts ...MiddlewareOption)) // From HTTP server r.Use(x402gin.PaymentMiddlewareFromHTTPServer(httpServer, opts ...MiddlewareOption)) // From config r.Use(x402gin.PaymentMiddlewareFromConfig(routes, opts ...MiddlewareOption)) // Builder shortcut r.Use(x402gin.X402Payment(Config{ Routes: routes, Facilitator: facilitator, Schemes: schemes })) // Simple one-liner r.Use(x402gin.SimpleX402Payment(payTo, price, network, facilitatorURL)) ``` MiddlewareOption functions: | Option | Type | Description | |:---:|:---:|:---:| | `WithFacilitatorClient(client)` | `FacilitatorClient` | Facilitator for verification/settlement | | `WithScheme(network, server)` | `Network, SchemeNetworkServer` | Register a scheme | | `WithPaywallConfig(config)` | `*PaywallConfig` | Browser paywall settings | | `WithSyncFacilitatorOnStart(bool)` | `bool` | Fetch supported kinds at startup | | `WithErrorHandler(fn)` | `func(*gin.Context, error)` | Custom error handler | | `WithSettlementHandler(fn)` | `func(*gin.Context, *SettleResponse)` | Custom settlement handler | | `WithTimeout(duration)` | `time.Duration` | Request timeout | Config struct (builder pattern): ```go type Config struct { Routes x402http.RoutesConfig Facilitator x402.FacilitatorClient Facilitators []x402.FacilitatorClient Schemes []SchemeConfig PaywallConfig *x402http.PaywallConfig SyncFacilitatorOnStart bool Timeout time.Duration ErrorHandler func(*gin.Context, error) SettlementHandler func(*gin.Context, *x402.SettleResponse) } type SchemeConfig struct { Network x402.Network Server x402.SchemeNetworkServer } ``` ### Echo (`go/http/echo`) Same API surface as Gin but with `echo.Context` types: ```go import x402echo "github.com/anthropics/x402/go/http/echo" e.Use(x402echo.PaymentMiddleware(routes, server, opts ...MiddlewareOption)) e.Use(x402echo.X402Payment(Config{ ... })) e.Use(x402echo.SimpleX402Payment(payTo, price, network, facilitatorURL)) ``` ### net/http (`go/http/nethttp`) Returns `func(http.Handler) http.Handler`: ```go import x402nethttp "github.com/anthropics/x402/go/http/nethttp" handler := x402nethttp.PaymentMiddleware(routes, server, opts ...MiddlewareOption)(yourHandler) handler := x402nethttp.X402Payment(Config{ ... })(yourHandler) handler := x402nethttp.SimpleX402Payment(payTo, price, network, facilitatorURL)(yourHandler) http.ListenAndServe(":4021", handler) ``` --- ## HTTP Client (Buyer) ```go import x402http "github.com/anthropics/x402/go/http" // Create HTTP client with payment support httpClient := x402http.Newx402HTTPClient(x402Client) // Wrap existing http.Client wrappedClient := x402http.WrapHTTPClientWithPayment(http.DefaultClient, httpClient) // Direct methods resp, err := httpClient.GetWithPayment(ctx, url) resp, err := httpClient.PostWithPayment(ctx, url, body) resp, err := httpClient.DoWithPayment(ctx, req) // Convenience functions resp, err := x402http.Get(ctx, url, httpClient) resp, err := x402http.Post(ctx, url, body, httpClient) resp, err := x402http.Do(ctx, req, httpClient) ``` --- ## EVM Mechanisms ### ExactEvmScheme (Client) ```go import ( "github.com/anthropics/x402/go/mechanisms/evm" evmsigners "github.com/anthropics/x402/go/mechanisms/evm/signers" evmclient "github.com/anthropics/x402/go/mechanisms/evm/exact/client" ) signer, err := evmsigners.NewClientSignerFromPrivateKey("0x...") scheme := evmclient.NewExactEvmScheme(signer, config) scheme.Scheme() // "exact" ``` ClientEvmSigner interface: ```go type ClientEvmSigner interface { Address() string SignTypedData(ctx context.Context, domain TypedDataDomain, types map[string][]TypedDataField, primaryType string, message map[string]interface{}) ([]byte, error) } ``` ### ExactEvmScheme (Server) ```go import evmserver "github.com/anthropics/x402/go/mechanisms/evm/exact/server" scheme := evmserver.NewExactEvmScheme() scheme.RegisterMoneyParser(customParser) // Optional: custom price parsing scheme.Scheme() // "exact" ``` ### ExactEvmScheme (Facilitator) ```go import evmfacilitator "github.com/anthropics/x402/go/mechanisms/evm/exact/facilitator" scheme := evmfacilitator.NewExactEvmScheme(signer, &ExactEvmSchemeConfig{ DeployERC4337WithEIP6492: false, // Auto-deploy smart wallets SimulateInSettle: false, // Re-simulate during settle }) ``` ### EVM Types ```go type TypedDataDomain struct { Name string `json:"name"` Version string `json:"version"` ChainID *big.Int `json:"chainId"` VerifyingContract string `json:"verifyingContract"` } type TypedDataField struct { Name string `json:"name"` Type string `json:"type"` } type AssetTransferMethod string const ( AssetTransferMethodEIP3009 AssetTransferMethod = "eip3009" AssetTransferMethodPermit2 AssetTransferMethod = "permit2" ) type AssetInfo struct { Address string Name string Version string Decimals int AssetTransferMethod AssetTransferMethod SupportsEip2612 bool } ``` --- ## SVM Mechanisms ### ExactSvmScheme (Client) ```go import ( svmsigners "github.com/anthropics/x402/go/mechanisms/svm/signers" svmclient "github.com/anthropics/x402/go/mechanisms/svm/exact/client" ) signer, err := svmsigners.NewClientSignerFromPrivateKey(solanaPrivateKey) scheme := svmclient.NewExactSvmScheme(signer, config?) ``` ### ExactSvmScheme (Server) ```go import svmserver "github.com/anthropics/x402/go/mechanisms/svm/exact/server" scheme := svmserver.NewExactSvmScheme() scheme.RegisterMoneyParser(customParser) ``` --- ## Facilitator Hooks ```go type FacilitatorVerifyContext struct { Ctx context.Context Payload PaymentPayloadView Requirements PaymentRequirementsView PayloadBytes []byte RequirementsBytes []byte } type FacilitatorBeforeHookResult struct { Abort bool Reason string Message string } type FacilitatorBeforeVerifyHook func(FacilitatorVerifyContext) (*FacilitatorBeforeHookResult, error) type FacilitatorAfterVerifyHook func(FacilitatorVerifyResultContext) error type FacilitatorOnVerifyFailureHook func(FacilitatorVerifyFailureContext) (*FacilitatorVerifyFailureHookResult, error) type FacilitatorBeforeSettleHook func(FacilitatorSettleContext) (*FacilitatorBeforeHookResult, error) type FacilitatorAfterSettleHook func(FacilitatorSettleResultContext) error type FacilitatorOnSettleFailureHook func(FacilitatorSettleFailureContext) (*FacilitatorSettleFailureHookResult, error) ``` - [Authentication](https://web3.okx.com/onchainos/dev-docs/payments/api-authentication.md) # Authentication All endpoints require API Key authentication. Include the following fields in the request header: | Header | Required | Description | | :---: | :---: | :---: | | `OK-ACCESS-KEY` | Yes | API Key | | `OK-ACCESS-SIGN` | Yes | Request signature | | `OK-ACCESS-PASSPHRASE` | Yes | API passphrase | | `OK-ACCESS-TIMESTAMP` | Yes | ISO 8601 timestamp | | `Content-Type` | Yes | Must be set to `application/json` for POST requests | - [Get Supported Info](https://web3.okx.com/onchainos/dev-docs/payments/get-supported-schemes-and-networks.md) # Get Supported Info Query the list of schemes, networks, and signers supported by the Facilitator. The Seller SDK calls this endpoint to build the `accepts` array for the `402` response. ## Request URL GET `/api/v6/pay/x402/supported` Request Parameters: None ### Response Parameters | Parameter | Type | Description | |:---:|:---:|:---:| | kinds | Array\ | List of supported payment types | | kinds[].x402Version | Integer | x402 protocol version, e.g. `2` | | kinds[].scheme | String | Settlement scheme: `exact` (one-time payment with a fixed amount) / `aggr_deferred` (deferred aggregated settlement) | | kinds[].network | String | CAIP-2 chain identifier, e.g. `eip155:196` (X Layer) | | kinds[].extra | Object | Scheme-specific extended configuration (optional) | | extensions | Array\ | List of supported extension identifiers | | signers | Object | CAIP-2 wildcard to signer address array mapping | ### Request Example ```bash curl --location --request GET 'https://web3.okx.com/api/v6/pay/x402/supported' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response Example ```json { "code": "0", "data": { "kinds": [ { "x402Version": 2, "scheme": "exact", "network": "eip155:196", "extra": null }, { "x402Version": 2, "scheme": "aggr_deferred", "network": "eip155:196", "extra": null } ], "extensions": [], "signers": { "eip155:*": ["0x...facilitatorSignerAddress"] } }, "msg": "" } ``` - [Verify Transaction](https://web3.okx.com/onchainos/dev-docs/payments/payment-verification.md) # Verify Transaction Verify the validity of a payment authorization **without executing an on-chain transaction**. The Seller calls this endpoint to confirm the legitimacy of the Buyer's signature before releasing the resource. ## Request URL POST `/api/v6/pay/x402/verify` ### Request Parameters | Parameter | Type | Required | Description | |:---:|:---:|:---:|:---:| | x402Version | Integer | Yes | x402 protocol version, e.g. `2` | | paymentPayload | Object | Yes | The x402 payment payload carried by the client with the protected request. See PaymentPayload for details | | paymentRequirements | Object | Yes | Payment requirements defined by the Seller. See PaymentRequirements for details | ### Response Parameters | Parameter | Type | Description | |:---:|:---:|:---:| | isValid | Boolean | `true` if verification passed, `false` if verification failed | | invalidReason | String | Machine-readable reason for invalidity (returned on verification failure), e.g. `insufficient_funds` | | invalidMessage | String | Human-readable description of invalidity (returned on verification failure) | | payer | String | Payer wallet address | ### Request Example ```bash curl --location --request POST 'https://web3.okx.com/api/v6/pay/x402/verify' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data '{ "x402Version": 2, "paymentPayload": { "x402Version": 2, "resource": { "url": "https://api.example.com/premium-data", "description": "Access to premium data", "mimeType": "application/json" }, "accepted": { "scheme": "exact", "network": "eip155:196", "amount": "10000", "asset": "0x4ae46a509f6b1d9056937ba4500cb143933d2dc8", "payTo": "0xRecipientAddress", "maxTimeoutSeconds": 60, "extra": { "name": "USDG", "version": "2" } }, "payload": { "signature": "0xf3746613c2d920b5fdabc0856f2aeb2d4f88ee6037b8cc5d04a71a4462f13480...", "authorization": { "from": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "to": "0xRecipientAddress", "value": "10000", "validAfter": "0", "validBefore": "1740672154", "nonce": "0xf374661..." } } }, "paymentRequirements": { "scheme": "exact", "network": "eip155:196", "amount": "10000", "asset": "0x4ae46a509f6b1d9056937ba4500cb143933d2dc8", "payTo": "0xRecipientAddress", "maxTimeoutSeconds": 60, "extra": { "name": "USDG", "version": "2" } } }' ``` ### Response Example -- Verification Passed ```json { "code": "0", "msg": "success", "data": { "isValid": true, "invalidReason": null, "invalidMessage": null, "payer": "0xcb30ed083ad246b126a3aa1f414b44346e83e67d" } } ``` ### Response Example -- Verification Failed ```json { "code": "0", "msg": "success", "data": { "isValid": false, "invalidReason": "insufficient_funds", "invalidMessage": "Payer balance is below required amount", "payer": "0xcb30ed083ad246b126a3aa1f414b44346e83e67d" } } ``` - [Settle Transaction](https://web3.okx.com/onchainos/dev-docs/payments/payment-settlement.md) # Settle Transaction After verification passes, submit on-chain settlement. Aligned with Coinbase V2 protocol + OKX extension field `syncSettle`. ## Request URL POST `/api/v6/pay/x402/settle` ## Request Parameters | Parameter | Type | Required | Description | |:---:|:---:|:---:|:---:| | x402Version | Integer | Yes | x402 protocol version, e.g. `2` | | paymentPayload | Object | Yes | x402 payment payload carried by the client. See PaymentPayload for details | | paymentRequirements | Object | Yes | Payment requirements defined by the seller. See PaymentRequirements for details | | syncSettle | Boolean | No | OKX extension. `true` = wait synchronously for on-chain confirmation before returning; `false` (default) = asynchronous, returns immediately after broadcast. Only effective for the `exact` scheme | ## Response Parameters | Parameter | Type | Description | |:---:|:---:|:---:| | success | Boolean | Whether the settlement succeeded | | errorReason | String | Machine-readable failure reason (returned on failure) | | errorMessage | String | Human-readable failure description (returned on failure) | | payer | String | Payer wallet address | | transaction | String | On-chain transaction hash (returned on `exact` success; empty string for `deferred`) | | network | String | CAIP-2 chain identifier, e.g. `eip155:196` | | status | String | OKX extension. Settlement status; see the status table below | ## status Values | scheme | syncSettle | Result | status Value | transaction | |:---:|:---:|:---:|:---:|:---:| | exact | false (default) | Broadcast | `pending` | txHash | | exact | true | On-chain confirmation succeeded | `success` | txHash | | exact | true | Wait timed out | `timeout` | txHash | | aggr_deferred | — | Stored | `success` | Empty string | ## Request Example ```bash curl --location --request POST 'https://web3.okx.com/api/v6/pay/x402/settle' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data '{ "x402Version": 2, "paymentPayload": { "x402Version": 2, "resource": { "url": "https://api.example.com/premium-data", "description": "Access to premium data", "mimeType": "application/json" }, "accepted": { "scheme": "exact", "network": "eip155:196", "amount": "10000", "asset": "0x4ae46a509f6b1d9056937ba4500cb143933d2dc8", "payTo": "0xRecipientAddress", "maxTimeoutSeconds": 60, "extra": { "name": "USDG", "version": "2" } }, "payload": { "signature": "0xf3746613c2d920b5fdabc0856f2aeb2d4f88ee6037b8cc5d04a71a4462f13480...", "authorization": { "from": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "to": "0xRecipientAddress", "value": "10000", "validAfter": "0", "validBefore": "1740672154", "nonce": "0xf374661..." } } }, "paymentRequirements": { "scheme": "exact", "network": "eip155:196", "amount": "10000", "asset": "0x4ae46a509f6b1d9056937ba4500cb143933d2dc8", "payTo": "0xRecipientAddress", "maxTimeoutSeconds": 60, "extra": { "name": "USDG", "version": "2" } }, "syncSettle": true }' ``` ## Response Example - Synchronous Settlement (syncSettle=true) ```json { "code": "0", "msg": "success", "data": { "success": true, "errorReason": null, "errorMessage": null, "payer": "0xcb30ed083ad246b126a3aa1f414b44346e83e67d", "transaction": "0x4f46ed8eac92ddbccfb56a88ff827db3616c7beb191adabbeeded901340bd7d5", "network": "eip155:196", "status": "success" } } ``` ## Response Example - Asynchronous Settlement (syncSettle=false) ```json { "code": "0", "msg": "success", "data": { "success": true, "errorReason": null, "errorMessage": null, "payer": "0xcb30ed083ad246b126a3aa1f414b44346e83e67d", "transaction": "0x4f46ed8eac92ddbccfb56a88ff827db3616c7beb191adabbeeded901340bd7d5", "network": "eip155:196", "status": "pending" } } ``` ## Response Example - Settlement Failed ```json { "code": "0", "msg": "success", "data": { "success": false, "errorReason": "insufficient_funds", "errorMessage": "Transaction reverted", "payer": "0xcb30ed083ad246b126a3aa1f414b44346e83e67d", "transaction": "", "network": "eip155:196", "status": "" } } ``` - [Query Settlement Status](https://web3.okx.com/onchainos/dev-docs/payments/api-query-settlement-status.md) # Query Settlement Status Query settlement status by on-chain transaction hash. Applicable to `exact` (`syncSettle=false`) one-time payments asynchronous settlement scenarios and status tracking after `aggr_deferred` batch payments submission. ## Request URL GET `/api/v6/pay/x402/settle/status` ## Request Parameters | Parameter | Type | Required | Description | |:---:|:---:|:---:|:---:| | txHash | String | Yes | On-chain transaction hash (Query parameter) | ## Response Parameters | Parameter | Type | Description | |:---:|:---:|:---:| | success | Boolean | Whether the query succeeded (`false` when txHash does not exist) | | errorReason | String | Machine-readable failure reason (returned on failure) | | errorMessage | String | Human-readable failure description (returned on failure) | | payer | String | Payer wallet address | | transaction | String | On-chain transaction hash | | network | String | CAIP-2 chain identifier | | status | String | Current settlement status | ## status Values | status | Meaning | |:---:|:---:| | `pending` | Processing, not yet finalized | | `success` | On-chain transaction succeeded | | `failed` | On-chain transaction failed | ## Request Example ```bash curl --location --request GET 'https://web3.okx.com/api/v6/pay/x402/settle/status?txHash=0x4f46ed8eac92ddbccfb56a88ff827db3616c7beb191adabbeeded901340bd7d5' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example -- Query Succeeded ```json { "code": "0", "msg": "success", "data": { "success": true, "errorReason": null, "errorMessage": null, "payer": "0xcb30ed083ad246b126a3aa1f414b44346e83e67d", "transaction": "0x4f46ed8eac92ddbccfb56a88ff827db3616c7beb191adabbeeded901340bd7d5", "network": "eip155:196", "status": "success" } } ``` ## Response Example -- Transaction Not Found ```json { "code": "0", "msg": "success", "data": { "success": false, "errorReason": "not_found", "errorMessage": "Transaction not found for txHash: 0xabc123...", "payer": null, "transaction": null, "network": null, "status": null } } ``` - [Common Data Structures](https://web3.okx.com/onchainos/dev-docs/payments/api-common-data-structures.md) # Common Data Structures ## PaymentPayload After signing, the Buyer passes this to the Seller via the `X-PAYMENT` header (base64-encoded), and the Seller forwards it as-is to the Facilitator. | Parameter | Type | Required | Description | |:---:|:---:|:---:|:---:| | x402Version | Integer | Yes | Protocol version, e.g. `2` | | resource | Object | No | Protected resource description | | resource.url | String | Yes | URL of the protected resource | | resource.description | String | No | Resource description | | resource.mimeType | String | No | Expected response MIME type | | accepted | Object | Yes | Payment method selected by the Buyer (picked from the `accepts` array), structure identical to PaymentRequirements | | payload | Object | Yes | Signed data | | payload.signature | String | Yes | EIP-712 signature. `exact`: EOA signature; `aggr_deferred`: session key signature | | payload.authorization | Object | Yes | EIP-3009 authorization parameters | ## Authorization | Parameter | Type | Required | Description | |:---:|:---:|:---:|:---:| | from | String | Yes | Payer wallet address | | to | String | Yes | Payee wallet address | | value | String | Yes | Payment amount (atomic units, with precision) | | validAfter | String | Yes | Unix timestamp when the authorization becomes valid | | validBefore | String | Yes | Unix timestamp when the authorization expires | | nonce | String | Yes | 32-byte random nonce (0x hex format, replay protection) | ## PaymentRequirements Used both as an element of the 402 response `accepts` array and as `paymentPayload.accepted`. | Parameter | Type | Required | Description | |:---:|:---:|:---:|:---:| | scheme | String | Yes | Settlement scheme: `exact` / `aggr_deferred` | | network | String | Yes | CAIP-2 chain identifier, e.g. `eip155:196` | | amount | String | Yes | Payment amount (atomic unit string) | | asset | String | Yes | Token contract address | | payTo | String | Yes | Payee wallet address | | maxTimeoutSeconds | Integer | No | Maximum timeout for payment completion (seconds) | | extra | Object | No | Scheme-specific extensions. For `aggr_deferred`, the Buyer includes the session key certificate in `accepted.extra.sessionCert` | - [Error Codes](https://web3.okx.com/onchainos/dev-docs/payments/error-code.md) # Error Codes ### Authentication Errors (HTTP 401) | Error Code | Description | |:---:|:---:| | 50103 | Request header `OK-ACCESS-KEY` cannot be empty | | 50104 | Request header `OK-ACCESS-PASSPHRASE` cannot be empty | | 50105 | Request header `OK-ACCESS-PASSPHRASE` is incorrect | | 50106 | Request header `OK-ACCESS-SIGN` cannot be empty | | 50107 | Request header `OK-ACCESS-TIMESTAMP` cannot be empty | | 50111 | Invalid `OK-ACCESS-KEY` | | 50112 | Invalid `OK-ACCESS-TIMESTAMP` | | 50113 | Invalid signature | ### Request Errors | Error Code | HTTP Status | Description | |:---:|:---:|:---:| | 50011 | 429 | Request rate too high, exceeding the allowed limit for this endpoint | | 50014 | 400 | Required parameter `{param}` cannot be empty | ### Business Errors | Error Code | HTTP Status | Description | |:---:|:---:|:---:| | 50026 | 500 | System error, please try again later | | 81001 | 200 | Invalid parameter `{param}` | | 81004 | 200 | Unsupported chain | | 80007 | 200 | Risky address | - [Instant vs Batch Payment Request Differences](https://web3.okx.com/onchainos/dev-docs/payments/api-instant-vs-batch.md) # Instant vs Batch Payment Request Differences ## Instant Payment (exact) vs Batch Payment (aggr_deferred) Request Differences | Field | exact | aggr_deferred | |:---:|:---:|:---:| | `accepted.scheme` | `"exact"` | `"aggr_deferred"` | | `accepted.extra.sessionCert` | None | Required: session key certificate (base64) | | `payload.signature` | EOA signature | session key signature | | `syncSettle` (settle endpoint) | Optional, defaults to false | Not applicable | | settle response `transaction` | txHash | Empty string | > **sessionCert flow**: Buyer includes it in `accepted.extra.sessionCert` → Seller passes it through as-is → Facilitator extracts it internally for TEE signature verification and signature conversion. Seller does not need to parse this field. - [Trade API](https://web3.okx.com/onchainos/dev-docs/trade/dex-api-introduction.md) # Trade API Our Trade API provides developers a set of APIs to identify the best quotes and execute the most efficient swap routes through our smart routing algorithm and liquidity aggregation across 500+ DEXs across Solana, EVM, SUI and more. It provides the critical multi-chain DEX aggregator backend for developers to build and scale trading experience within a variety of dApps such as - DEX Dashboards and Aggregators: offering users a comprehensive view of prices and liquidity across multiple decentralized exchanges for optimized trading. - Native Swap in Wallets: enabling wallets to incorporate built-in swap functionalities with access to the best liquidity pools. - Multi-chain Trading Bots: allowing automation of trading strategies such as arbitrage, liquidity mining, and asset management by leveraging high liquidity and efficient trade routing across 20+ chains. - DeFi Lending Platforms: supporting Defi platforms with liquidity tracking for optimized asset management and lending strategies. - Arbitrage Bots: providing tools and infrastructure to enable developers to perform and profit from price differences across multiple DEXs or between DEXs and CEXs. - [Build with AI](https://web3.okx.com/onchainos/dev-docs/trade/dex-ai-tools-introduction.md) # Build with AI OKX Onchain OS Trade give agents and developers a complete swap execution layer, from getting the best multi-chain quote to a transaction, without stitching together separate routing, signing, and RPC integrations. Whether you are building an automated trading agent or embedding swap execution into a product, the Skill and MCP Server handle the entire lifecycle with production-grade patterns already built in. ## Why Onchain OS Trade for AI - **Broadest on-chain liquidity coverage.** The OKX DEX aggregator routes across 500+ DEXs on 20+ chains such as Solana, Ethereum, Base, BNB Chain, Arbitrum, Sui, TON, and more. At quote time, it splits orders across multiple pools and routes to minimize price impact and maximize the amount received, not just find the cheapest single route. - **Full execution stack in one tool.** Onchain OS Trade AI tools cover every step from quote → swap → sign with multi-chain support. An Agent can execute a complete multi-step swap from a single high-level instruction, including Approve transactions where needed, chain-specific signing flows for EVM and Solana, and confirmation handling. - **Agent-optimized interface Skill and MCP Server.** OKX Web3 Trade provides two integration paths depending on how your Agent is deployed. The Skill teaches your Agent how to call the OKX DEX API through structured instructions and code generation. The MCP Server exposes the same capabilities as directly callable tools via the Model Context Protocol. ## Quickstart By adding the Skill files to the Agent’s skill directory, the Agent will automatically load the intent router, chain-specific execution playbooks, signing modes, and error-handling logic. ```shell npx skills add okx/onchainos-skills ``` For more details, please refer to the [GitHub repository](https://github.com/okx/onchainos-skills). For Claude Desktop, Cursor, and other MCP-compatible clients, add the following configuration: **for General Claude code** ```shell claude mcp add onchainos-mcp https://web3.okx.com/api/v1/onchainos-mcp -t http -H"OK-ACCESS-KEY: d573a84c-8e79-4a35-b0c6-427e9ad2478d" ``` **For Claude Desktop Installation** 1. Go to the `Settings` page and locate the `Connector` menu. 2. Scroll to the bottom, find `Add custom connector`, and enter the URL: https://web3.okx.com/api/v1/onchainos-mcp You can also try a local installation. For detailed instructions, please consult your Claude client. **for Claude code MCP settings** ```shell claude mcp add-json onchainos-mcp '{ "type": "http", "url": "https://web3.okx.com/api/v1/onchainos-mcp", "headers": { "OK-ACCESS-KEY": "d573a84c-8e79-4a35-b0c6-427e9ad2478d" } }' ``` One MCP server covers both Trade and Market capabilities. Restart your client after updating the config. - [Skills](https://web3.okx.com/onchainos/dev-docs/trade/dex-ai-tools-skills.md) # Skills Beyond simply "retrieving documentation," Skills encapsulate domain knowledge and engineering workflows into stable capabilities. They enable the Agent not only to answer "how to write the docs," but also to handle "which endpoint to choose, what the next step is, and how to deal with errors." ## Why Onchain OS Trade Skills for AI - Covers the full DEX swap lifecycle: supported chains → liquidity sources → approve → quote → swap → sign → broadcast. - Provides an Intent Router: maps user instructions ("swap 0.1 ETH for USDC", "get me a quote for 500 USDT → SOL", "what DEXs are available on Arbitrum?") to the correct API and the appropriate first action. - Plug-and-play for AI agents: structured, framework-agnostic capability modules that directly encapsulate the OKX DEX API for AI Agents. Each Skill corresponds to a specific capability (e.g., generating transaction execution data, fetching quotes, querying token information) and defines clear input/output schemas, enabling seamless integration into any Agent architecture. ## Quickstart ```shell skills:npx skills add okx/onchainos-skills ``` For more details, please refer to the [GitHub repository](https://github.com/okx/onchainos-skills). ## Example interactions Once the Skills is uploaded to your agent, an Agent can respond to natural-language instructions like: ```shell What chains support DEX swaps? # Call dex-aggregator-supported-chains ``` ```shell Which DEXs are available on X-layer? # Call dex-liquidity ``` ```shell How much USDC will I get for 1 OKB on X-layer? # Call dex-quote ``` ```shell I need to approve USDT before swapping, generate the calldata # Call dex-approve-transaction ``` ```shell Build a swap transaction: 100 USDT → ETH, wallet 0xd8dA..., slippage 0.5% # Call dex-swap ``` ```shell Swap 2 SOL for USDC on Solana, wallet DYw8... # Call dex-solana-swap-instruction ``` - [MCP Server](https://web3.okx.com/onchainos/dev-docs/trade/dex-ai-tools-mcp-server.md) # MCP Server MCP (Model Context Protocol) connects AI tools with developer resources. After adding the OKX DEX MCP Server, the Agent can get quotes, check DEX liquidity, construct Approve transactions, execute swaps, and signed transactions — all through standardized, directly callable tool interfaces, within a single conversation or editor session, without any additional integration code. ## What the MCP Server exposes - **Chain & Liquidity Tools:** `dex-okx-dex-aggregator-supported-chains` lists all chains that support swaps; `dex-okx-dex-liquidity` lists active DEX liquidity sources on a specified chain. - **Approve Tool:** `dex-okx-dex-approve-transaction` generates the ERC-20 Approve calldata required for a first-time token swap. - **Quote Tool:** `dex-okx-dex-quote` retrieves the best aggregated quote across all liquidity sources, including expected output amount, price impact, and route details. - **Swap Tool:** `dex-okx-dex-swap` constructs a complete swap transaction (calldata + value + gas estimation), ready for signing. - **Solana Tool:** `dex-okx-dex-solana-swap-instruction` generates a Solana versioned transaction instruction set for swapping SPL tokens, ready to be signed by a wallet. ## Quickstart **for General Claude code** ```shell claude mcp add onchainos-mcp https://web3.okx.com/api/v1/onchainos-mcp -t http -H"OK-ACCESS-KEY: d573a84c-8e79-4a35-b0c6-427e9ad2478d" ``` **for Claude Desktop Installation** 1. Go to the `Settings` page and locate the `Connector` menu. 2. Scroll to the bottom, find `Add custom connector`, and enter the URL: https://web3.okx.com/api/v1/onchainos-mcp You can also try a local installation. For detailed instructions, please consult your Claude client. **for Claude code MCP settings** ```shell claude mcp add-json onchainos-mcp '{ "type": "http", "url": "https://web3.okx.com/api/v1/onchainos-mcp", "headers": { "OK-ACCESS-KEY": "d573a84c-8e79-4a35-b0c6-427e9ad2478d" } }' ``` ## Example interactions Once the MCP Server is active, an Agent can respond to natural-language instructions like: ```shell What chains support DEX swaps? # Call dex-aggregator-supported-chains ``` ```shell Which DEXs are available on X-layer? # Call dex-liquidity ``` ```shell How much USDC will I get for 1 OKB on X-layer? # Call dex-quote ``` ```shell I need to approve USDT for swap # Call dex-approve-transaction ``` ```shell Swap 100 USDT to OKB # Call dex-swap ``` ```shell Swap 2 SOL for USDC on Solana... # Call dex-solana-swap-instruction ``` - [llms.txt](https://web3.okx.com/onchainos/dev-docs/trade/dex-ai-tools-llm.md) # llms.txt ## Onchain OS Trade llms.txt Structure `llms.txt` is a proposed standard designed to help AI language models efficiently understand and navigate documentation or websites. It enables Agents to quickly grasp the structure of documentation and locate relevant pages. Based on minimal context, it can precisely identify the appropriate module within shorter response times, reduce hallucinations, and lower token consumption—serving as a low-cost navigation layer. A typical `llms.txt` file includes: - Site title (H1) - Sections organized by module (H2) - A link to each page + a one-sentence description (used for routing and retrieval) Please visit [OnchainOS.llms.txt](https://web3.okx.com/llms.txt) to view the detailed structure of `llms.txt`. ## Onchain OS Trade llms-full.txt Structure In addition to `llms.txt`, we also provide `llms-full.txt`. Unlike a directory-style index, it aggregates the full site documentation in Markdown format (including more granular descriptions and examples) for deeper indexing and search. Suitable for: - AI tools that require full-context access (deep indexing / advanced search / offline knowledge base construction) - Developers who want a comprehensive view of all pages and resources at once - Building custom AI workflows (e.g., full indexing first, then chunk-based retrieval as needed) Please visit [OnchainOS.llms-full.txt](https://web3.okx.com/llms-full.txt) to view the detailed structure of `llms-full.txt`. - [Build Swap Applications](https://web3.okx.com/onchainos/dev-docs/trade/dex-use-swap.md) # Build Swap Applications - [Build Swap Applications on Solana](https://web3.okx.com/onchainos/dev-docs/trade/dex-use-swap-solana-quick-start.md) # Build Swap Applications on Solana There are two approaches to building swap applications with OKX DEX on Solana: 1. The API-first approach - directly interacting with OKX DEX API endpoints 2. The SDK approach - using the `@okx-dex/okx-dex-sdk` package for a simplified developer experience This guide covers both methods to help you choose the approach that best fits your needs. ## Method 1: API-First Approach This approach demonstrates a token swap using the OKX DEX API endpoints directly. You will swap SOL to USDC on Solana Mainnet. ## 1. Set Up Your Environment Import the necessary Node.js libraries and set up your environment variables: ```typescript // Required libraries import base58 from "bs58"; import BN from "bn.js"; import * as solanaWeb3 from "@solana/web3.js"; import { Connection } from "@solana/web3.js"; import cryptoJS from "crypto-js"; import axios from "axios"; import dotenv from 'dotenv'; dotenv.config(); // Environment variables const apiKey = process.env.OKX_API_KEY; const secretKey = process.env.OKX_SECRET_KEY; const apiPassphrase = process.env.OKX_API_PASSPHRASE; const userAddress = process.env.WALLET_ADDRESS; const userPrivateKey = process.env.PRIVATE_KEY; const solanaRpcUrl = process.env.SOLANA_RPC_URL; // Constants const SOLANA_CHAIN_ID = "501"; const COMPUTE_UNITS = 300000; const MAX_RETRIES = 3; // Initialize Solana connection const connection = new Connection(`${solanaRpcUrl}`, { confirmTransactionInitialTimeout: 5000 }); ``` ```typescript // Utility function for OKX API authentication function getHeaders(timestamp: string, method: string, requestPath: string, queryString = "", body = "") { const stringToSign = timestamp + method + requestPath + (queryString || body); return { "Content-Type": "application/json", "OK-ACCESS-KEY": apiKey, "OK-ACCESS-SIGN": cryptoJS.enc.Base64.stringify( cryptoJS.HmacSHA256(stringToSign, secretKey) ), "OK-ACCESS-TIMESTAMP": timestamp, "OK-ACCESS-PASSPHRASE": apiPassphrase, }; } ``` ## 2. Get Swap Data Solana's native token address is 11111111111111111111111111111111. Use the /swap endpoint to retrieve detailed swap information: ```typescript async function getSwapData( fromTokenAddress: string, toTokenAddress: string, amount: string, slippagePercent = '0.5' // 0.5% slippagePercent ) { const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/aggregator/swap"; const params = { amount: amount, chainIndex: SOLANA_CHAIN_ID, fromTokenAddress: fromTokenAddress, toTokenAddress: toTokenAddress, userWalletAddress: userAddress, slippagePercent: slippagePercent }; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); try { const response = await axios.get( `https://web3.okx.com${requestPath}${queryString}`, { headers } ); if (response.data.code !== "0" || !response.data.data?.[0]) { throw new Error(`API Error: ${response.data.msg || "Failed to get swap data"}`); } return response.data.data[0]; } catch (error) { console.error("Error fetching swap data:", error); throw error; } } ``` ## 3. Prepare Transaction ```typescript async function prepareTransaction(callData: string) { try { // Decode the base58 encoded transaction data const decodedTransaction = base58.decode(callData); // Get the latest blockhash const recentBlockHash = await connection.getLatestBlockhash(); console.log("Got blockhash:", recentBlockHash.blockhash); let tx; // Try to deserialize as a versioned transaction first try { tx = solanaWeb3.VersionedTransaction.deserialize(decodedTransaction); console.log("Successfully created versioned transaction"); tx.message.recentBlockhash = recentBlockHash.blockhash; } catch (e) { // Fall back to legacy transaction if versioned fails console.log("Versioned transaction failed, trying legacy:", e); tx = solanaWeb3.Transaction.from(decodedTransaction); console.log("Successfully created legacy transaction"); tx.recentBlockhash = recentBlockHash.blockhash; } return { transaction: tx, recentBlockHash }; } catch (error) { console.error("Error preparing transaction:", error); throw error; } } ``` ## 4. Simulate Transaction Before executing the actual swap, it's crucial to simulate the transaction to ensure it will succeed and to identify any potential issues: The Simulate API is available to our whitelisted customers only. Please reach out to dexapi@okx.com to request access. ```typescript async function simulateTransaction(swapData: any) { try { if (!swapData.tx) { throw new Error('Invalid swap data format - missing transaction data'); } const tx = swapData.tx; const params: any = { fromAddress: tx.from, toAddress: tx.to, txAmount: tx.value, chainIndex: SOLANA_CHAIN_ID, extJson: { inputData: tx.data }, includeDebug: true }; const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/pre-transaction/simulate"; const requestBody = JSON.stringify(params); const headers = getHeaders(timestamp, "POST", requestPath, "", requestBody); console.log('Simulating transaction...'); const response = await axios.post( `https://web3.okx.com${requestPath}`, params, { headers } ); if (response.data.code !== "0") { throw new Error(`Simulation failed: ${response.data.msg || "Unknown simulation error"}`); } const simulationResult = response.data.data[0]; // Check simulation success if (simulationResult.success === false) { console.error('Transaction simulation failed:', simulationResult.error); throw new Error(`Transaction would fail: ${simulationResult.error}`); } console.log('Transaction simulation successful'); console.log(`Estimated gas used: ${simulationResult.gasUsed || 'N/A'}`); if (simulationResult.logs) { console.log('Simulation logs:', simulationResult.logs); } return simulationResult; } catch (error) { console.error("Error simulating transaction:", error); throw error; } } ``` ## 5. Broadcast Transaction 5.1 Create a Compute Unit Estimation Utility Function Solana uses compute units instead of gas to measure transaction complexity. There are two approaches to estimate compute units for your transactions: using standard RPC calls or leveraging the Onchain Gateway API. Method 1: Using the Onchain Gateway API for Compute Unit Estimation The first approach leverages OKX's Onchain Gateway API, which provides more accurate compute unit estimations than standard methods. ```typescript /** * Get transaction compute units from Onchain Gateway API * @param fromAddress - Sender address * @param toAddress - Target program address * @param inputData - Transaction data (base58 encoded) * @returns Estimated compute units */ async function getComputeUnits( fromAddress: string, toAddress: string, inputData: string ): Promise { try { const path = 'dex/pre-transaction/gas-limit'; const url = `https://web3.okx.com/api/v6/${path}`; const body = { chainIndex: "501", // Solana chain ID fromAddress: fromAddress, toAddress: toAddress, txAmount: "0", extJson: { inputData: inputData } }; // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { const computeUnits = parseInt(response.data.data[0].gasLimit); console.log(`API estimated compute units: ${computeUnits}`); return computeUnits; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get compute units from API:', (error as Error).message); throw error; } } ``` Method 2: Using RPC to Estimate Compute Units The second approach utilizes standard Solana RPC calls to simulate and estimate the required compute units for your transaction. ```typescript /** * Estimate compute units for a transaction */ async function getComputeUnits(transaction: VersionedTransaction): Promise { try { // Simulate the transaction to get compute unit usage const simulationResult = await connection.simulateTransaction(transaction, { replaceRecentBlockhash: true, commitment: 'processed' }); if (simulationResult.value.err) { throw new Error(`Simulation failed: ${JSON.stringify(simulationResult.value.err)}`); } // Get the compute units consumed from simulation const computeUnitsConsumed = simulationResult.value.unitsConsumed || 200000; // Add 20% buffer for safety const computeUnitsWithBuffer = Math.ceil(computeUnitsConsumed * 1.2); console.log(`Estimated compute units: ${computeUnitsConsumed}`); console.log(`With 20% buffer: ${computeUnitsWithBuffer}`); return computeUnitsWithBuffer; } catch (error) { console.warn('Failed to estimate compute units, using default:', error); return 300000; // Default fallback } } ``` 5.2 Transaction Preparation with Compute Units Before broadcasting, prepare your transaction with the estimated compute units and latest blockhash: Method 1: Transaction Using Compute Units from Gas-Limit API prepare your transaction with compute units estimated from the Onchain Gateway API: ```typescript /** * Get transaction compute units from Onchain Gateway API */ async function getComputeUnitsFromAPI( fromAddress: string, inputData: string ): Promise { try { const path = 'dex/pre-transaction/gas-limit'; const url = `https://web3.okx.com/api/v6/${path}`; const body = { chainIndex: "501", // Solana chain ID fromAddress: fromAddress, toAddress: "", // Can be empty for Solana txAmount: "0", extJson: { inputData: inputData } }; // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await fetch(url, { method: 'POST', headers, body: bodyString }); const data = await response.json(); if (data.code === '0') { const computeUnits = parseInt(data.data[0].gasLimit); console.log(`API estimated compute units: ${computeUnits}`); return computeUnits; } else { throw new Error(`API Error: ${data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get compute units from API:', (error as Error).message); throw error; } } /** * Prepare transaction with compute units from API */ async function prepareTransactionWithAPIComputeUnits( transaction: VersionedTransaction, fromAddress: string, transactionData: string ): Promise<{ transaction: VersionedTransaction; gasData: { estimatedComputeUnits: number; priorityFee: number; blockhash: string; }; }> { try { // Get fresh blockhash const { blockhash } = await connection.getLatestBlockhash('confirmed'); console.log(`Using blockhash: ${blockhash}`); // Update the transaction's blockhash transaction.message.recentBlockhash = blockhash; // Check if transaction already has compute budget instructions const hasComputeBudgetIx = transaction.message.compiledInstructions.some(ix => { const programId = transaction.message.staticAccountKeys[ix.programIdIndex]; return programId.equals(ComputeBudgetProgram.programId); }); if (hasComputeBudgetIx) { console.log('Transaction already contains compute budget instructions, skipping addition'); return { transaction, gasData: { estimatedComputeUnits: 300000, priorityFee: 1000, blockhash } }; } // Get compute units from API const estimatedComputeUnits = await getComputeUnitsFromAPI(fromAddress, transactionData); // Set priority fee const priorityFee = 1000; // microLamports const gasData = { estimatedComputeUnits, priorityFee, blockhash }; console.log(`Priority fee: ${gasData.priorityFee} microLamports`); // Create compute unit limit instruction const computeBudgetIx = ComputeBudgetProgram.setComputeUnitLimit({ units: gasData.estimatedComputeUnits }); // Create compute unit price instruction for priority const computePriceIx = ComputeBudgetProgram.setComputeUnitPrice({ microLamports: gasData.priorityFee }); // Get existing instructions and account keys const existingInstructions = [...transaction.message.compiledInstructions]; const existingAccountKeys = [...transaction.message.staticAccountKeys]; // Add compute budget program to account keys if not present let computeBudgetProgramIndex = existingAccountKeys.findIndex( key => key.equals(ComputeBudgetProgram.programId) ); if (computeBudgetProgramIndex === -1) { computeBudgetProgramIndex = existingAccountKeys.length; existingAccountKeys.push(ComputeBudgetProgram.programId); } // Create new instructions array with compute budget instructions const newInstructions = [ { programIdIndex: computeBudgetProgramIndex, accountKeyIndexes: [], data: computeBudgetIx.data }, { programIdIndex: computeBudgetProgramIndex, accountKeyIndexes: [], data: computePriceIx.data }, ...existingInstructions ]; // Create new versioned message with proper instruction mapping const newMessage = new TransactionMessage({ payerKey: existingAccountKeys[0], recentBlockhash: gasData.blockhash, instructions: newInstructions.map(ix => ({ programId: existingAccountKeys[ix.programIdIndex], keys: ix.accountKeyIndexes.map(idx => ({ pubkey: existingAccountKeys[idx], isSigner: false, isWritable: false })).filter(key => key.pubkey), data: Buffer.from(ix.data) })).filter(ix => ix.programId) }).compileToV0Message(); // Create and return new transaction const preparedTransaction = new VersionedTransaction(newMessage); return { transaction: preparedTransaction, gasData }; } catch (error) { console.error('Error preparing transaction:', error); throw error; } } ``` Method 2: Transaction Using Compute Units from RPC ```typescript // Simple connection setup const connection = new Connection( process.env.SOLANA_RPC_URL || "https://api.mainnet-beta.solana.com" ); /** * Prepare transaction with compute units */ async function prepareTransactionWithComputeUnits( transaction: VersionedTransaction ): Promise<{ transaction: VersionedTransaction; gasData: { estimatedComputeUnits: number; priorityFee: number; blockhash: string; }; }> { try { // Get fresh blockhash const { blockhash } = await connection.getLatestBlockhash('confirmed'); console.log(`Using blockhash: ${blockhash}`); // Update the transaction's blockhash transaction.message.recentBlockhash = blockhash; // Check if transaction already has compute budget instructions const hasComputeBudgetIx = transaction.message.compiledInstructions.some(ix => { const programId = transaction.message.staticAccountKeys[ix.programIdIndex]; return programId.equals(ComputeBudgetProgram.programId); }); if (hasComputeBudgetIx) { console.log('Transaction already contains compute budget instructions, skipping addition'); return { transaction, gasData: { estimatedComputeUnits: 300000, priorityFee: 1000, blockhash } }; } // Estimate compute units const estimatedComputeUnits = await getComputeUnits(transaction); // Set priority fee const priorityFee = 1000; // microLamports const gasData = { estimatedComputeUnits, priorityFee, blockhash }; console.log(`Priority fee: ${gasData.priorityFee} microLamports`); // Create compute unit limit instruction const computeBudgetIx = ComputeBudgetProgram.setComputeUnitLimit({ units: gasData.estimatedComputeUnits }); // Create compute unit price instruction for priority const computePriceIx = ComputeBudgetProgram.setComputeUnitPrice({ microLamports: gasData.priorityFee }); // Get existing instructions and account keys const existingInstructions = [...transaction.message.compiledInstructions]; const existingAccountKeys = [...transaction.message.staticAccountKeys]; // Add compute budget program to account keys if not present let computeBudgetProgramIndex = existingAccountKeys.findIndex( key => key.equals(ComputeBudgetProgram.programId) ); if (computeBudgetProgramIndex === -1) { computeBudgetProgramIndex = existingAccountKeys.length; existingAccountKeys.push(ComputeBudgetProgram.programId); } // Create new instructions array with compute budget instructions const newInstructions = [ { programIdIndex: computeBudgetProgramIndex, accountKeyIndexes: [], data: computeBudgetIx.data }, { programIdIndex: computeBudgetProgramIndex, accountKeyIndexes: [], data: computePriceIx.data }, ...existingInstructions ]; // Create new versioned message with proper instruction mapping const newMessage = new TransactionMessage({ payerKey: existingAccountKeys[0], recentBlockhash: gasData.blockhash, instructions: newInstructions.map(ix => ({ programId: existingAccountKeys[ix.programIdIndex], keys: ix.accountKeyIndexes.map(idx => ({ pubkey: existingAccountKeys[idx], isSigner: false, isWritable: false })).filter(key => key.pubkey), data: Buffer.from(ix.data) })).filter(ix => ix.programId) }).compileToV0Message(); // Create and return new transaction const preparedTransaction = new VersionedTransaction(newMessage); return { transaction: preparedTransaction, gasData }; } catch (error) { console.error('Error preparing transaction:', error); throw error; } } ``` 5.3 Broadcasting Transactions Using Onchain Gateway API For developers with access to the Onchain Gateway API, you can broadcast transactions directly through OKX's infrastructure. This method provides enhanced reliability and monitoring capabilities for high-volume trading operations. The Broadcast API is available to our whitelisted customers only. Please reach out to dexapi@okx.com to request access. ```typescript async function broadcastTransaction( signedTx: solanaWeb3.Transaction | solanaWeb3.VersionedTransaction ) { try { const serializedTx = signedTx.serialize(); const encodedTx = base58.encode(serializedTx); const path = "dex/pre-transaction/broadcast-transaction"; const url = `https://web3.okx.com/api/v6/${path}`; const broadcastData = { signedTx: encodedTx, chainIndex: SOLANA_CHAIN_ID, address: userAddress // See [MEV Section](#8-mev-protection) for MEV protection settings }; // Prepare authentication with body included in signature const bodyString = JSON.stringify(broadcastData); const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, broadcastData, { headers }); if (response.data.code === '0') { const orderId = response.data.data[0].orderId; console.log(`Transaction broadcast successfully, Order ID: ${orderId}`); return orderId; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to broadcast transaction:', error); throw error; } } ``` Using Standard RPC For developers who prefer using standard blockchain RPC methods or do not have yet requested API whitelisting, you can broadcast transactions directly to the network using Web3 RPC calls. ```typescript async function signAndBroadcastTransaction( tx: solanaWeb3.Transaction | solanaWeb3.VersionedTransaction, connection: Connection ) { if (!userPrivateKey) { throw new Error("Private key not found"); } const feePayer = solanaWeb3.Keypair.fromSecretKey( base58.decode(userPrivateKey) ); // Sign the transaction if (tx instanceof solanaWeb3.VersionedTransaction) { tx.sign([feePayer]); } else { tx.partialSign(feePayer); } // Send the transaction with retry logic const maxRetries = 3; let attempt = 0; while (attempt < maxRetries) { try { const txId = await connection.sendRawTransaction(tx.serialize(), { skipPreflight: false, preflightCommitment: 'processed', maxRetries: 0 // Handle retries manually }); console.log(`Transaction sent: ${txId}`); // Wait for confirmation with timeout const confirmation = await connection.confirmTransaction({ signature: txId, blockhash: tx instanceof solanaWeb3.VersionedTransaction ? tx.message.recentBlockhash : tx.recentBlockhash!, lastValidBlockHeight: tx instanceof solanaWeb3.VersionedTransaction ? undefined : tx.lastValidBlockHeight! }, 'confirmed'); if (confirmation.value.err) { throw new Error(`Transaction failed: ${JSON.stringify(confirmation.value.err)}`); } console.log(`Transaction confirmed: https://solscan.io/tx/${txId}`); return txId; } catch (error) { attempt++; console.warn(`Attempt ${attempt} failed:`, error); if (attempt >= maxRetries) { throw new Error(`Transaction failed after ${maxRetries} attempts: ${error}`); } // Wait before retry await new Promise(resolve => setTimeout(resolve, 1000 * attempt)); } } } ``` ### Swap Transaction Using Compute Unit Data Here's a complete example that demonstrates the full flow from getting swap data to preparing transactions with proper compute unit estimation: ```typescript import { getHeaders } from '../../shared'; import { Connection, VersionedTransaction, ComputeBudgetProgram, TransactionMessage } from "@solana/web3.js"; import base58 from 'bs58'; import dotenv from 'dotenv'; dotenv.config(); // Simple connection to one RPC endpoint const connection = new Connection( process.env.SOLANA_RPC_URL || "https://api.mainnet-beta.solana.com" ); async function getQuote(params: any) { const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/aggregator/swap"; const queryString = "?" + new URLSearchParams({ ...params, }).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); const response = await fetch(`https://web3.okx.com${requestPath}${queryString}`, { method: "GET", headers }); const data = await response.json(); return data; } /** * * Get compute units using Onchain Gateway API (API registration and whitelist required) */ async function getComputeUnitsFromAPI( fromAddress: string, inputData: string ): Promise { try { const path = 'dex/pre-transaction/gas-limit'; const url = `https://web3.okx.com/api/v6/${path}`; const body = { chainIndex: "501", // Solana chain ID fromAddress: fromAddress, toAddress: "", // Can be empty for Solana txAmount: "0", extJson: { inputData: inputData } }; const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await fetch(url, { method: 'POST', headers, body: bodyString }); const data = await response.json(); if (data.code === '0') { const computeUnits = parseInt(data.data[0].gasLimit); console.log(`API estimated compute units: ${computeUnits}`); return computeUnits; } else { throw new Error(`API Error: ${data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get compute units from API, falling back to simulation:', error); // Fallback to RPC simulation return 300000; } } /** * Execute a complete Solana transaction with proper compute unit estimation */ async function executeTransaction(): Promise<{ quote: any; gasData: { estimatedComputeUnits: number; priorityFee: number; blockhash: string; }; preparedTransaction: string; }> { try { console.log('Getting Solana swap data...'); // Step 1: Get swap data from OKX DEX API const quote = await getQuote({ chainIndex: '501', // Solana chain ID amount: '10000000', // 0.01 SOL in lamports fromTokenAddress: '11111111111111111111111111111111', // SOL toTokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC userWalletAddress: "YOUR_WALLET_ADDRESS", slippagePercent: '0.5', autoSlippage: "true", maxAutoSlippagePercent: "0.5" }); console.log('Quote response:', JSON.stringify(quote, null, 2)); // Step 2: Process transaction data if available if (quote.data && quote.data[0] && quote.data[0].tx && quote.data[0].tx.data) { console.log('\nGetting gas data for transaction...'); // Step 3: Create transaction from the data const decodedTransaction = base58.decode(quote.data[0].tx.data); const transaction = VersionedTransaction.deserialize(decodedTransaction); // Step 4: Get compute units using API (API whitelist required) or fallback to RPC const userWalletAddress = "YOUR_WALLET_ADDRESS"; let estimatedComputeUnits: number; try { // Try API first (API whitelist required) estimatedComputeUnits = await getComputeUnitsFromAPI( userWalletAddress, quote.data[0].tx.data ); console.log('Using API estimate for compute units'); } catch (error) { // Fallback to RPC simulation estimatedComputeUnits = await getComputeUnits(transaction); console.log('Using RPC simulation for compute units'); } // Step 5: Prepare transaction with compute units const { transaction: preparedTransaction, gasData } = await prepareTransactionWithComputeUnits(transaction); // Override with API estimate if we got one gasData.estimatedComputeUnits = estimatedComputeUnits; console.log('\nGas Data Summary:'); console.log('Blockhash:', gasData.blockhash); console.log('Estimated Compute Units:', gasData.estimatedComputeUnits); console.log('Priority Fee:', gasData.priorityFee, 'microLamports'); console.log('Transaction prepared successfully'); // Return the complete result const result = { quote: quote.data[0], gasData, preparedTransaction: Buffer.from(preparedTransaction.serialize()).toString('base64') }; console.log('\nFinal Result:', JSON.stringify(result, null, 2)); return result; } else { throw new Error('No transaction data received from swap API'); } } catch (error) { console.error("Error executing transaction:", error); throw error; } } // Example usage async function main() { try { await executeTransaction(); } catch (error) { console.error('Failed to prepare transaction:', error); process.exit(1); } } // Run if this file is executed directly if (require.main === module) { main(); } export { executeTransaction, prepareTransactionWithComputeUnits, getComputeUnits, getComputeUnitsFromAPI }; ``` ## 6. Track Transaction Finally, create a transaction tracking system, choose the first (section 6.1) when you need detailed information about the swap execution itself, or the second (section 6.2) for complete swap insight with token-level details. 6.1 With the Onchain gateway API The Onchain gateway API provides transaction tracking capabilities through the `/dex/post-transaction/orders` endpoint. Use the order ID returned by the broadcast API to track transactions as they progress through OKX's systems with simple status codes (1: Pending, 2: Success, 3: Failed). ```typescript // Define transaction status interface interface TxErrorInfo { error: string; message: string; action: string; } /** * Tracking transaction confirmation status using the Onchain gateway API * @param orderId - Order ID from broadcast response * @param intervalMs - Polling interval in milliseconds * @param timeoutMs - Maximum time to wait * @returns Final transaction confirmation status */ async function trackTransaction( orderId: string, intervalMs: number = 5000, timeoutMs: number = 300000 ): Promise { console.log(`Tracking transaction with Order ID: ${orderId}`); const startTime = Date.now(); let lastStatus = ''; while (Date.now() - startTime < timeoutMs) { // Get transaction status try { const path = 'dex/post-transaction/orders'; const url = `https://web3.okx.com/api/v6/${path}`; const params = { orderId: orderId, chainIndex: SOLANA_CHAIN_ID, address: userAddress, limit: '1' }; // Prepare authentication const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); if (response.data.code === '0' && response.data.data && response.data.data.length > 0) { if (response.data.data[0].orders && response.data.data[0].orders.length > 0) { const txData = response.data.data[0].orders[0]; // Use txStatus to match the API response const status = txData.txStatus; // Only log when status changes if (status !== lastStatus) { lastStatus = status; if (status === '1') { console.log(`Transaction pending: ${txData.txHash || 'Hash not available yet'}`); } else if (status === '2') { console.log(`Transaction successful: https://solscan.io/tx/${txData.txHash}`); return txData; } else if (status === '3') { const failReason = txData.failReason || 'Unknown reason'; const errorMessage = `Transaction failed: ${failReason}`; console.error(errorMessage); const errorInfo = handleTransactionError(txData); console.log(`Error type: ${errorInfo.error}`); console.log(`Suggested action: ${errorInfo.action}`); throw new Error(errorMessage); } } } else { console.log(`No orders found for Order ID: ${orderId}`); } } } catch (error) { console.warn('Error checking transaction status:', (error instanceof Error ? error.message : "Unknown error")); } // Wait before next check await new Promise(resolve => setTimeout(resolve, intervalMs)); } throw new Error('Transaction tracking timed out'); } /** * Comprehensive error handling with failReason * @param txData - Transaction data from post-transaction/orders * @returns Structured error information */ function handleTransactionError(txData: any): TxErrorInfo { const failReason = txData.failReason || 'Unknown reason'; // Log the detailed error console.error(`Transaction failed with reason: ${failReason}`); // Default error info let errorInfo: TxErrorInfo = { error: 'TRANSACTION_FAILED', message: failReason, action: 'Try again or contact support' }; // More specific error handling based on the failure reason if (failReason.includes('insufficient funds')) { errorInfo = { error: 'INSUFFICIENT_FUNDS', message: 'Your wallet does not have enough funds to complete this transaction', action: 'Add more SOL to your wallet to cover the transaction' }; } else if (failReason.includes('blockhash')) { errorInfo = { error: 'BLOCKHASH_EXPIRED', message: 'The transaction blockhash has expired', action: 'Try again with a fresh transaction' }; } else if (failReason.includes('compute budget')) { errorInfo = { error: 'COMPUTE_BUDGET_EXCEEDED', message: 'Transaction exceeded compute budget', action: 'Increase compute units or simplify the transaction' }; } return errorInfo; } ``` 6.2 For more detailed swap-specific information, you can use the SWAP API: SWAP API transaction tracking provides comprehensive swap execution details using the `/dex/aggregator/history` endpoint. It offers token-specific information (symbols, amounts), fees paid, and detailed blockchain data. Use this when you need complete swap insight with token-level details. ```typescript /** * Track transaction using SWAP API * @param chainIndex - Chain ID (e.g., 501 for Solana) * @param txHash - Transaction hash * @returns Transaction details */ async function trackTransactionWithSwapAPI( txHash: string ): Promise { try { const path = 'dex/aggregator/history'; const url = `https://web3.okx.com/api/v6/${path}`; const params = { chainIndex: SOLANA_CHAIN_ID, txHash: txHash, isFromMyProject: 'true' }; // Prepare authentication const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); if (response.data.code === '0') { const txData = response.data.data[0]; const status = txData.status; if (status === 'pending') { console.log(`Transaction is still pending: ${txHash}`); return { status: 'pending', details: txData }; } else if (status === 'success') { console.log(`Transaction successful!`); console.log(`From: ${txData.fromTokenDetails.symbol} - Amount: ${txData.fromTokenDetails.amount}`); console.log(`To: ${txData.toTokenDetails.symbol} - Amount: ${txData.toTokenDetails.amount}`); console.log(`Transaction Fee: ${txData.txFee}`); console.log(`Explorer URL: https://solscan.io/tx/${txHash}`); return { status: 'success', details: txData }; } else if (status === 'failure') { console.error(`Transaction failed: ${txData.errorMsg || 'Unknown reason'}`); return { status: 'failure', details: txData }; } return txData; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to track transaction status:', (error instanceof Error ? error.message : "Unknown error")); throw error; } } ``` ## 7. Complete Implementation Here's a complete implementation example: ```typescript import { getHeaders } from '../../shared'; import { Connection, PublicKey, Transaction, Keypair, VersionedTransaction, SystemProgram } from '@solana/web3.js'; import * as axios from 'axios'; import bs58 from 'bs58'; // // Utility function for OKX API authentication // function getHeaders(timestamp: string, method: string, requestPath: string, queryString = "", body = "") { // const stringToSign = timestamp + method + requestPath + (queryString || body); // return { // "Content-Type": "application/json", // "OK-ACCESS-KEY": apiKey, // "OK-ACCESS-SIGN": cryptoJS.enc.Base64.stringify( // cryptoJS.HmacSHA256(stringToSign, secretKey) // ), // "OK-ACCESS-TIMESTAMP": timestamp, // "OK-ACCESS-PASSPHRASE": apiPassphrase, // }; // Environment variables const WALLET_ADDRESS = process.env.SOLANA_WALLET_ADDRESS; const PRIVATE_KEY = process.env.SOLANA_PRIVATE_KEY; const chainIndex = '501'; // Solana Mainnet const rpcUrl = process.env.SOLANA_RPC_URL || 'https://api.mainnet-beta.solana.com'; // Constants const SOL_ADDRESS = '11111111111111111111111111111111'; // Native SOL const USDC_ADDRESS = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'; // USDC // Initialize Solana connection const connection = new Connection(rpcUrl, 'confirmed'); // Type definitions interface GasLimitApiResponse { code: string; msg?: string; data: Array<{ gasLimit: string; }>; } interface SimulationApiResponse { code: string; msg?: string; data: Array<{ intention: string; gasUsed?: string; failReason?: string; assetChange?: Array<{ assetType: string; name: string; symbol: string; decimals: number; address: string; imageUrl: string; rawValue: string; }>; risks?: Array; }>; } interface BroadcastApiResponse { code: string; msg?: string; data: Array<{ orderId: string; }>; } interface TxErrorInfo { error: string; message: string; action: string; } // ============================================================================ // API Functions // ============================================================================ /** * Get gas limit from Onchain Gateway API */ async function getGasLimit( fromAddress: string, toAddress: string, txAmount: string = '0', inputData: string = '' ): Promise { try { console.log('Getting gas limit from Onchain Gateway API...'); const path = 'dex/pre-transaction/gas-limit'; const url = `https://web3.okx.com/api/v6/${path}`; const body = { chainIndex: chainIndex, fromAddress: fromAddress, toAddress: toAddress, txAmount: txAmount, extJson: { inputData: inputData } }; // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { const gasLimit = response.data.data[0].gasLimit; console.log(`Gas Limit obtained: ${gasLimit}`); return gasLimit; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get gas limit:', (error as Error).message); throw error; } } /** * Get swap data from OKX API */ async function getSwapData( fromTokenAddress: string, toTokenAddress: string, amount: string, slippagePercent = '0.5' ) { try { console.log('Getting swap data from OKX API...'); const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/aggregator/swap"; const queryString = "?" + new URLSearchParams({ chainIndex: chainIndex, fromTokenAddress, toTokenAddress, amount, slippagePercent, userWalletAddress: WALLET_ADDRESS!, autoSlippage: "false", maxAutoSlippagePercent: "0.5" }).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); const response = await fetch(`https://web3.okx.com${requestPath}${queryString}`, { method: "GET", headers }); if (!response.ok) { throw new Error(`Failed to get swap data: ${response.status} ${await response.text()}`); } const data = await response.json(); console.log('Swap data obtained'); return data.data[0]; // Return only the first swap data object } catch (error) { console.error('Failed to get swap data:', (error as Error).message); throw error; } } /** * Simulate transaction using Onchain Gateway API */ async function simulateTransaction(swapData: any) { try { console.log('Simulating transaction with Onchain Gateway API...'); const path = 'dex/pre-transaction/simulate'; const url = `https://web3.okx.com/api/v6/${path}`; const body = { chainIndex: chainIndex, fromAddress: swapData.tx.from, toAddress: swapData.tx.to, txAmount: swapData.tx.value, extJson: { inputData: swapData.tx.data } }; // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { const simulationData = response.data.data[0]; if (simulationData.failReason) { throw new Error(`Simulation failed: ${simulationData.failReason}`); } console.log(`Transaction simulation successful. Gas used: ${simulationData.gasUsed}`); console.log('Simulation API Response:', simulationData); return simulationData; } else { throw new Error(`Simulation API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Transaction simulation failed:', (error as Error).message); throw error; } } /** * Broadcast transaction using Onchain Gateway API with RPC fallback */ async function broadcastTransaction( signedTx: string, chainIndex: string, walletAddress: string ): Promise { try { console.log('Broadcasting transaction via Onchain Gateway API...'); const path = 'dex/pre-transaction/broadcast-transaction'; const url = `https://web3.okx.com/api/v6/${path}`; const body = { signedTx: signedTx, chainIndex: chainIndex, address: walletAddress }; console.log('Broadcast request body:', JSON.stringify(body, null, 2)); // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { const orderId = response.data.data[0].orderId; console.log(`Transaction broadcast successful. Order ID: ${orderId}`); return orderId; } else { throw new Error(`Broadcast API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('OKX API broadcast failed:', (error as Error).message); // Fallback to direct RPC broadcast try { console.log('Attempting direct RPC broadcast as fallback...'); // Decode the signed transaction const txBytes = bs58.decode(signedTx); // Send directly to Solana RPC const signature = await connection.sendRawTransaction(txBytes, { skipPreflight: false, preflightCommitment: 'processed' }); console.log(`Direct RPC broadcast successful. Signature: ${signature}`); // Wait for confirmation const confirmation = await connection.confirmTransaction(signature, 'confirmed'); if (confirmation.value.err) { throw new Error(`Transaction failed: ${JSON.stringify(confirmation.value.err)}`); } console.log(`Transaction confirmed: https://solscan.io/tx/${signature}`); return signature; } catch (rpcError) { console.error('RPC broadcast also failed:', (rpcError as Error).message); throw new Error(`Both OKX API and RPC broadcast failed. OKX Error: ${(error as Error).message}, RPC Error: ${(rpcError as Error).message}`); } } } /** * Track transaction status using Onchain Gateway API */ async function trackTransaction( orderId: string, intervalMs: number = 5000, timeoutMs: number = 180000 // Reduced timeout to 3 minutes ): Promise { console.log(`Tracking transaction with Order ID: ${orderId}`); const startTime = Date.now(); let lastStatus = ''; let pendingCount = 0; while (Date.now() - startTime < timeoutMs) { try { const path = 'dex/post-transaction/orders'; const url = `https://web3.okx.com/api/v6/${path}`; const params = { orderId: orderId, chainIndex: chainIndex, address: WALLET_ADDRESS!, limit: '1' }; const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); const responseData = response.data as any; if (responseData.code === '0' && responseData.data && responseData.data.length > 0) { if (responseData.data[0].orders && responseData.data[0].orders.length > 0) { const txData = responseData.data[0].orders[0]; const status = txData.txStatus; if (status !== lastStatus) { lastStatus = status; if (status === '1') { pendingCount++; console.log(`Transaction pending (${pendingCount}): ${txData.txHash || 'Hash not available yet'}`); // If pending too long without a hash, something is wrong if (pendingCount > 12 && !txData.txHash) { // 1 minute of pending without hash console.warn('Transaction has been pending for too long without a transaction hash. This may indicate an issue.'); } } else if (status === '2') { console.log(`Transaction successful: https://web3.okx.com/explorer/solana/tx/${txData.txHash}`); return txData; } else if (status === '3') { const failReason = txData.failReason || 'Unknown reason'; const errorMessage = `Transaction failed: ${failReason}`; console.error(errorMessage); const errorInfo = handleTransactionError(txData); console.log(`Error type: ${errorInfo.error}`); console.log(`Suggested action: ${errorInfo.action}`); throw new Error(errorMessage); } } else if (status === '1') { pendingCount++; // Show progress for long pending transactions if (pendingCount % 6 === 0) { // Every 30 seconds const elapsed = Math.round((Date.now() - startTime) / 1000); console.log(`Still pending... (${elapsed}s elapsed)`); } } } else { console.log(`No orders found for Order ID: ${orderId}`); } } else { console.log('No response data from tracking API'); } } catch (error) { console.warn('Error checking transaction status:', (error as Error).message); } await new Promise(resolve => setTimeout(resolve, intervalMs)); } throw new Error(`Transaction tracking timed out after ${timeoutMs/1000} seconds. The transaction may still be processing.`); } // ============================================================================ // Transaction Signing Functions // ============================================================================ /** * Sign transaction with private key - Fixed OKX approach with gas limit analysis */ async function signTransaction(swapData: any, gasLimit: string): Promise { try { console.log('Signing transaction...'); if (!PRIVATE_KEY) { throw new Error('Private key not found in environment variables'); } // Create keypair from private key const privateKeyBytes = bs58.decode(PRIVATE_KEY); const keypair = Keypair.fromSecretKey(privateKeyBytes); if (!swapData.tx || !swapData.tx.data) { throw new Error('No transaction data found in swap response'); } const callData = swapData.tx.data; console.log('Transaction data length:', callData.length); console.log('Gas limit from API:', gasLimit); try { // Decode the base58 encoded transaction data (this is the correct approach) const decodedTransaction = bs58.decode(callData); console.log('Decoded transaction bytes length:', decodedTransaction.length); // Get the latest blockhash (CRITICAL!) const recentBlockHash = await connection.getLatestBlockhash(); console.log('Got recent blockhash:', recentBlockHash.blockhash); let transaction: Transaction | VersionedTransaction; // Try VersionedTransaction first (more common for modern Solana programs) try { transaction = VersionedTransaction.deserialize(decodedTransaction); console.log('Successfully deserialized as VersionedTransaction'); // DEBUGGING: Let's see what instructions are already in the transaction console.log('Number of instructions in OKX transaction:', transaction.message.compiledInstructions.length); // Check if there are already ComputeBudget instructions const computeBudgetProgram = new PublicKey('ComputeBudget111111111111111111111111111111'); const computeBudgetIndex = transaction.message.staticAccountKeys.findIndex( key => key.equals(computeBudgetProgram) ); if (computeBudgetIndex !== -1) { console.log('ComputeBudget program found at index:', computeBudgetIndex); // Check which instructions use the ComputeBudget program const computeBudgetInstructions = transaction.message.compiledInstructions.filter( ix => ix.programIdIndex === computeBudgetIndex ); console.log('Number of ComputeBudget instructions:', computeBudgetInstructions.length); // Analyze each ComputeBudget instruction computeBudgetInstructions.forEach((ix, i) => { const data = ix.data; if (data.length > 0) { const instructionType = data[0]; console.log(`ComputeBudget instruction ${i}: type ${instructionType}`); if (instructionType === 0 && data.length >= 5) { // SetComputeUnitLimit instruction const computeUnits = new Uint32Array(data.slice(1, 5).buffer)[0]; console.log(` - Current compute unit limit: ${computeUnits}`); console.log(` - Gas limit from API: ${gasLimit}`); // Check if we need to update it const apiGasLimit = parseInt(gasLimit); if (computeUnits !== apiGasLimit) { console.log(` - Compute units mismatch! OKX: ${computeUnits}, API: ${apiGasLimit}`); // We could potentially update this here } } else if (instructionType === 1 && data.length >= 9) { // SetComputeUnitPrice instruction const microLamports = new BigUint64Array(data.slice(1, 9).buffer)[0]; console.log(` - Current compute unit price: ${microLamports} microlamports`); } } }); } else { console.log('No ComputeBudget program found - OKX transaction may not have compute budget instructions'); console.log('We should add ComputeBudget instruction with gas limit:', gasLimit); // Add ComputeBudget instruction since OKX didn't include one const setComputeUnitLimitData = Buffer.alloc(5); setComputeUnitLimitData[0] = 0; // SetComputeUnitLimit instruction setComputeUnitLimitData.writeUInt32LE(parseInt(gasLimit), 1); // Add the ComputeBudget program to static accounts transaction.message.staticAccountKeys.push(computeBudgetProgram); const programIndex = transaction.message.staticAccountKeys.length - 1; // Add the compute budget instruction at the beginning transaction.message.compiledInstructions.unshift({ programIdIndex: programIndex, accountKeyIndexes: [], data: setComputeUnitLimitData }); console.log('Added ComputeBudget instruction with gas limit:', gasLimit); } // CRITICAL: Update the blockhash in the transaction message transaction.message.recentBlockhash = recentBlockHash.blockhash; // Sign the versioned transaction transaction.sign([keypair]); console.log('Signed VersionedTransaction'); } catch (versionedError) { console.log('VersionedTransaction failed, trying legacy Transaction'); try { transaction = Transaction.from(decodedTransaction); console.log('Successfully deserialized as legacy Transaction'); // DEBUGGING: Check legacy transaction instructions console.log('Number of instructions in legacy transaction:', transaction.instructions.length); // Check for ComputeBudget instructions in legacy format const computeBudgetProgram = new PublicKey('ComputeBudget111111111111111111111111111111'); const computeBudgetInstructions = transaction.instructions.filter( ix => ix.programId.equals(computeBudgetProgram) ); if (computeBudgetInstructions.length === 0) { console.log('No ComputeBudget instructions found in legacy transaction'); console.log('Adding ComputeBudget instruction with gas limit:', gasLimit); // Add ComputeBudget instruction const setComputeUnitLimitData = Buffer.alloc(5); setComputeUnitLimitData[0] = 0; // SetComputeUnitLimit instruction setComputeUnitLimitData.writeUInt32LE(parseInt(gasLimit), 1); const computeBudgetIx = { programId: computeBudgetProgram, keys: [], data: setComputeUnitLimitData }; // Add at the beginning transaction.instructions.unshift(computeBudgetIx); console.log('Added ComputeBudget instruction to legacy transaction'); } else { console.log('Found existing ComputeBudget instructions:', computeBudgetInstructions.length); } // CRITICAL: Update the blockhash in the transaction transaction.recentBlockhash = recentBlockHash.blockhash; // Sign the legacy transaction transaction.sign(keypair); console.log('Signed legacy Transaction'); } catch (legacyError) { console.log('Both transaction types failed to deserialize'); console.log('VersionedTransaction error:', (versionedError as Error).message); console.log('Legacy Transaction error:', (legacyError as Error).message); // This should not happen with proper OKX data throw new Error('Failed to deserialize OKX transaction data. Data may be corrupted.'); } } // Serialize and encode the signed transaction const serializedTx = transaction.serialize(); const encodedTx = bs58.encode(serializedTx); console.log('Transaction signed and encoded successfully'); return encodedTx; } catch (error) { console.log('Failed to process OKX transaction data:', (error as Error).message); // If we reach here, the OKX data is not in expected format throw new Error(`Cannot process OKX transaction data: ${(error as Error).message}`); } } catch (error) { console.error('Failed to sign transaction:', (error as Error).message); throw error; } } // ============================================================================ // Error Handling // ============================================================================ /** * Comprehensive error handling with failReason */ function handleTransactionError(txData: any): TxErrorInfo { const failReason = txData.failReason || 'Unknown reason'; console.error(`Transaction failed with reason: ${failReason}`); return { error: 'TRANSACTION_FAILED', message: failReason, action: 'Try again or contact support' }; } // ============================================================================ // Main Execution Functions // ============================================================================ /** * Execute swap with full transaction flow */ async function executeSwap( fromTokenAddress: string, toTokenAddress: string, amount: string, slippagePercent: string = '0.5' ): Promise { try { console.log('Starting swap execution...'); // Step 1: Get swap data const swapData = await getSwapData(fromTokenAddress, toTokenAddress, amount, slippagePercent); console.log('Swap data obtained'); // Step 2: Simulate transaction const simulationResult = await simulateTransaction(swapData); console.log('Transaction simulation completed'); console.log('Simulation result', simulationResult.intention); // Step 3: Get gas limit const gasLimit = await getGasLimit( swapData.tx.from, swapData.tx.to, swapData.tx.value || '0', swapData.tx.data ); console.log('Gas limit obtained'); // Step 4: Check account balance if (!(swapData.tx && swapData.tx.data)) { throw new Error('No valid transaction data found in swap API response (tx.data missing)'); } console.log('Checking account balance...'); const fromPubkey = new PublicKey(swapData.tx.from); const balance = await connection.getBalance(fromPubkey); console.log(`Account balance: ${balance / 1e9} SOL`); // Check if we have enough balance for the transaction const requiredAmount = parseInt(swapData.tx.value || '0'); console.log(`Required amount: ${requiredAmount / 1e9} SOL`); if (balance < requiredAmount) { throw new Error(`Insufficient balance. Required: ${requiredAmount / 1e9} SOL, Available: ${balance / 1e9} SOL`); } // Step 5: Sign the transaction with private key console.log('Signing transaction with private key...'); const signedTx = await signTransaction(swapData, gasLimit); console.log('Transaction signed successfully'); // Step 6: Broadcast transaction console.log('Broadcasting signed transaction via Onchain Gateway API...'); const txHash = await broadcastTransaction(signedTx, chainIndex, WALLET_ADDRESS!); console.log(`Transaction broadcast successful. Hash: ${txHash}`); // Step 7: Track transaction console.log('Tracking transaction status...'); const trackingResult = await trackTransaction(txHash); console.log('Transaction tracking completed'); console.log('Tracking result', trackingResult); return txHash; } catch (error) { console.error('Swap execution failed:', (error as Error).message); throw error; } } /** * Execute swap with simulation and detailed logging */ async function executeSwapWithSimulation( fromTokenAddress: string, toTokenAddress: string, amount: string, slippagePercent: string = '0.5' ): Promise { try { console.log('Starting swap execution with simulation...'); const txHash = await executeSwap(fromTokenAddress, toTokenAddress, amount, slippagePercent); console.log('Swap execution completed successfully!'); console.log(`Transaction Hash: ${txHash}`); return { success: true, txHash }; } catch (error) { console.error('Swap execution failed:', (error as Error).message); return { success: false, error: (error as Error).message }; } } /** * Simulation-only mode */ async function simulateOnly( fromTokenAddress: string, toTokenAddress: string, amount: string, slippagePercent: string = '0.5' ): Promise { try { console.log('Starting simulation-only mode...'); console.log(`Simulation Details:`); console.log(` From Token: ${fromTokenAddress}`); console.log(` To Token: ${toTokenAddress}`); console.log(` Amount: ${amount}`); console.log(` SlippagePercent: ${slippagePercent}%`); // Step 1: Get swap data const swapData = await getSwapData(fromTokenAddress, toTokenAddress, amount, slippagePercent); console.log('Swap data obtained'); // Step 2: Simulate transaction const simulationResult = await simulateTransaction(swapData); console.log('Transaction simulation completed'); // Step 3: Get gas limit const gasLimit = await getGasLimit( swapData.tx.from, swapData.tx.to, swapData.tx.value || '0', swapData.tx.data ); console.log('Gas limit obtained'); return { success: true, swapData, simulationResult, gasLimit, estimatedGasUsed: simulationResult.gasUsed, }; } catch (error) { console.error('Simulation failed:', (error as Error).message); return { success: false, error: (error as Error).message }; } } // ============================================================================ // Main Entry Point // ============================================================================ async function main() { try { console.log('Solana Swap Tools with Onchain Gateway API'); console.log('====================================='); // Validate environment variables if (!WALLET_ADDRESS || !PRIVATE_KEY) { throw new Error('Missing wallet address or private key in environment variables'); } console.log(`Wallet Address: ${WALLET_ADDRESS}`); console.log(`Chain ID: ${chainIndex}`); console.log(`RPC URL: ${rpcUrl}`); // Parse command line arguments const args = process.argv.slice(2); const mode = args[0] || 'simulate'; // Default to simulate mode // Example parameters const fromToken = SOL_ADDRESS; const toToken = USDC_ADDRESS; const amount = '10000000'; // 0.01 SOL in lamports const slippagePercent = '0.5'; // 0.5% console.log('\nConfiguration:'); console.log(` From: ${fromToken} (SOL)`); console.log(` To: ${toToken} (USDC)`); console.log(` Amount: ${parseInt(amount) / 1e9} SOL`); console.log(` SlippagePercent: ${slippagePercent}%`); console.log(` Mode: ${mode}`); let result; switch (mode.toLowerCase()) { case 'simulate': case 'sim': result = await simulateOnly(fromToken, toToken, amount, slippagePercent); break; case 'execute': case 'exec': result = await executeSwapWithSimulation(fromToken, toToken, amount, slippagePercent); break; default: console.log('\nAvailable modes:'); console.log(' simulate/sim - Only simulate the transaction'); console.log(' execute/exec - Execute the full swap'); console.log('\nExample: npm run solana-swap simulate'); return; } if (result.success) { console.log('\nOperation completed successfully!'); if (mode === 'simulate' || mode === 'sim') { console.log(`Gas Limit: ${result.gasLimit}`); } else { console.log(`Transaction Hash: ${result.txHash}`); } } else { console.log('\nOperation failed!'); console.log(`Error: ${result.error}`); } } catch (error) { console.error('Main execution failed:', (error as Error).message); process.exit(1); } } // Run the script if (require.main === module) { main(); } // ============================================================================ // Exports // ============================================================================ export { executeSwap, executeSwapWithSimulation, simulateOnly, getSwapData, simulateTransaction, getGasLimit, broadcastTransaction, trackTransaction, signTransaction }; ``` You can run this script using `solana-swap-executor.ts sim` or `solana-swap-executor.ts exec`. `sim` simulates a transaction using swap data using the transaction simulation API and retruns `gasLimit` info `exec` executes a transaction using the broadcast API ## 8. MEV Protection ### MEV Protection with Broadcast Transaction API The OKX Broadcast Transaction API provides built-in MEV protection capabilities to help safeguard your transactions from front-running and sandwich attacks. The Broadcast API is available to our whitelisted customers only. Please reach out to dexapi@okx.com to request access. **Disclaimer:** Your end-user's transaction can only be covered by the MEV protection feature if you actually utilise OKX Build's API services for that particular transaction. MEV protection is currently an experimental feature provided by third-parties and OKX Build does not guarantee the effectiveness and quality of such MEV protection. #### Basic MEV Protection To enable MEV protection, add the `extraData` field to your broadcast transaction request with `enableMevProtection: true`: ```typescript /** * Broadcast transaction with MEV protection enabled */ async function broadcastTransactionWithMEV( signedTx: string, chainIndex: string = "501", walletAddress: string, enableMevProtection: boolean = true ): Promise { try { console.log('Broadcasting transaction with MEV protection...'); const path = 'dex/pre-transaction/broadcast-transaction'; const url = `https://web3.okx.com/api/v6/${path}`; const body = { signedTx: signedTx, chainIndex: chainIndex, address: walletAddress, extraData: JSON.stringify({ enableMevProtection: enableMevProtection }) }; const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { const orderId = response.data.data[0].orderId; console.log(`Transaction broadcast with MEV protection. Order ID: ${orderId}`); return orderId; } else { throw new Error(`Broadcast API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('MEV-protected broadcast failed:', error); throw error; } } ``` #### Jito Integration for Enhanced Protection For additional MEV protection on Solana, you can include Jito-specific parameters: ```typescript /** * Broadcast transaction with Jito MEV protection */ async function broadcastTransactionWithJito( signedTx: string, jitoSignedTx: string, chainIndex: string = "501", walletAddress: string ): Promise { try { console.log('Broadcasting transaction with Jito MEV protection...'); const path = 'dex/pre-transaction/broadcast-transaction'; const url = `https://web3.okx.com/api/v6/${path}`; const body = { signedTx: signedTx, chainIndex: chainIndex, address: walletAddress, extraData: JSON.stringify({ enableMevProtection: true, jitoSignedTx: jitoSignedTx }) }; const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { const orderId = response.data.data[0].orderId; console.log(`Transaction broadcast with Jito protection. Order ID: ${orderId}`); return orderId; } else { throw new Error(`Broadcast API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Jito-protected broadcast failed:', error); throw error; } } ``` #### Updated Broadcast Function with MEV Parameters Here's the updated `broadcastTransaction` function that includes MEV protection parameters: ```typescript /** * Enhanced broadcast transaction with MEV protection parameters */ async function broadcastTransaction( signedTx: string, chainIndex: string = "501", walletAddress: string, enableMevProtection: boolean = false, jitoSignedTx: string = "" ): Promise { try { console.log(`Broadcasting transaction${enableMevProtection ? ' with MEV protection' : ''}...`); const path = 'dex/pre-transaction/broadcast-transaction'; const url = `https://web3.okx.com/api/v6/${path}`; const body: any = { signedTx: signedTx, chainIndex: chainIndex, address: walletAddress }; // Add MEV protection parameters if enabled if (enableMevProtection || jitoSignedTx) { const extraData: any = {}; if (enableMevProtection) { extraData.enableMevProtection = true; } if (jitoSignedTx) { extraData.jitoSignedTx = jitoSignedTx; } body.extraData = JSON.stringify(extraData); } const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { const orderId = response.data.data[0].orderId; console.log(`Transaction broadcast successful. Order ID: ${orderId}`); return orderId; } else { throw new Error(`Broadcast API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Broadcast failed:', error); throw error; } } ``` #### Usage Examples **Basic swap without MEV protection:** ```typescript // Standard broadcast (no MEV protection) const orderId = await broadcastTransaction(signedTx, "501", walletAddress); ``` **Swap with MEV protection enabled:** ```typescript // With MEV protection const orderId = await broadcastTransaction(signedTx, "501", walletAddress, true); ``` **Swap with Jito MEV protection:** ```typescript // With Jito protection const orderId = await broadcastTransaction(signedTx, "501", walletAddress, true, jitoSignedTransaction); ``` **Swap with only Jito (no general MEV protection):** ```typescript // Only Jito protection const orderId = await broadcastTransaction(signedTx, "501", walletAddress, false, jitoSignedTransaction); ``` #### Integration with Complete Swap Flow Here's how to integrate MEV protection into your complete swap execution: ```typescript /** * Execute swap with MEV protection */ async function executeSwapWithMEVProtection( fromTokenAddress: string, toTokenAddress: string, amount: string, slippagePercent: string = '0.5', enableMevProtection: boolean = true ): Promise { try { // Step 1: Get swap data const swapData = await getSwapData(fromTokenAddress, toTokenAddress, amount, slippagePercent); // Step 2: Prepare and sign transaction const { transaction } = await prepareTransaction(swapData.tx.data); const signedTx = await signTransaction(transaction); // Step 3: Broadcast with MEV protection const orderId = await broadcastTransaction(signedTx, "501", userAddress, enableMevProtection); // Step 4: Track transaction const result = await trackTransaction(orderId); return result.txHash; } catch (error) { console.error("MEV-protected swap failed:", error); throw error; } } ``` The MEV protection feature integrates seamlessly with your existing EVM and Solana swap implementation and provides an additional layer of security against MEV attacks across Solana, Base, Ethereum, and BSC. ## Method 2: SDK approach Using the OKX DEX SDK provides a much simpler developer experience while retaining all the functionality of the API-first approach. The SDK handles many implementation details for you, including retry logic, error handling, and transaction management. ## 1. Install the SDK ```typescript npm install @okx-dex/okx-dex-sdk # or yarn add @okx-dex/okx-dex-sdk # or pnpm add @okx-dex/okx-dex-sdk ``` ## 2. Setup Your Environment Create a .env file with your API credentials and wallet information: ```typescript # OKX API Credentials OKX_API_KEY=your_api_key OKX_SECRET_KEY=your_secret_key OKX_API_PASSPHRASE=your_passphrase # Solana Configuration SOLANA_RPC_URL=your_solana_rpc_url SOLANA_WALLET_ADDRESS=your_solana_wallet_address SOLANA_PRIVATE_KEY=your_solana_private_key # Ethereum Configuration EVM_RPC_URL=your_evm_rpc_url EVM_WALLET_ADDRESS=your_evm_wallet_address EVM_PRIVATE_KEY=your_evm_private_key ``` ## 3. Initialize the Client Create a file for your DEX client (e.g., DexClient.ts): ```typescript import { OKXDexClient } from '@okx-dex/okx-dex-sdk'; import { createEVMWallet } from '@okx-dex/okx-dex-sdk/core/evm-wallet'; import { createWallet } from '@okx-dex/okx-dex-sdk/core/wallet'; import { Connection } from '@solana/web3.js'; import { ethers } from 'ethers'; import dotenv from 'dotenv'; dotenv.config(); // EVM setup (Ethereum, Base, Arbitrum, etc.) const evmProvider = new ethers.JsonRpcProvider(process.env.EVM_RPC_URL!); const evmWallet = createEVMWallet(process.env.EVM_PRIVATE_KEY!, evmProvider); // Solana setup const solanaConnection = new Connection(process.env.SOLANA_RPC_URL!); const solanaWallet = createWallet(process.env.SOLANA_PRIVATE_KEY!, solanaConnection); // Initialize the client const client = new OKXDexClient({ // API credentials (get from OKX Developer Portal) apiKey: process.env.OKX_API_KEY!, secretKey: process.env.OKX_SECRET_KEY!, apiPassphrase: process.env.OKX_API_PASSPHRASE!, // EVM configuration (works for all EVM chains) evm: { wallet: evmWallet }, // Solana configuration solana: { wallet: solanaWallet, computeUnits: 300000, // Optional maxRetries: 3 // Optional }, }) ``` ## 4. Execute a Swap With the SDK Create a swap execution file: ```typescript // swap.ts import { client } from './DexClient'; /** * Example: Execute a swap from SOL to USDC */ async function executeSwap() { try { if (!process.env.SOLANA_PRIVATE_KEY) { throw new Error('Missing SOLANA_PRIVATE_KEY in .env file'); } // Get quote to fetch token information console.log("Getting token information..."); const quote = await client.dex.getQuote({ chainIndex: '501', fromTokenAddress: '11111111111111111111111111111111', // SOL toTokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC amount: '1000000', // Small amount for quote slippagePercent: '0.5' // 0.5% slippagePercent }); const tokenInfo = { fromToken: { symbol: quote.data[0].fromToken.tokenSymbol, decimals: parseInt(quote.data[0].fromToken.decimal), price: quote.data[0].fromToken.tokenUnitPrice }, toToken: { symbol: quote.data[0].toToken.tokenSymbol, decimals: parseInt(quote.data[0].toToken.decimal), price: quote.data[0].toToken.tokenUnitPrice } }; // Convert amount to base units (for display purposes) const humanReadableAmount = 0.1; // 0.1 SOL const rawAmount = (humanReadableAmount * Math.pow(10, tokenInfo.fromToken.decimals)).toString(); console.log("\nSwap Details:"); console.log("--------------------"); console.log(`From: ${tokenInfo.fromToken.symbol}`); console.log(`To: ${tokenInfo.toToken.symbol}`); console.log(`Amount: ${humanReadableAmount} ${tokenInfo.fromToken.symbol}`); console.log(`Amount in base units: ${rawAmount}`); console.log(`Approximate USD value: $${(humanReadableAmount * parseFloat(tokenInfo.fromToken.price)).toFixed(2)}`); // Execute the swap console.log("\nExecuting swap..."); const swapResult = await client.dex.executeSwap({ chainIndex: '501', // Solana chain ID fromTokenAddress: '11111111111111111111111111111111', // SOL toTokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC amount: rawAmount, slippagePercent: '0.5', // 0.5% slippagePercent userWalletAddress: process.env.SOLANA_WALLET_ADDRESS! }); console.log('Swap executed successfully:'); console.log(JSON.stringify(swapResult, null, 2)); return swapResult; } catch (error) { if (error instanceof Error) { console.error('Error executing swap:', error.message); // API errors include details in the message if (error.message.includes('API Error:')) { const match = error.message.match(/API Error: (.*)/); if (match) console.error('API Error Details:', match[1]); } } throw error; } } // Run if this file is executed directly if (require.main === module) { executeSwap() .then(() => process.exit(0)) .catch((error) => { console.error('Error:', error); process.exit(1); }); } export { executeSwap }; ``` ## 5. Additional SDK Functionality The SDK provides additional methods that simplify development: Get a quote for a token pair ```typescript const quote = await client.dex.getQuote({ chainIndex: '501', // Solana fromTokenAddress: '11111111111111111111111111111111', // SOL toTokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC amount: '100000000', // 0.1 SOL (in lamports) slippagePercent: '0.5' // 0.5% slippagePercent }); ``` - [Advanced Control With Swap-Instructions on Solana](https://web3.okx.com/onchainos/dev-docs/trade/dex-use-swap-solana-advance-control.md) # Advanced Control With Swap-Instructions on Solana The `swap-instruction` endpoint offers more control over the swap process than the standard `/swap` endpoint. While `/swap` gives you a pre-built transaction ready to sign, `swap-instruction` lets you: - Build custom transaction signing flows - Handle instruction processing your own way - Add your own instructions to the transaction if needed - Work with lookup tables directly for optimizing transaction size ## 1. Set Up Your Environment Import the necessary libraries: ```javascript // Required Solana dependencies for DEX interaction import { Connection, // Handles RPC connections to Solana network Keypair, // Manages wallet keypairs for signing PublicKey, // Handles Solana public key conversion and validation TransactionInstruction, // Core transaction instruction type TransactionMessage, // Builds transaction messages (v0 format) VersionedTransaction, // Supports newer transaction format with lookup tables RpcResponseAndContext, // RPC response wrapper type SimulatedTransactionResponse, // Simulation result type AddressLookupTableAccount, // For transaction size optimization PublicKeyInitData // Public key input type } from "@solana/web3.js"; import base58 from "bs58"; // Required for private key decoding ``` ## 2. Initialize Your Connection and Wallet Set up your connection and wallet instance: ```javascript // Note: Consider using a reliable RPC endpoint with high rate limits for production const connection = new Connection( process.env.SOLANA_RPC_URL || "https://api.mainnet-beta.solana.com" ); // Initialize wallet for signing // This wallet will be the fee payer and transaction signer const wallet = Keypair.fromSecretKey( Uint8Array.from(base58.decode(userPrivateKey)) ); ``` ## 3. Configure Swap Parameters Set up the parameters for your swap: ```javascript // Configure swap parameters const baseUrl = "https://web3.okx.com/api/v6/dex/aggregator/swap-instruction"; const params = { chainIndex: "501", // Solana mainnet chain ID feePercent: "1", // Platform fee percentage amount: "1000000", // Amount in smallest denomination (lamports for SOL) fromTokenAddress: "11111111111111111111111111111111", // SOL mint address toTokenAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC mint address slippagePercent: "0.5", // SlippagePercent tolerance 0.5% userWalletAddress: userAddress, // Wallet performing the swap autoSlippage: "false", // Use fixed slippage instead of auto pathNum: "3" // Maximum routes to consider }; ``` ## 4. Process Swap Instructions Fetch and process the swap instructions: ```javascript // Helper function to convert DEX API instructions to Solana format function createTransactionInstruction(instruction) { return new TransactionInstruction({ programId: new PublicKey(instruction.programId), // DEX program ID keys: instruction.accounts.map((key) => ({ pubkey: new PublicKey(key.pubkey), // Account address isSigner: key.isSigner, // True if account must sign tx isWritable: key.isWritable // True if instruction modifies account })), data: Buffer.from(instruction.data, 'base64') // Instruction parameters }); } // Fetch optimal swap route and instructions from DEX const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/aggregator/swap-instruction"; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); const response = await fetch( `https://web3.okx.com${requestPath}${queryString}`, { method: 'GET', headers } ); const { data } = await response.json(); const { instructionLists, addressLookupTableAccount } = data; // Process DEX instructions into Solana-compatible format const instructions = []; // Remove duplicate lookup table addresses returned by DEX const uniqueLookupTables = Array.from(new Set(addressLookupTableAccount)); console.log("Lookup tables to load:", uniqueLookupTables); // Convert each DEX instruction to Solana format if (instructionLists?.length) { instructions.push(...instructionLists.map(createTransactionInstruction)); } ``` ## 5. Handle Address Lookup Tables Process the address lookup tables for transaction optimization: ```javascript // Process lookup tables for transaction optimization // Lookup tables are crucial for complex swaps that interact with many accounts // They significantly reduce transaction size and cost const addressLookupTableAccounts = []; if (uniqueLookupTables?.length > 0) { console.log("Loading address lookup tables..."); // Fetch all lookup tables in parallel for better performance const lookupTableAccounts = await Promise.all( uniqueLookupTables.map(async (address) => { const pubkey = new PublicKey(address); // Get lookup table account data from Solana const account = await connection .getAddressLookupTable(pubkey) .then((res) => res.value); if (!account) { throw new Error(`Could not fetch lookup table account ${address}`); } return account; }) ); addressLookupTableAccounts.push(...lookupTableAccounts); } ``` ## 6. Create and Sign Transaction Create the transaction message and sign it: ```javascript // Get recent blockhash for transaction timing and uniqueness const latestBlockhash = await connection.getLatestBlockhash('finalized'); // Create versioned transaction message (V0 format required for lookup table support) const messageV0 = new TransactionMessage({ payerKey: wallet.publicKey, // Fee payer address recentBlockhash: latestBlockhash.blockhash, // Transaction timing instructions // Swap instructions from DEX }).compileToV0Message(addressLookupTableAccounts); // Include lookup tables // Create new versioned transaction with optimizations const transaction = new VersionedTransaction(messageV0); // Simulate transaction to check for errors // This helps catch issues before paying fees const result = await connection.simulateTransaction(transaction); // Sign transaction with fee payer wallet transaction.sign([wallet]); ``` ## 7. Execute Transaction Finally, simulate and send the transaction: ```javascript // Send transaction to Solana // skipPreflight=false ensures additional validation // maxRetries helps handle network issues const txId = await connection.sendRawTransaction(transaction.serialize(), { skipPreflight: false, // Run preflight validation maxRetries: 5 // Retry on failure }); // Log transaction results console.log("Transaction ID:", txId); console.log("Explorer URL:", `https://solscan.io/tx/${txId}`); // Wait for confirmation await connection.confirmTransaction({ signature: txId, blockhash: latestBlockhash.blockhash, lastValidBlockHeight: latestBlockhash.lastValidBlockHeight }); console.log("Transaction confirmed!"); ``` ## Best Practices and Considerations When implementing swap instructions, keep these key points in mind: - Error Handling: Always implement proper error handling for API responses and transaction simulation results. - Slippage Protection: Choose appropriate slippagePercent parameters based on your use case and market conditions. - Gas Optimization: Use address lookup tables when available to reduce transaction size and costs. - Transaction Simulation: Always simulate transactions before sending them to catch potential issues early. - Retry Logic: Implement proper retry mechanisms for failed transactions with appropriate backoff strategies. MEV Protection Trading on Solana comes with MEV (Maximal Extractable Value) risks. While the MEV protection is not directly included in the SDK, you can implement it yourself using the API-first approach. - [Build Swap Applications on EVM](https://web3.okx.com/onchainos/dev-docs/trade/dex-use-swap-quick-start.md) # Build Swap Applications on EVM There are two approaches to building swap applications with OKX DEX on EVM networks: 1. The API-first approach - directly interacting with OKX DEX API endpoints 2. The SDK approach - using the @okx-dex/okx-dex-sdk package for a simplified developer experience This guide covers both methods to help you choose the approach that best fits your needs. ## Method 1: API-First Approach This approach demonstrates a token swap using the OKX DEX API endpoints directly. You will swap USDC to ETH on the Ethereum network. ## 1. Set Up Your Environment ```typescript // --------------------- npm package --------------------- import { Web3 } from 'web3'; import axios from 'axios'; import * as dotenv from 'dotenv'; import CryptoJS from 'crypto-js'; // The URL for the Ethereum node you want to connect to const web3 = new Web3('https://......com'); // --------------------- environment variable --------------------- // Load hidden environment variables dotenv.config(); // Your wallet information - REPLACE WITH YOUR OWN VALUES const WALLET_ADDRESS: string = process.env.EVM_WALLET_ADDRESS || '0xYourWalletAddress'; const PRIVATE_KEY: string = process.env.EVM_PRIVATE_KEY || 'YourPrivateKey'; // Token addresses for swap on Base Chain const ETH_ADDRESS: string = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'; // Native ETH const USDC_ADDRESS: string = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'; // USDC on Base // Chain ID for Base Chain const chainIndex: string = '8453'; // API URL const baseUrl: string = 'https://web3.okx.com/api/v6/'; // Amount to swap in smallest unit (0.0005 ETH) const SWAP_AMOUNT: string = '500000000000000'; // 0.0005 ETH const SLIPPAGEPERCENT: string = '0.5'; // 0.5% slippagePercent tolerance // --------------------- util function --------------------- export function getHeaders(timestamp: string, method: string, requestPath: string, queryString = "") { // Check https://web3.okx.com/zh-hans/web3/build/docs/waas/rest-authentication for api-key const apiKey = process.env.OKX_API_KEY; const secretKey = process.env.OKX_SECRET_KEY; const apiPassphrase = process.env.OKX_API_PASSPHRASE; if (!apiKey || !secretKey || !apiPassphrase ) { throw new Error("Missing required environment variables"); } const stringToSign = timestamp + method + requestPath + queryString; return { "Content-Type": "application/json", "OK-ACCESS-KEY": apiKey, "OK-ACCESS-SIGN": CryptoJS.enc.Base64.stringify( CryptoJS.HmacSHA256(stringToSign, secretKey) ), "OK-ACCESS-TIMESTAMP": timestamp, "OK-ACCESS-PASSPHRASE": apiPassphrase, }; }; ``` ## 2. Check Allowance You need to check if the token has been approved for the DEX to spend. This step is only needed for ERC20 tokens, not for native tokens like ETH. ```typescript /** * Check token allowance for DEX * @param tokenAddress - Token contract address * @param ownerAddress - Your wallet address * @param spenderAddress - DEX spender address * @returns Allowance amount */ async function checkAllowance( tokenAddress: string, ownerAddress: string, spenderAddress: string ): Promise { const tokenABI = [ { "constant": true, "inputs": [ { "name": "_owner", "type": "address" }, { "name": "_spender", "type": "address" } ], "name": "allowance", "outputs": [{ "name": "", "type": "uint256" }], "payable": false, "stateMutability": "view", "type": "function" } ]; const tokenContract = new web3.eth.Contract(tokenABI, tokenAddress); try { const allowance = await tokenContract.methods.allowance(ownerAddress, spenderAddress).call(); return BigInt(String(allowance)); } catch (error) { console.error('Failed to query allowance:', error); throw error; } } ``` ## 3. Check the Approval Parameters and Initiate the Approval If the allowance is lower than the amount you want to swap, you need to approve the token.
3.1 Define your transaction approval parameters ```typescript const getApproveTransactionParams = { chainIndex: chainIndex, tokenContractAddress: tokenAddress, approveAmount: amount }; ``` 3.2 Define helper functions ```typescript async function getApproveTransaction( tokenAddress: string, amount: string ): Promise { try { const path = 'dex/aggregator/approve-transaction'; const url = `${baseUrl}${path}`; const params = { chainIndex: chainIndex, tokenContractAddress: tokenAddress, approveAmount: amount }; // Prepare authentication const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); if (response.data.code === '0') { return response.data.data[0]; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get approval transaction data:', (error as Error).message); throw error; } } ``` 3.3 Create Compute gasLimit utility function Using the Onchain gateway API to get the gas limit. ```typescript /** * Get transaction gas limit from Onchain gateway API * @param fromAddress - Sender address * @param toAddress - Target contract address * @param txAmount - Transaction amount (0 for approvals) * @param inputData - Transaction calldata * @returns Estimated gas limit */ async function getGasLimit( fromAddress: string, toAddress: string, txAmount: string = '0', inputData: string = '' ): Promise { try { const path = 'dex/pre-transaction/gas-limit'; const url = `https://web3.okx.com/api/v6/${path}`; const body = { chainIndex: chainIndex, fromAddress: fromAddress, toAddress: toAddress, txAmount: txAmount, extJson: { inputData: inputData } }; // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { return response.data.data[0].gasLimit; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get gas limit:', (error as Error).message); throw error; } } ``` Using RPC to get the gas limit. ```typescript const gasLimit = await web3.eth.estimateGas({ from: WALLET_ADDRESS, to: tokenAddress, value: '0', data: approveData.data }); // Add 20% buffer const gasLimit = (BigInt(gasLimit) * BigInt(12) / BigInt(10)).toString(); ``` 3.4 Get transaction information and send approveTransaction ```typescript /** * Sign and send approve transaction * @param tokenAddress - Token to approve * @param amount - Amount to approve * @returns Transaction hash of the approval transaction */ async function approveToken(tokenAddress: string, amount: string): Promise { const spenderAddress = '0x3b3ae790Df4F312e745D270119c6052904FB6790'; // Ethereum Mainnet DEX spender // See Router addresses at: https://web3.okx.com/build/docs/waas/dex-smart-contract const currentAllowance = await checkAllowance(tokenAddress, WALLET_ADDRESS, spenderAddress); if (currentAllowance >= BigInt(amount)) { console.log('Sufficient allowance already exists'); return null; } console.log('Insufficient allowance, approving tokens...'); // Get approve transaction data from OKX DEX API const approveData = await getApproveTransaction(tokenAddress, amount); // Get accurate gas limit using RPC const gasLimit = await web3.eth.estimateGas({ from: WALLET_ADDRESS, to: tokenAddress, value: '0', data: approveData.data }); // Get accurate gas limit using Onchain gateway API // const gasLimit = await getGasLimit(WALLET_ADDRESS, tokenAddress, '0', approveData.data); // Get current gas price const gasPrice = await web3.eth.getGasPrice(); const adjustedGasPrice = BigInt(gasPrice) * BigInt(15) / BigInt(10); // 1.5x for faster confirmation // Get current nonce const nonce = await web3.eth.getTransactionCount(WALLET_ADDRESS, 'latest'); // Create transaction object const txObject = { from: WALLET_ADDRESS, to: tokenAddress, data: approveData.data, value: '0', gas: gasLimit, gasPrice: adjustedGasPrice.toString(), nonce: nonce }; // Sign and broadcast transaction const signedTx = await web3.eth.accounts.signTransaction(txObject, PRIVATE_KEY); const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction); console.log(`Approval transaction successful: ${receipt.transactionHash}`); return receipt.transactionHash; } ``` ## 4. Get Quote Data 4.1 Define quote parameters ```typescript const quoteParams = { amount: fromAmount, chainIndex: chainIndex, toTokenAddress: toTokenAddress, fromTokenAddress: fromTokenAddress, }; ``` 4.2 Define helper functions ```typescript /** * Get swap quote from DEX API * @param fromTokenAddress - Source token address * @param toTokenAddress - Destination token address * @param amount - Amount to swap * @param slippagePercent - Maximum slippagePercent (e.g., "0.5" for 0.5%) * @returns Swap quote */ async function getSwapQuote( fromTokenAddress: string, toTokenAddress: string, amount: string, slippagePercent: string = '0.5' ): Promise { try { const path = 'dex/aggregator/quote'; const url = `${baseUrl}${path}`; const params = { chainIndex: chainIndex, fromTokenAddress, toTokenAddress, amount, slippagePercent }; // Prepare authentication const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); if (response.data.code === '0') { return response.data.data[0]; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get swap quote:', (error as Error).message); throw error; } } ``` ## 5. Prepare Transaction 5.1 Define swap parameters ```typescript const swapParams = { chainIndex: chainIndex, fromTokenAddress, toTokenAddress, amount, userWalletAddress: userAddress, slippagePercent }; ``` 5.2 Request swap transaction data ```typescript /** * Get swap transaction data from DEX API * @param fromTokenAddress - Source token address * @param toTokenAddress - Destination token address * @param amount - Amount to swap * @param userAddress - User wallet address * @param slippagePercent - Maximum slippagePercent (e.g., "0.5" for 0.5%) * @returns Swap transaction data */ async function getSwapTransaction( fromTokenAddress: string, toTokenAddress: string, amount: string, userAddress: string, slippagePercent: string = '0.5' ): Promise { try { const path = 'dex/aggregator/swap'; const url = `${baseUrl}${path}`; const params = { chainIndex: chainIndex, fromTokenAddress, toTokenAddress, amount, userWalletAddress: userAddress, slippagePercent }; // Prepare authentication const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); if (response.data.code === '0') { return response.data.data[0]; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get swap transaction data:', (error as Error).message); throw error; } } ``` ## 6. Simulate Transaction Before executing the actual swap, it's crucial to simulate the transaction to ensure it will succeed and to identify any potential issues: The Simulate API is available to our whitelisted customers only. Please reach out to dexapi@okx.com to request access. ```typescript async function simulateTransaction(swapData: any) { try { if (!swapData.tx) { throw new Error('Invalid swap data format - missing transaction data'); } const tx = swapData.tx; const params: any = { fromAddress: tx.from, toAddress: tx.to, txAmount: tx.value || '0', chainIndex: chainIndex, extJson: { inputData: tx.data }, includeDebug: true }; const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/pre-transaction/simulate"; const requestBody = JSON.stringify(params); const headers = getHeaders(timestamp, "POST", requestPath, "", requestBody); console.log('Simulating transaction...'); const response = await axios.post( `https://web3.okx.com${requestPath}`, params, { headers } ); if (response.data.code !== "0") { throw new Error(`Simulation failed: ${response.data.msg || "Unknown simulation error"}`); } const simulationResult = response.data.data[0]; // Check simulation success if (simulationResult.success === false) { console.error('Transaction simulation failed:', simulationResult.error); throw new Error(`Transaction would fail: ${simulationResult.error}`); } console.log('Transaction simulation successful'); console.log(`Estimated gas used: ${simulationResult.gasUsed || 'N/A'}`); if (simulationResult.logs) { console.log('Simulation logs:', simulationResult.logs); } return simulationResult; } catch (error) { console.error("Error simulating transaction:", error); throw error; } } ``` ## 7. Broadcast Transaction Creating a Compute Gas Limit Utility Function There are two approaches to obtain the gas limit for your transactions: using standard RPC calls or leveraging the Onchain Gateway API. Method 1: Using the Onchain Gateway API for Gas Estimation The first approach leverages OKX's Onchain Gateway API, which provides more accurate gas estimations than standard methods. ```typescript /** * Get transaction gas limit from Onchain gateway API * @param fromAddress - Sender address * @param toAddress - Target contract address * @param txAmount - Transaction amount (0 for approvals) * @param inputData - Transaction calldata * @returns Estimated gas limit */ async function getGasLimit( fromAddress: string, toAddress: string, txAmount: string = '0', inputData: string = '' ): Promise { try { const path = 'dex/pre-transaction/gas-limit'; const url = `https://web3.okx.com/api/v6/${path}`; const body = { chainIndex: chainIndex, fromAddress: fromAddress, toAddress: toAddress, txAmount: txAmount, extJson: { inputData: inputData } }; // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { return response.data.data[0].gasLimit; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get gas limit:', (error as Error).message); throw error; } } ``` Method 2: Using RPC to Estimate Gas Limit The second approach utilizes standard Web3 RPC calls to estimate the required gas for your transaction. ```typescript const gasLimit = await web3.eth.estimateGas({ from: WALLET_ADDRESS, to: tokenAddress, value: '0', data: swapData.data }); // Add 20% buffer const gasLimit = (BigInt(gasLimit) * BigInt(12) / BigInt(10)).toString(); ``` Broadcasting Transactions with the Onchain Gateway API For developers with access to the Onchain Gateway API, you can broadcast transactions directly through OKX's infrastructure. This method provides enhanced reliability and monitoring capabilities for high-volume trading operations. The Broadcast API requires API is available to our whitelisted customers only. Please reach out to dexapi@okx.com to request access. ```typescript import { Web3 } from 'web3'; import axios from 'axios'; import * as dotenv from 'dotenv'; import CryptoJS from 'crypto-js'; // Load environment variables dotenv.config(); // Connect to Base network const web3 = new Web3(process.env.EVM_RPC_URL || 'https://mainnet.base.org'); // Your wallet information - REPLACE WITH YOUR OWN VALUES const WALLET_ADDRESS = process.env.EVM_WALLET_ADDRESS || ''; const PRIVATE_KEY = process.env.EVM_PRIVATE_KEY || ''; // Token addresses for swap on Base Chain const ETH_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'; // Native ETH // Chain ID for Base Chain const chainIndex = '8453'; // API URL const baseUrl = 'https://web3.okx.com/api/v6/'; // Define interfaces interface GasLimitApiResponse { code: string; msg?: string; data: Array<{ gasLimit: string; }>; } // Interface for broadcast API response interface BroadcastApiResponse { code: string; msg?: string; data: Array<{ orderId: string; }>; } /** * Generate API authentication headers */ function getHeaders(timestamp: string, method: string, requestPath: string, queryString = "", body = "") { const apiKey = process.env.OKX_API_KEY; const secretKey = process.env.OKX_SECRET_KEY; const apiPassphrase = process.env.OKX_API_PASSPHRASE; if (!apiKey || !secretKey || !apiPassphrase ) { throw new Error("Missing required environment variables for API authentication"); } const stringToSign = timestamp + method + requestPath + (queryString || body); return { "Content-Type": "application/json", "OK-ACCESS-KEY": apiKey, "OK-ACCESS-SIGN": CryptoJS.enc.Base64.stringify( CryptoJS.HmacSHA256(stringToSign, secretKey) ), "OK-ACCESS-TIMESTAMP": timestamp, "OK-ACCESS-PASSPHRASE": apiPassphrase, }; } /** * Get transaction gas limit from Onchain gateway API * @param fromAddress - Sender address * @param toAddress - Target contract address * @param txAmount - Transaction amount (0 for approvals) * @param inputData - Transaction calldata * @returns Estimated gas limit */ async function getGasLimit( fromAddress: string, toAddress: string, txAmount: string = '0', inputData: string = '' ): Promise { const path = 'dex/pre-transaction/gas-limit'; const url = `${baseUrl}${path}`; const body = { chainIndex: chainIndex, fromAddress, toAddress, txAmount, extJson: { inputData } }; const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const headers = getHeaders(timestamp, 'POST', `/api/v6/${path}`, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { return response.data.data[0].gasLimit; } throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } /** * Get swap data from OKX API */ async function getSwapData( fromTokenAddress: string, toTokenAddress: string, amount: string, slippagePercent = '0.5' ) { const path = 'dex/aggregator/swap'; const url = `${baseUrl}${path}`; const params = { chainIndex: chainIndex, fromTokenAddress, toTokenAddress, amount, slippagePercent, userWalletAddress: WALLET_ADDRESS }; const queryString = "?" + new URLSearchParams(params).toString(); const timestamp = new Date().toISOString(); const headers = getHeaders(timestamp, 'GET', `/api/v6/${path}`, queryString); const response = await axios.get(`${url}${queryString}`, { headers }); const responseData = response.data as any; if (responseData.code === '0') { return responseData.data[0]; } throw new Error(`Swap API Error: ${responseData.msg || 'Unknown error'}`); } /** * Build and sign transaction using gas limit */ async function buildAndSignTransaction(swapData: any, gasLimit: string): Promise { const gasPrice = await web3.eth.getGasPrice(); const nonce = await web3.eth.getTransactionCount(WALLET_ADDRESS, 'pending'); const transaction = { from: swapData.tx.from, to: swapData.tx.to, data: swapData.tx.data, value: swapData.tx.value || '0x0', gas: gasLimit, gasPrice: gasPrice.toString(), nonce: Number(nonce), chainIndex: parseInt(chainIndex) }; return await web3.eth.accounts.signTransaction(transaction, PRIVATE_KEY); } /** * Broadcast transaction using Onchain Gateway API */ async function broadcastTransaction(signedTx: any, chainIndex: string, walletAddress: string): Promise { const path = 'dex/pre-transaction/broadcast-transaction'; const url = `${baseUrl}${path}`; const rawTxHex = typeof signedTx.rawTransaction === 'string' ? signedTx.rawTransaction : web3.utils.bytesToHex(signedTx.rawTransaction); const body = { signedTx: rawTxHex, chainIndex: chainIndex, address: walletAddress }; const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const headers = getHeaders(timestamp, 'POST', `/api/v6/${path}`, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { return response.data.data[0].orderId; } throw new Error(`Broadcast API Error: ${response.data.msg || 'Unknown error'}`); } async function main() { try { console.log('EVM Gas Limit and Broadcast'); console.log('================================'); // Validate environment variables if (!WALLET_ADDRESS || !PRIVATE_KEY) { throw new Error('Missing wallet address or private key in environment variables'); } console.log(`Wallet Address: ${WALLET_ADDRESS}`); console.log(`Chain ID: ${chainIndex}`); console.log(`RPC URL: ${process.env.EVM_RPC_URL || 'https://mainnet.base.org'}`); // Example parameters const fromToken = ETH_ADDRESS; const toToken = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'; // USDC on Base const amount = '100000000000000'; // 0.0001 ETH in wei const slippagePercent = '0.5'; // 0.5% // Step 1: Get swap data const swapData = await getSwapData(fromToken, toToken, amount, slippagePercent); console.log('Swap data obtained'); // Step 2: Get gas limit const gasLimit = await getGasLimit( swapData.tx.from, swapData.tx.to, swapData.tx.value || '0', swapData.tx.data ); console.log('Gas limit obtained', gasLimit); // Step 3: Build and sign transaction const signedTx = await buildAndSignTransaction(swapData, gasLimit); console.log('Transaction built and signed'); // Step 4: Broadcast transaction try { const orderId = await broadcastTransaction(signedTx, chainIndex, swapData.tx.from); console.log(`Transaction broadcast successful. Order ID: ${orderId}`); } catch (broadcastError: any) { if (broadcastError.message.includes('API registration and whitelist required')) { console.log('Broadcast failed - API registration and whitelist required'); console.log('Gas limit obtained successfully:', gasLimit); } else { throw broadcastError; } } } catch (error) { console.error('Main execution failed:', (error as Error).message); process.exit(1); } } // Run the script if (require.main === module) { main(); } export { getSwapData, getGasLimit, broadcastTransaction }; ``` Alternative: Broadcasting Transactions Using Standard RPC For developers who prefer using standard blockchain RPC methods or do not have yet requested API whitelisting, you can broadcast transactions directly to the network using Web3 RPC calls. ```typescript /** * Execute token swap * @param fromTokenAddress - Source token address * @param toTokenAddress - Destination token address * @param amount - Amount to swap * @param slippagePercent - Maximum slippagePercent * @returns Transaction hash */ async function executeSwap( fromTokenAddress: string, toTokenAddress: string, amount: string, slippagePercent: string = '0.5' ): Promise { // 1. Check allowance and approve if necessary (skip for native token) if (fromTokenAddress !== ETH_ADDRESS) { await approveToken(fromTokenAddress, amount); } // 2. Get swap transaction data const swapData = await getSwapTransaction(fromTokenAddress, toTokenAddress, amount, WALLET_ADDRESS, slippagePercent); const txData = swapData.tx; console.log("Swap TX data received"); // 3. Get accurate gas limit const gasLimit = await getGasLimit( WALLET_ADDRESS, txData.to, txData.value || '0', txData.data ); console.log("Gas limit received"); // 4. Get current nonce const nonce = await web3.eth.getTransactionCount(WALLET_ADDRESS, 'latest'); console.log("Nonce received"); // 5. Get current gas price and adjust for faster confirmation const gasPrice = await web3.eth.getGasPrice(); const adjustedGasPrice = BigInt(gasPrice) * BigInt(15) / BigInt(10); // 1.5x for faster confirmation console.log("Gas price received"); // 6. Create transaction object const txObject = { from: WALLET_ADDRESS, to: txData.to, data: txData.data, value: txData.value || '0', gas: gasLimit, gasPrice: adjustedGasPrice.toString(), nonce: nonce }; console.log("TX build complete"); // 7. Sign and broadcast transaction using RPC const signedTx = await web3.eth.accounts.signTransaction(txObject, PRIVATE_KEY); console.log("TX signed"); const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction); console.log(`Transaction successful: ${receipt.transactionHash}`); return receipt.transactionHash; } ``` ## 8. Track Transaction Choose the first(section 8.1) for basic transaction confirmation status, and the second(section 8.2) when you need detailed information about the swap execution itself. 8.1 Using Onchain gateway API The Onchain gateway API provides transaction tracking capabilities through the `/dex/post-transaction/orders` endpoint. Use the order ID returned by the broadcast API to track transactions as they progress through OKX's systems with simple status codes (1: Pending, 2: Success, 3: Failed). ```typescript // Define error info interface interface TxErrorInfo { error: string; message: string; action: string; } /** * Tracking transaction confirmation status using the Onchain gateway API * @param orderId - Order ID from broadcast response * @param intervalMs - Polling interval in milliseconds * @param timeoutMs - Maximum time to wait * @returns Final transaction confirmation status */ async function trackTransaction( orderId: string, intervalMs: number = 5000, timeoutMs: number = 300000 ): Promise { console.log(`Tracking transaction with Order ID: ${orderId}`); const startTime = Date.now(); let lastStatus = ''; while (Date.now() - startTime < timeoutMs) { // Get transaction status try { const path = 'dex/post-transaction/orders'; const url = `https://web3.okx.com/api/v6/${path}`; const params = { orderId: orderId, chainIndex: chainIndex, address: WALLET_ADDRESS, limit: '1' }; // Prepare authentication const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); if (response.data.code === '0' && response.data.data && response.data.data.length > 0) { if (response.data.data[0].orders && response.data.data[0].orders.length > 0) { const txData = response.data.data[0].orders[0]; // Use txStatus to match the API response const status = txData.txStatus; // Only log when status changes if (status !== lastStatus) { lastStatus = status; if (status === '1') { console.log(`Transaction pending: ${txData.txHash || 'Hash not available yet'}`); } else if (status === '2') { console.log(`Transaction successful: https://web3.okx.com/explorer/base/tx/${txData.txHash}`); return txData; } else if (status === '3') { const failReason = txData.failReason || 'Unknown reason'; const errorMessage = `Transaction failed: ${failReason}`; console.error(errorMessage); const errorInfo = handleTransactionError(txData); console.log(`Error type: ${errorInfo.error}`); console.log(`Suggested action: ${errorInfo.action}`); throw new Error(errorMessage); } } } else { console.log(`No orders found for Order ID: ${orderId}`); } } } catch (error) { console.warn('Error checking transaction status:', (error as Error).message); } // Wait before next check await new Promise(resolve => setTimeout(resolve, intervalMs)); } throw new Error('Transaction tracking timed out'); } /** * Comprehensive error handling with failReason * @param txData - Transaction data from post-transaction/orders * @returns Structured error information */ function handleTransactionError(txData: any): TxErrorInfo { const failReason = txData.failReason || 'Unknown reason'; // Log the detailed error console.error(`Transaction failed with reason: ${failReason}`); // Default error handling return { error: 'TRANSACTION_FAILED', message: failReason, action: 'Try again or contact support' }; } ``` 8.2 Track transaction using SWAP API: SWAP API transaction tracking provides comprehensive swap execution details using the `/dex/aggregator/history` endpoint. It offers token-specific information (symbols, amounts), fees paid, and detailed blockchain data. Use this when you need complete swap insight with token-level details. ```typescript /** * Track transaction using SWAP API * @param chainIndex - Chain ID (e.g., 1 for Ethereum Mainnet) * @param txHash - Transaction hash * @returns Transaction details */ async function trackTransactionWithSwapAPI(chainIndex: string, txHash: string): Promise { try { const path = 'dex/aggregator/history'; const url = `${baseUrl}${path}`; const params = { chainIndex: chainIndex, txHash: txHash, isFromMyProject: 'true' }; // Prepare authentication const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); if (response.data.code === '0') { const txData = response.data.data[0]; const status = txData.status; if (status === 'pending') { console.log(`Transaction is still pending: ${txHash}`); return { status: 'pending', details: txData }; } else if (status === 'success') { console.log(`Transaction successful!`); console.log(`From: ${txData.fromTokenDetails.symbol} - Amount: ${txData.fromTokenDetails.amount}`); console.log(`To: ${txData.toTokenDetails.symbol} - Amount: ${txData.toTokenDetails.amount}`); console.log(`Transaction Fee: ${txData.txFee}`); console.log(`Explorer URL: https://basescan.org/tx/${txHash}`); return { status: 'success', details: txData }; } else if (status === 'failure') { console.error(`Transaction failed: ${txData.errorMsg || 'Unknown reason'}`); return { status: 'failure', details: txData }; } return txData; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to track transaction status:', (error as Error).message); throw error; } } ``` ## 9. Complete Implementation Here's a complete implementation example: ```typescript import { Web3 } from 'web3'; import * as axios from 'axios'; import * as dotenv from 'dotenv'; import * as CryptoJS from 'crypto-js'; // Load environment variables dotenv.config(); // Connect to Base network const web3 = new Web3(process.env.EVM_RPC_URL || 'https://mainnet.base.org'); // Your wallet information - REPLACE WITH YOUR OWN VALUES const WALLET_ADDRESS: string = process.env.EVM_WALLET_ADDRESS || ''; const PRIVATE_KEY: string = process.env.EVM_PRIVATE_KEY || ''; // Token addresses for swap on Base Chain const ETH_ADDRESS: string = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'; // Native ETH // Chain ID for Base Chain const chainIndex: string = '8453'; // API URL const baseUrl: string = 'https://web3.okx.com/api/v6/'; // Define interfaces interface TokenInfo { tokenSymbol: string; decimal: string; tokenUnitPrice: string; } // Interface for gas limit API response interface GasLimitApiResponse { code: string; msg?: string; data: Array<{ gasLimit: string; }>; } // Interface for simulation API response interface SimulationApiResponse { code: string; msg?: string; data: Array<{ intention: string; gasUsed?: string; failReason?: string; assetChange?: Array<{ assetType: string; name: string; symbol: string; decimals: number; address: string; imageUrl: string; rawValue: string; }>; risks?: Array; }>; } // Interface for broadcast API response interface BroadcastApiResponse { code: string; msg?: string; data: Array<{ orderId: string; }>; } // Define error info interface interface TxErrorInfo { error: string; message: string; action: string; } /** * Generate API authentication headers */ function getHeaders(timestamp: string, method: string, requestPath: string, queryString = "", body = "") { const apiKey = process.env.OKX_API_KEY; const secretKey = process.env.OKX_SECRET_KEY; const apiPassphrase = process.env.OKX_API_PASSPHRASE; if (!apiKey || !secretKey || !apiPassphrase ) { throw new Error("Missing required environment variables for API authentication"); } const stringToSign = timestamp + method + requestPath + (queryString || body); return { "Content-Type": "application/json", "OK-ACCESS-KEY": apiKey, "OK-ACCESS-SIGN": CryptoJS.enc.Base64.stringify( CryptoJS.HmacSHA256(stringToSign, secretKey) ), "OK-ACCESS-TIMESTAMP": timestamp, "OK-ACCESS-PASSPHRASE": apiPassphrase, }; } /** * Get transaction gas limit from Onchain gateway API * @param fromAddress - Sender address * @param toAddress - Target contract address * @param txAmount - Transaction amount (0 for approvals) * @param inputData - Transaction calldata * @returns Estimated gas limit */ async function getGasLimit( fromAddress: string, toAddress: string, txAmount: string = '0', inputData: string = '' ): Promise { try { console.log('Getting gas limit from Onchain Gateway API...'); const path = 'dex/pre-transaction/gas-limit'; const url = `${baseUrl}${path}`; const body = { chainIndex: chainIndex, fromAddress: fromAddress, toAddress: toAddress, txAmount: txAmount, extJson: { inputData: inputData } }; // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); console.log('Gas Limit API Response:'); console.log(JSON.stringify(response.data, null, 2)); if (response.data.code === '0') { const gasLimit = response.data.data[0].gasLimit; console.log(`Gas Limit obtained: ${gasLimit}`); return gasLimit; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get gas limit:', (error as Error).message); throw error; } } /** * Get swap data from OKX API */ async function getSwapData( fromTokenAddress: string, toTokenAddress: string, amount: string, slippagePercent = '0.5' ) { try { console.log('Getting swap data from OKX API...'); const path = 'dex/aggregator/swap'; const url = `${baseUrl}${path}`; const params = { chainIndex: chainIndex, fromTokenAddress: fromTokenAddress, toTokenAddress: toTokenAddress, amount: amount, slippagePercent: slippagePercent, userWalletAddress: WALLET_ADDRESS }; console.log('Swap API Request Parameters:'); console.log(JSON.stringify(params, null, 2)); // Prepare authentication with query string const queryString = "?" + new URLSearchParams(params).toString(); const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(`${url}${queryString}`, { headers }); console.log('Swap API Response:'); console.log(JSON.stringify(response.data, null, 2)); const responseData = response.data as any; if (responseData.code === '0') { return responseData.data[0]; } else { throw new Error(`Swap API Error: ${responseData.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get swap data:', (error as Error).message); throw error; } } /** * Simulate transaction using Onchain Gateway API */ async function simulateTransaction(swapData: any) { try { console.log('Simulating transaction with Onchain Gateway API...'); const path = 'dex/pre-transaction/simulate'; const url = `${baseUrl}${path}`; const body = { chainIndex: chainIndex, fromAddress: swapData.tx.from, toAddress: swapData.tx.to, txAmount: swapData.tx.value || '0', extJson: { inputData: swapData.tx.data } }; // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); console.log('Simulation API Response:'); console.log(JSON.stringify(response.data, null, 2)); if (response.data.code === '0') { const simulationResult = response.data.data[0]; // Check if simulation was successful (no failReason or empty failReason) if (!simulationResult.failReason || simulationResult.failReason === '') { console.log(`Transaction simulation successful. Gas used: ${simulationResult.gasUsed}`); return simulationResult; } else { throw new Error(`Simulation failed: ${simulationResult.failReason}`); } } else { throw new Error(`Simulation API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Transaction simulation failed:', (error as Error).message); throw error; } } /** * Broadcast transaction using Onchain Gateway API with RPC fallback */ async function broadcastTransaction(signedTx: any, chainIndex: string, walletAddress: string): Promise { try { console.log('Broadcasting transaction via Onchain Gateway API...'); const path = 'dex/pre-transaction/broadcast-transaction'; const url = `${baseUrl}${path}`; // Convert rawTransaction to hex string const rawTxHex = typeof signedTx.rawTransaction === 'string' ? signedTx.rawTransaction : web3.utils.bytesToHex(signedTx.rawTransaction); const body = { signedTx: rawTxHex, chainIndex: chainIndex, address: walletAddress // See [MEV Section](#10-mev-protection) for MEV protection settings }; console.log('Broadcast API Request Body:'); console.log(JSON.stringify(body, null, 2)); // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); console.log('Broadcast API Response:'); console.log(JSON.stringify(response.data, null, 2)); if (response.data.code === '0') { const orderId = response.data.data[0].orderId; console.log(`Transaction broadcast successful. Order ID: ${orderId}`); return orderId; } else { throw new Error(`Broadcast API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('API broadcast failed, trying RPC fallback:', (error as Error).message); // Fallback to RPC broadcast try { console.log('Broadcasting via RPC fallback...'); const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction); console.log(`RPC broadcast successful. Transaction hash: ${receipt.transactionHash}`); return receipt.transactionHash.toString(); } catch (rpcError) { console.error('RPC broadcast also failed:', (rpcError as Error).message); throw new Error(`Both API and RPC broadcast failed. API Error: ${(error as Error).message}, RPC Error: ${(rpcError as Error).message}`); } } } /** * Execute swap with full transaction flow */ async function executeSwap( fromTokenAddress: string, toTokenAddress: string, amount: string, slippagePercent: string = '0.5' ): Promise { try { console.log('Starting swap execution...'); // Step 1: Get swap data const swapData = await getSwapData(fromTokenAddress, toTokenAddress, amount, slippagePercent); console.log('Swap data obtained'); // Step 2: Simulate transaction const simulationResult = await simulateTransaction(swapData); console.log('Transaction simulation completed'); console.log('Simulation result', simulationResult.intention); // Step 3: Get gas limit const gasLimit = await getGasLimit( swapData.tx.from, swapData.tx.to, swapData.tx.value || '0', swapData.tx.data ); // Step 4: Get current gas price const gasPrice = await web3.eth.getGasPrice(); console.log(`Current gas price: ${web3.utils.fromWei(gasPrice, 'gwei')} gwei`); // Step 5: Get nonce const nonce = await web3.eth.getTransactionCount(WALLET_ADDRESS, 'pending'); console.log(`Nonce: ${nonce}`); // Step 6: Build transaction const transaction = { from: swapData.tx.from, to: swapData.tx.to, data: swapData.tx.data, value: swapData.tx.value || '0x0', gas: gasLimit, gasPrice: gasPrice.toString(), nonce: Number(nonce), chainIndex: parseInt(chainIndex) }; console.log('Transaction object:'); console.log(JSON.stringify(transaction, null, 2)); // Step 7: Sign transaction console.log('Signing transaction...'); const signedTx = await web3.eth.accounts.signTransaction(transaction, PRIVATE_KEY); console.log('Transaction signed'); // Step 8: Broadcast transaction const txHash = await broadcastTransaction(signedTx, chainIndex, WALLET_ADDRESS); console.log(`Transaction broadcast successful. Hash: ${txHash}`); // Step 9: Track transaction console.log('Tracking transaction status...'); const trackingResult = await trackTransaction(txHash); console.log('Transaction tracking completed'); console.log('Tracking result', trackingResult); return txHash; } catch (error) { console.error('Swap execution failed:', (error as Error).message); throw error; } } /** * Execute swap with simulation and detailed logging */ async function executeSwapWithSimulation( fromTokenAddress: string, toTokenAddress: string, amount: string, slippagePercent: string = '0.5' ): Promise { try { console.log('Starting swap execution with simulation...'); const txHash = await executeSwap(fromTokenAddress, toTokenAddress, amount, slippagePercent); console.log('Swap execution completed successfully!'); console.log(`Transaction Hash: ${txHash}`); return { success: true, txHash }; } catch (error) { console.error('Swap execution failed:', (error as Error).message); return { success: false, error: (error as Error).message }; } } /** * Tracking transaction confirmation status using the Onchain gateway API * @param orderId - Order ID from broadcast response * @param intervalMs - Polling interval in milliseconds * @param timeoutMs - Maximum time to wait * @returns Final transaction confirmation status */ async function trackTransaction( orderId: string, intervalMs: number = 5000, timeoutMs: number = 300000 ): Promise { console.log(`Tracking transaction with Order ID: ${orderId}`); const startTime = Date.now(); let lastStatus = ''; while (Date.now() - startTime < timeoutMs) { try { const path = 'dex/post-transaction/orders'; const url = `https://web3.okx.com/api/v6/${path}`; const params = { orderId: orderId, chainIndex: chainIndex, address: WALLET_ADDRESS, limit: '1' }; const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); const responseData = response.data as any; if (responseData.code === '0' && responseData.data && responseData.data.length > 0) { if (responseData.data[0].orders && responseData.data[0].orders.length > 0) { const txData = responseData.data[0].orders[0]; const status = txData.txStatus; if (status !== lastStatus) { lastStatus = status; if (status === '1') { console.log(`Transaction pending: ${txData.txHash || 'Hash not available yet'}`); } else if (status === '2') { console.log(`Transaction successful: https://web3.okx.com/explorer/base/tx/${txData.txHash}`); return txData; } else if (status === '3') { const failReason = txData.failReason || 'Unknown reason'; const errorMessage = `Transaction failed: ${failReason}`; console.error(errorMessage); const errorInfo = handleTransactionError(txData); console.log(`Error type: ${errorInfo.error}`); console.log(`Suggested action: ${errorInfo.action}`); throw new Error(errorMessage); } } } else { console.log(`No orders found for Order ID: ${orderId}`); } } } catch (error) { console.warn('Error checking transaction status:', (error as Error).message); } await new Promise(resolve => setTimeout(resolve, intervalMs)); } throw new Error('Transaction tracking timed out'); } /** * Comprehensive error handling with failReason * @param txData - Transaction data from post-transaction/orders * @returns Structured error information */ function handleTransactionError(txData: any): TxErrorInfo { const failReason = txData.failReason || 'Unknown reason'; console.error(`Transaction failed with reason: ${failReason}`); return { error: 'TRANSACTION_FAILED', message: failReason, action: 'Try again or contact support' }; } // ======== Main Execution ======== async function simulateOnly( fromTokenAddress: string, toTokenAddress: string, amount: string, slippagePercent: string = '0.5' ): Promise { try { console.log('Starting simulation-only mode...'); console.log(`Simulation Details:`); console.log(` From Token: ${fromTokenAddress}`); console.log(` To Token: ${toTokenAddress}`); console.log(` Amount: ${amount}`); console.log(` SlippagePercent: ${slippagePercent}%`); // Step 1: Get swap data const swapData = await getSwapData(fromTokenAddress, toTokenAddress, amount, slippagePercent); console.log('Swap data obtained'); // Step 2: Simulate transaction const simulationResult = await simulateTransaction(swapData); console.log('Transaction simulation completed'); // Step 3: Get gas limit const gasLimit = await getGasLimit( swapData.tx.from, swapData.tx.to, swapData.tx.value || '0', swapData.tx.data ); return { success: true, swapData, simulationResult, gasLimit, estimatedGasUsed: simulationResult.gasUsed, }; } catch (error) { console.error('Simulation failed:', (error as Error).message); return { success: false, error: (error as Error).message }; } } async function main() { try { console.log('EVM Swap Tools with Onchain Gateway API'); console.log('====================================='); // Validate environment variables if (!WALLET_ADDRESS || !PRIVATE_KEY) { throw new Error('Missing wallet address or private key in environment variables'); } console.log(`Wallet Address: ${WALLET_ADDRESS}`); console.log(`Chain ID: ${chainIndex}`); console.log(`RPC URL: ${process.env.EVM_RPC_URL || 'https://mainnet.base.org'}`); // Parse command line arguments const args = process.argv.slice(2); const mode = args[0] || 'simulate'; // Default to simulate mode // Example parameters const fromToken = ETH_ADDRESS; const toToken = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'; // USDC on Base const amount = '100000000000000'; // 0.0001 ETH in wei const slippagePercent = '0.5'; // 0.5% console.log('\nConfiguration:'); console.log(` From: ${fromToken} (ETH)`); console.log(` To: ${toToken} (USDC)`); console.log(` Amount: ${web3.utils.fromWei(amount, 'ether')} ETH`); console.log(` SlippagePercent: ${slippagePercent}%`); console.log(` Mode: ${mode}`); let result; switch (mode.toLowerCase()) { case 'simulate': case 'sim': result = await simulateOnly(fromToken, toToken, amount, slippagePercent); break; case 'execute': case 'exec': result = await executeSwapWithSimulation(fromToken, toToken, amount, slippagePercent); break; default: console.log('\nAvailable modes:'); console.log(' simulate/sim - Only simulate the transaction'); console.log(' execute/exec - Execute the full swap'); console.log('\nExample: npm run evm-swap simulate'); return; } if (result.success) { console.log('\nOperation completed successfully!'); if (mode === 'simulate' || mode === 'sim') { console.log(`Gas Limit: ${result.gasLimit}`); } else { console.log(`Transaction Hash: ${result.txHash}`); } } else { console.log('\nOperation failed!'); console.log(`Error: ${result.error}`); } } catch (error) { console.error('Main execution failed:', (error as Error).message); process.exit(1); } } // Run the script if (require.main === module) { main(); } export { executeSwap, executeSwapWithSimulation, simulateOnly, getSwapData, simulateTransaction, getGasLimit, broadcastTransaction, trackTransaction }; ``` You can run this script using `evm-swap.ts sim` or `evm-swap.ts exec`. `sim` simulates a transaction using swap data using the transaction simulation API and retruns `gasLimit` info `exec` executes a transaction using the broadcast API ## 10. MEV Protection ### MEV Protection with Broadcast Transaction API The OKX Broadcast Transaction API provides built-in MEV protection capabilities to help safeguard your transactions from front-running and sandwich attacks. The Broadcast API is available to our whitelisted customers only. Please reach out to dexapi@okx.com to request access. **Disclaimer:** Your end-user's transaction can only be covered by the MEV protection feature if you actually utilise OKX Build's API services for that particular transaction. MEV protection is currently an experimental feature provided by third-parties and OKX Build does not guarantee the effectiveness and quality of such MEV protection. #### Adding MEV Protection To enable MEV protection on EVM chains, add the `extraData` field to your broadcast transaction request with `enableMevProtection: true`: ```tsx /** * Broadcast transaction with MEV protection enabled for EVM chains */ async function broadcastTransactionWithMEV( signedTx: string, chainIndex: string = "8453", // Base chain walletAddress: string, enableMevProtection: boolean = true ): Promise { try { console.log('Broadcasting transaction with MEV protection...'); const path = 'dex/pre-transaction/broadcast-transaction'; const url = `https://web3.okx.com/api/v6/${path}`; const body = { signedTx: signedTx, chainIndex: chainIndex, address: walletAddress, extraData: JSON.stringify({ enableMevProtection: enableMevProtection }) }; const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { const orderId = response.data.data[0].orderId; console.log(`Transaction broadcast with MEV protection. Order ID: ${orderId}`); return orderId; } else { throw new Error(`Broadcast API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('MEV-protected broadcast failed:', error); throw error; } } ``` #### Usage Examples **Basic swap without MEV protection:** ```tsx // Standard broadcast (no MEV protection) for Base chain const orderId = await broadcastTransaction(signedTx, "8453", walletAddress); ``` **Swap with MEV protection enabled:** ```tsx // With MEV protection on Base chain const orderId = await broadcastTransactionWithMEVOptions(signedTx, "8453", walletAddress, true); ``` #### Integration with Complete Swap Flow Here's how to integrate MEV protection into your complete EVM swap execution: ```tsx /** * Execute EVM swap with MEV protection */ async function executeSwapWithMEVProtection( fromTokenAddress: string, toTokenAddress: string, amount: string, slippagePercent: string = '0.5', enableMevProtection: boolean = true, chainIndex: string = "8453" // Base chain ): Promise { try { // Step 1: Check allowance and approve if necessary (skip for native token) if (fromTokenAddress !== ETH_ADDRESS) { await approveToken(fromTokenAddress, amount); } // Step 2: Get swap transaction data const swapData = await getSwapTransaction(fromTokenAddress, toTokenAddress, amount, WALLET_ADDRESS, slippagePercent); const txData = swapData.tx; console.log("Swap TX data received"); // Step 3: Get current gas price and nonce const gasPrice = await web3.eth.getGasPrice(); const adjustedGasPrice = BigInt(gasPrice) * BigInt(15) / BigInt(10); // 1.5x for faster confirmation const nonce = await web3.eth.getTransactionCount(WALLET_ADDRESS, 'latest'); // Step 4: Create and sign transaction object const txObject = { from: WALLET_ADDRESS, to: txData.to, data: txData.data, value: txData.value || '0', gas: '300000', // Default gas limit gasPrice: adjustedGasPrice.toString(), nonce: nonce }; const signedTx = await web3.eth.accounts.signTransaction(txObject, PRIVATE_KEY); console.log("Transaction signed"); // Step 5: Broadcast with MEV protection const orderId = await broadcastTransactionWithMEVOptions( signedTx.rawTransaction, chainIndex, WALLET_ADDRESS, enableMevProtection ); // Step 6: Track transaction const result = await trackTransaction(orderId); return result.txHash; } catch (error) { console.error("MEV-protected swap failed:", error); throw error; } } ``` The MEV protection feature integrates seamlessly with your existing EVM and Solana swap implementation and provides an additional layer of security against MEV attacks across Solana, Base, Ethereum and BSC. ## Method 2: SDK approach Using the OKX DEX SDK provides a much simpler developer experience while retaining all the functionality of the API-first approach. The SDK handles many implementation details for you, including retry logic, error handling, and transaction management. ## 1. Install the SDK ```typescript npm install @okx-dex/okx-dex-sdk # or yarn add @okx-dex/okx-dex-sdk # or pnpm add @okx-dex/okx-dex-sdk ``` ## 2. Setup Your Environment Create a .env file with your API credentials and wallet information: ```typescript # OKX API Credentials OKX_API_KEY=your_api_key OKX_SECRET_KEY=your_secret_key OKX_API_PASSPHRASE=your_passphrase # EVM Configuration EVM_RPC_URL=your_evm_rpc_url EVM_WALLET_ADDRESS=your_evm_wallet_address EVM_PRIVATE_KEY=your_evm_private_key ``` ## 3. Initialize the Client Create a file for your DEX client (e.g., DexClient.ts): ```typescript // DexClient.ts import { OKXDexClient } from '@okx-dex/okx-dex-sdk'; import { createEVMWallet } from '@okx-dex/okx-dex-sdk/core/evm-wallet'; import { createWallet } from '@okx-dex/okx-dex-sdk/core/wallet'; import { Connection } from '@solana/web3.js'; import { ethers } from 'ethers'; import dotenv from 'dotenv'; dotenv.config(); // EVM setup (Ethereum, Base, Arbitrum, etc.) const evmProvider = new ethers.JsonRpcProvider(process.env.EVM_RPC_URL!); const evmWallet = createEVMWallet(process.env.EVM_PRIVATE_KEY!, evmProvider); // Initialize the client const client = new OKXDexClient({ // API credentials (get from OKX Developer Portal) apiKey: process.env.OKX_API_KEY!, secretKey: process.env.OKX_SECRET_KEY!, apiPassphrase: process.env.OKX_API_PASSPHRASE!, // EVM configuration (works for all EVM chains) evm: { wallet: evmWallet }, }) ``` ## 4. Token Approval With the SDK Create an approval utility function: ```typescript // approval.ts import { client } from './DexClient'; // Helper function to convert human-readable amounts to base units export function toBaseUnits(amount: string, decimals: number): string { // Remove any decimal point and count the decimal places const [integerPart, decimalPart = ''] = amount.split('.'); const currentDecimals = decimalPart.length; // Combine integer and decimal parts, removing the decimal point let result = integerPart + decimalPart; // Add zeros if you need more decimal places if (currentDecimals < decimals) { result = result + '0'.repeat(decimals - currentDecimals); } // Remove digits if you have too many decimal places else if (currentDecimals > decimals) { result = result.slice(0, result.length - (currentDecimals - decimals)); } // Remove leading zeros result = result.replace(/^0+/, '') || '0'; return result; } /** * Example: Approve a token for swapping */ async function executeApproval(tokenAddress: string, amount: string) { try { // Get token information using quote console.log("Getting token information..."); const tokenInfo = await client.dex.getQuote({ chainIndex: '8453', // Base Chain fromTokenAddress: tokenAddress, toTokenAddress: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // Native token amount: '1000000', // Use a reasonable amount for quote slippagePercent: '0.5' }); const tokenDecimals = parseInt(tokenInfo.data[0].fromToken.decimal); const rawAmount = toBaseUnits(amount, tokenDecimals); console.log(`\nApproval Details:`); console.log(`--------------------`); console.log(`Token: ${tokenInfo.data[0].fromToken.tokenSymbol}`); console.log(`Amount: ${amount} ${tokenInfo.data[0].fromToken.tokenSymbol}`); console.log(`Amount in base units: ${rawAmount}`); // Execute the approval console.log("\nExecuting approval..."); const result = await client.dex.executeApproval({ chainIndex: '8453', // Base Chain tokenContractAddress: tokenAddress, approveAmount: rawAmount }); if ('alreadyApproved' in result) { console.log("\nToken already approved for the requested amount!"); return { success: true, alreadyApproved: true }; } else { console.log("\nApproval completed successfully!"); console.log("Transaction Hash:", result.transactionHash); console.log("Explorer URL:", result.explorerUrl); return result; } } catch (error) { if (error instanceof Error) { console.error('Error executing approval:', error.message); } throw error; } } // Run if this file is executed directly if (require.main === module) { // Example usage: ts-node approval.ts 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 1000 const args = process.argv.slice(2); if (args.length !== 2) { console.log("Usage: ts-node approval.ts "); console.log("\nExamples:"); console.log(" # Approve 1000 USDC"); console.log(` ts-node approval.ts 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 1000`); process.exit(1); } const [tokenAddress, amount] = args; executeApproval(tokenAddress, amount) .then(() => process.exit(0)) .catch((error) => { console.error('Error:', error); process.exit(1); }); } export { executeApproval }; ``` ## 5. Execute a Swap With the SDK Create a swap execution file: ```typescript // swap.ts import { client } from './DexClient'; /** * Example: Execute a swap from ETH to USDC on Base chain */ async function executeSwap() { try { if (!process.env.EVM_PRIVATE_KEY) { throw new Error('Missing EVM_PRIVATE_KEY in .env file'); } // You can change this to any EVM chain // For example, for Base, use chainIndex: '8453' // For example, for baseSepolia, use chainIndex: '84532' // You can also use SUI, use chainIndex: '784' // When using another Chain, you need to change the fromTokenAddress and toTokenAddress to the correct addresses for that chain const swapResult = await client.dex.executeSwap({ chainIndex: '8453', // Base chain ID fromTokenAddress: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // Native ETH toTokenAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC on Base amount: String(10 * 10 ** 14), // .0001 ETH slippagePercent: '0.5', // 0.5% slippagePercent userWalletAddress: process.env.EVM_WALLET_ADDRESS! }); console.log('Swap executed successfully:'); console.log(JSON.stringify(swapResult, null, 2)); return swapResult; } catch (error) { if (error instanceof Error) { console.error('Error executing swap:', error.message); // API errors include details in the message if (error.message.includes('API Error:')) { const match = error.message.match(/API Error: (.*)/); if (match) console.error('API Error Details:', match[1]); } } throw error; } } // Run if this file is executed directly if (require.main === module) { executeSwap() .then(() => process.exit(0)) .catch((error) => { console.error('Error:', error); process.exit(1); }); } export { executeSwap }; ``` ## 6. Additional SDK Functionality The SDK provides additional methods that simplify development: Get a quote for a token pair ```typescript const quote = await client.dex.getQuote({ chainIndex: '8453', // Base Chain fromTokenAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC toTokenAddress: '0x4200000000000000000000000000000000000006', // WETH amount: '1000000', // 1 USDC (in smallest units) slippagePercent: '0.5' // 0.5% }); ``` - [Build Swap Applications on Sui](https://web3.okx.com/onchainos/dev-docs/trade/dex-use-swap-sui-quick-start.md) # Build Swap Applications on Sui There are two approaches to building swap applications with OKX DEX on Sui: - The API-first approach directly interacting with OKX DEX API endpoints - The SDK approach using the @okx-dex/okx-dex-sdk package for a simplified developer experience This guide covers both methods to help you choose the approach that best fits your needs. ## Method 1: API-first Approach In this guide, we will provide a use case for Sui token exchange through the OKX DEX. ## 1. Set Up Your Environment Import the necessary Node.js libraries and set up your environment variables: ```javascript // Required libraries import { SuiWallet } from "@okxweb3/coin-sui"; import { getFullnodeUrl, SuiClient } from '@mysten/sui/client'; import { Transaction } from '@mysten/sui/transactions'; import cryptoJS from "crypto-js"; // Install dependencies // npm i @okxweb3/coin-sui // npm i @mysten/sui // npm i crypto-js // Set up environment variables const apiKey = 'your_api_key'; const secretKey = 'your_secret_key'; const apiPassphrase = 'your_passphrase'; const userAddress = 'your_sui_wallet_address'; const userPrivateKey = 'your_sui_wallet_private_key'; // Constants const SUI_CHAIN_ID = "784"; const DEFAULT_GAS_BUDGET = 50000000; const MAX_RETRIES = 3; // Initialize Sui client const wallet = new SuiWallet(); const client = new SuiClient({ url: getFullnodeUrl('mainnet') }); // For Sui, you need to use the hexWithoutFlag format of your private key // You can convert your key using sui keytool: // sui keytool convert ``` ## 2. Obtain Token Information and Swap Quote First, create a utility function to handle API authentication headers: ```javascript function getHeaders(timestamp, method, requestPath, queryString = "") { if (!apiKey || !secretKey || !apiPassphrase ) { throw new Error("Missing required environment variables"); } const stringToSign = timestamp + method + requestPath + queryString; return { "Content-Type": "application/json", "OK-ACCESS-KEY": apiKey, "OK-ACCESS-SIGN": cryptoJS.enc.Base64.stringify( cryptoJS.HmacSHA256(stringToSign, secretKey) ), "OK-ACCESS-TIMESTAMP": timestamp, "OK-ACCESS-PASSPHRASE": apiPassphrase, }; } ``` Then, create a function to get token information: ```javascript async function getTokenInfo(fromTokenAddress, toTokenAddress) { const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/aggregator/quote"; const params = { chainIndex: SUI_CHAIN_ID, fromTokenAddress, toTokenAddress, amount: "1000000", slippagePercent: "0.5",// 0.5% slippagePercent }; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); const response = await fetch( `https://web3.okx.com${requestPath}${queryString}`, { method: "GET", headers } ); if (!response.ok) { throw new Error(`Failed to get quote: ${await response.text()}`); } const data = await response.json(); if (data.code !== "0" || !data.data?.[0]) { throw new Error("Failed to get token information"); } const quoteData = data.data[0]; return { fromToken: { symbol: quoteData.fromToken.tokenSymbol, decimals: parseInt(quoteData.fromToken.decimal), price: quoteData.fromToken.tokenUnitPrice }, toToken: { symbol: quoteData.toToken.tokenSymbol, decimals: parseInt(quoteData.toToken.decimal), price: quoteData.toToken.tokenUnitPrice } }; } ``` Create a function to convert human-readable amounts to base units: ```javascript function convertAmount(amount, decimals) { try { if (!amount || isNaN(parseFloat(amount))) { throw new Error("Invalid amount"); } const value = parseFloat(amount); if (value <= 0) { throw new Error("Amount must be greater than 0"); } return (BigInt(Math.floor(value * Math.pow(10, decimals)))).toString(); } catch (err) { console.error("Amount conversion error:", err); throw new Error("Invalid amount format"); } } ``` ## 3. Get Swap Data 3.1 Define swap parameters ```typescript const swapParams = { chainIndex: chainIndex, fromTokenAddress, toTokenAddress, amount, userWalletAddress: userAddress, slippagePercent }; ``` 3.2 Request swap transaction data ```typescript /** * Get swap transaction data from DEX API * @param fromTokenAddress - Source token address * @param toTokenAddress - Destination token address * @param amount - Amount to swap * @param userAddress - User wallet address * @param slippagePercent - Maximum slippagePercent (e.g., "0.5" for 0.5%) * @returns Swap transaction data */ async function getSwapTransaction( fromTokenAddress: string, toTokenAddress: string, amount: string, userAddress: string, slippagePercent: string = '0.5' ): Promise { try { const path = 'dex/aggregator/swap'; const url = `${baseUrl}${path}`; const params = { chainIndex: chainIndex, fromTokenAddress, toTokenAddress, amount, userWalletAddress: userAddress, slippagePercent }; // Prepare authentication const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); if (response.data.code === '0') { return response.data.data[0]; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get swap transaction data:', (error as Error).message); throw error; } } ``` ## 4. Simulate Transaction Before executing the actual swap, it's crucial to simulate the transaction to ensure it will succeed and to identify any potential issues: The Simulate API is available to our whitelisted customers only. Please reach out to dexapi@okx.com to request access. ```javascript async function simulateTransaction(txData) { try { if (!txData) { throw new Error('Invalid transaction data format'); } const params = { chainIndex: SUI_CHAIN_ID, txData: txData, includeDebug: true }; const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/pre-transaction/simulate"; const requestBody = JSON.stringify(params); const headers = getHeaders(timestamp, "POST", requestPath, "", requestBody); console.log('Simulating transaction...'); const response = await fetch( `https://web3.okx.com${requestPath}`, { method: 'POST', headers, body: requestBody } ); const data = await response.json(); if (data.code !== "0") { throw new Error(`Simulation failed: ${data.msg || "Unknown simulation error"}`); } const simulationResult = data.data[0]; // Check simulation success if (simulationResult.success === false) { console.error('Transaction simulation failed:', simulationResult.error); throw new Error(`Transaction would fail: ${simulationResult.error}`); } console.log('Transaction simulation successful'); console.log(`Estimated gas used: ${simulationResult.gasUsed || 'N/A'}`); if (simulationResult.logs) { console.log('Simulation logs:', simulationResult.logs); } return simulationResult; } catch (error) { console.error("Error simulating transaction:", error); throw error; } } ``` ## 5. Execute the Transaction First, prepare and sign the transaction: ```javascript async function executeSwap(txData, privateKey) { // Create transaction block const txBlock = Transaction.from(txData); txBlock.setSender(normalizedWalletAddress); // Set gas parameters const referenceGasPrice = await client.getReferenceGasPrice(); txBlock.setGasPrice(BigInt(referenceGasPrice)); txBlock.setGasBudget(BigInt(DEFAULT_GAS_BUDGET)); // Build and sign transaction const builtTx = await txBlock.build({ client }); const txBytes = Buffer.from(builtTx).toString('base64'); const signedTx = await wallet.signTransaction({ privateKey, data: { type: 'raw', data: txBytes } }); if (!signedTx?.signature) { throw new Error("Failed to sign transaction"); } return { builtTx, signature: signedTx.signature }; } ``` Then, send the transaction using RPC method calls Using RPC: ```javascript async function sendTransaction(builtTx, signature) { // Execute transaction const result = await client.executeTransactionBlock({ transactionBlock: builtTx, signature: [signature], options: { showEffects: true, showEvents: true, } }); // Wait for confirmation const confirmation = await client.waitForTransaction({ digest: result.digest, options: { showEffects: true, showEvents: true, } }); console.log("\nSwap completed successfully!"); console.log("Transaction ID:", result.digest); console.log("Explorer URL:", `https://suiscan.xyz/mainnet/tx/${result.digest}`); return result.digest; } ``` ## 6. Track Transaction Track transaction using SWAP API: SWAP API transaction tracking provides comprehensive swap execution details using the `/dex/aggregator/history` endpoint. It offers token-specific information (symbols, amounts), fees paid, and detailed blockchain data. Use this when you need complete swap insight with token-level details. ```javascript async function trackTransactionWithSwapAPI(txHash) { try { const path = 'dex/aggregator/history'; const url = `${baseUrl}${path}`; const params = { chainIndex: SUI_CHAIN_ID, txHash: txHash, isFromMyProject: 'false' }; const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); console.log('Fetching transaction status...'); const response = await fetch(`${url}${queryString}`, { headers }); const data = await response.json(); if (!data) { throw new Error('No response data received from API'); } if (data.code !== '0') { throw new Error(`API Error: ${data.msg || 'Unknown error'}`); } if (!data.data || !Array.isArray(data.data) || data.data.length === 0) { console.log('Transaction not found in history yet, might be too recent'); return { status: 'pending', details: null }; } const txData = data.data[0]; if (!txData) { console.log('Transaction data not available yet'); return { status: 'pending', details: null }; } const status = txData.status; console.log(`Transaction status: ${status}`); if (status === 'pending') { console.log(`Transaction is still pending: ${txHash}`); return { status: 'pending', details: txData }; } else if (status === 'success') { console.log(`Transaction successful!`); console.log(`From: ${txData.fromTokenDetails.symbol} - Amount: ${txData.fromTokenDetails.amount}`); console.log(`To: ${txData.toTokenDetails.symbol} - Amount: ${txData.toTokenDetails.amount}`); console.log(`Transaction Fee: ${txData.txFee}`); console.log(`Explorer URL: https://suiscan.xyz/mainnet/tx/${txHash}`); return { status: 'success', details: txData }; } else if (status === 'fail') { const errorMsg = txData.errorMsg || 'Unknown reason'; console.error(`Transaction failed: ${errorMsg}`); return { status: 'failure', details: txData, error: errorMsg }; } return { status: 'unknown', details: txData }; } catch (error) { console.error('Failed to track transaction status:', error.message); return { status: 'pending', details: null, error: error.message }; } } ``` ## 7. Complete Implementation Here's a complete implementation putting it all together: ```javascript // swap.ts import { SuiWallet } from "@okxweb3/coin-sui"; import { getFullnodeUrl, SuiClient } from '@mysten/sui/client'; import { Transaction } from '@mysten/sui/transactions'; import cryptoJS from "crypto-js"; import dotenv from 'dotenv'; dotenv.config(); // Environment variables const apiKey = process.env.OKX_API_KEY; const secretKey = process.env.OKX_SECRET_KEY; const apiPassphrase = process.env.OKX_API_PASSPHRASE; const userAddress = process.env.WALLET_ADDRESS; const userPrivateKey = process.env.PRIVATE_KEY; // Constants const SUI_CHAIN_ID = "784"; const DEFAULT_GAS_BUDGET = 50000000; const MAX_RETRIES = 3; // Initialize clients const wallet = new SuiWallet(); const client = new SuiClient({ url: getFullnodeUrl('mainnet') }); // Normalize wallet address const normalizedWalletAddress = userAddress; function getHeaders(timestamp: string, method: string, requestPath: string, queryString: string = "", requestBody: string = "") { if (!apiKey || !secretKey || !apiPassphrase) { throw new Error("Missing required environment variables"); } const stringToSign = timestamp + method + requestPath + queryString + requestBody; return { "Content-Type": "application/json", "OK-ACCESS-KEY": apiKey, "OK-ACCESS-SIGN": cryptoJS.enc.Base64.stringify( cryptoJS.HmacSHA256(stringToSign, secretKey) ), "OK-ACCESS-TIMESTAMP": timestamp, "OK-ACCESS-PASSPHRASE": apiPassphrase, }; } async function getTokenInfo(fromTokenAddress: string, toTokenAddress: string) { const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/aggregator/quote"; const params = { chainIndex: SUI_CHAIN_ID, fromTokenAddress, toTokenAddress, amount: "1000000", slippagePercent: "0.5",// 0.5% slippagePercent }; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); const response = await fetch( `https://web3.okx.com${requestPath}${queryString}`, { method: "GET", headers } ); if (!response.ok) { throw new Error(`Failed to get quote: ${await response.text()}`); } const data = await response.json(); if (data.code !== "0" || !data.data?.[0]) { throw new Error("Failed to get token information"); } const quoteData = data.data[0]; return { fromToken: { symbol: quoteData.fromToken.tokenSymbol, decimals: parseInt(quoteData.fromToken.decimal), price: quoteData.fromToken.tokenUnitPrice }, toToken: { symbol: quoteData.toToken.tokenSymbol, decimals: parseInt(quoteData.toToken.decimal), price: quoteData.toToken.tokenUnitPrice } }; } function convertAmount(amount: string | number, decimals: number) { try { if (!amount || isNaN(parseFloat(amount.toString()))) { throw new Error("Invalid amount"); } const value = parseFloat(amount.toString()); if (value <= 0) { throw new Error("Amount must be greater than 0"); } return (BigInt(Math.floor(value * Math.pow(10, decimals)))).toString(); } catch (err) { console.error("Amount conversion error:", err); throw new Error("Invalid amount format"); } } async function trackTransactionWithSwapAPI(txHash: string) { try { const path = 'dex/aggregator/history'; const url = `https://web3.okx.com/api/v6/${path}`; const params = { chainIndex: SUI_CHAIN_ID, txHash: txHash, isFromMyProject: 'false' }; const timestamp = new Date().toISOString(); const requestPath = `/api/v6/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await fetch(`${url}${queryString}`, { headers }); const data = await response.json(); if (data.code !== '0') { throw new Error(`API Error: ${data.msg || 'Unknown error'}`); } return data.data?.[0] || { status: 'pending' }; } catch (error) { console.error('Failed to track transaction:', error); return { status: 'error', error: error instanceof Error ? error.message : 'Unknown error' }; } } async function main() { try { const args = process.argv.slice(2); if (args.length < 3) { console.log("Usage: ts-node swap.ts "); console.log("Example: ts-node swap.ts 1.5 0x2::sui::SUI 0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC"); process.exit(1); } const [amount, fromTokenAddress, toTokenAddress] = args; if (!userPrivateKey || !userAddress) { throw new Error("Private key or user address not found"); } // Get token information console.log("Getting token information..."); const tokenInfo = await getTokenInfo(fromTokenAddress, toTokenAddress); console.log(`From: ${tokenInfo.fromToken.symbol} (${tokenInfo.fromToken.decimals} decimals)`); console.log(`To: ${tokenInfo.toToken.symbol} (${tokenInfo.toToken.decimals} decimals)`); // Convert amount using fetched decimals const rawAmount = convertAmount(amount, tokenInfo.fromToken.decimals); console.log(`Amount in ${tokenInfo.fromToken.symbol} base units:`, rawAmount); // Get swap quote const quoteParams = { chainIndex: SUI_CHAIN_ID, amount: rawAmount, fromTokenAddress, toTokenAddress, slippagePercent: "0.5",// 0.5% slippagePercent userWalletAddress: normalizedWalletAddress || "", }; // Get swap data const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/aggregator/swap"; const queryString = "?" + new URLSearchParams(quoteParams).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); console.log("Requesting swap quote..."); const response = await fetch( `https://web3.okx.com${requestPath}${queryString}`, { method: "GET", headers } ); const data = await response.json(); if (data.code !== "0") { throw new Error(`API Error: ${data.msg}`); } const swapData = data.data[0]; // Show estimated output and price impact const outputAmount = parseFloat(swapData.routerResult.toTokenAmount) / Math.pow(10, tokenInfo.toToken.decimals); console.log("\nSwap Quote:"); console.log(`Input: ${amount} ${tokenInfo.fromToken.symbol} ($${(parseFloat(amount) * parseFloat(tokenInfo.fromToken.price)).toFixed(2)})`); console.log(`Output: ${outputAmount.toFixed(tokenInfo.toToken.decimals)} ${tokenInfo.toToken.symbol} ($${(outputAmount * parseFloat(tokenInfo.toToken.price)).toFixed(2)})`); if (swapData.priceImpactPercent) { console.log(`Price Impact: ${swapData.priceImpactPercent}%`); } console.log("\nExecuting swap transaction..."); let retryCount = 0; while (retryCount < MAX_RETRIES) { try { // Create transaction block const txBlock = Transaction.from(swapData.tx.data); if (!normalizedWalletAddress) { throw new Error("Wallet address is not defined"); } txBlock.setSender(normalizedWalletAddress); // Set gas parameters const referenceGasPrice = await client.getReferenceGasPrice(); txBlock.setGasPrice(BigInt(referenceGasPrice)); txBlock.setGasBudget(BigInt(DEFAULT_GAS_BUDGET)); // Build and sign transaction const builtTx = await txBlock.build({ client }); const txBytes = Buffer.from(builtTx).toString('base64'); const signedTx = await wallet.signTransaction({ privateKey: userPrivateKey, data: { type: 'raw', data: txBytes } }); if (!signedTx?.signature) { throw new Error("Failed to sign transaction"); } // Execute transaction const result = await client.executeTransactionBlock({ transactionBlock: builtTx, signature: [signedTx.signature], options: { showEffects: true, showEvents: true, } }); // Wait for confirmation const confirmation = await client.waitForTransaction({ digest: result.digest, options: { showEffects: true, showEvents: true, } }); console.log("\nSwap completed successfully!"); console.log("Transaction ID:", result.digest); console.log("Explorer URL:", `https://suiscan.xyz/mainnet/tx/${result.digest}`); // Track transaction const txStatus = await trackTransactionWithSwapAPI(result.digest); console.log("Transaction Status:", txStatus); process.exit(0); } catch (error) { console.error(`Attempt ${retryCount + 1} failed:`, error); retryCount++; if (retryCount === MAX_RETRIES) { throw error; } await new Promise(resolve => setTimeout(resolve, 2000 * retryCount)); } } } catch (error) { console.error("Error:", error instanceof Error ? error.message : "Unknown error"); process.exit(1); } } if (require.main === module) { main(); } ``` ## Method 2: SDK Approach Using the OKX DEX SDK provides a much simpler developer experience while retaining all the functionality of the API-first approach. The SDK handles many implementation details for you, including retry logic, error handling, and transaction management. ## 1. Install the SDK ```javascript npm install @okx-dex/okx-dex-sdk # or yarn add @okx-dex/okx-dex-sdk # or pnpm add @okx-dex/okx-dex-sdk ``` ## 2. Setup Your Environment Create a .env file with your API credentials and wallet information: ```javascript # OKX API Credentials OKX_API_KEY=your_api_key OKX_SECRET_KEY=your_secret_key OKX_API_PASSPHRASE=your_passphrase # Sui Configuration SUI_WALLET_ADDRESS=your_sui_wallet_address SUI_PRIVATE_KEY=your_sui_private_key ``` Remember that you need to use the hexWithoutFlag format of your SUI private key, which you can obtain using the SUI CLI: ```javascript sui keytool convert ``` ## 3. Initialize the Client Create a file for your DEX client (e.g., DexClient.ts): ```javascript // DexClient.ts import { OKXDexClient } from '@okx-dex/okx-dex-sdk'; import 'dotenv/config'; // Validate environment variables const requiredEnvVars = [ 'OKX_API_KEY', 'OKX_SECRET_KEY', 'OKX_API_PASSPHRASE', 'SUI_WALLET_ADDRESS', 'SUI_PRIVATE_KEY' ]; for (const envVar of requiredEnvVars) { if (!process.env[envVar]) { throw new Error(`Missing required environment variable: ${envVar}`); } } // Initialize the client export const client = new OKXDexClient({ apiKey: process.env.OKX_API_KEY!, secretKey: process.env.OKX_SECRET_KEY!, apiPassphrase: process.env.OKX_API_PASSPHRASE!, sui: { privateKey: process.env.SUI_PRIVATE_KEY!, walletAddress: process.env.SUI_WALLET_ADDRESS!, connection: { rpcUrl: 'https://sui-mainnet.blockvision.org' } } }); ``` ## 4. Create a Token Helper (Optional) You can create a token list helper for easy reference: ```javascript // Common tokens on Sui mainnet export const TOKENS = { SUI: "0x2::sui::SUI", USDC: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC" } as const; ``` ## 5. Execute a Swap With the SDK Create a swap execution file: ```javascript // swap.ts import { client } from './DexClient'; import { TOKENS } from './Tokens'; // Optional, if you created the token helper /** * Example: Execute a swap from SUI to USDC */ async function executeSwap() { try { if (!process.env.SUI_PRIVATE_KEY) { throw new Error('Missing SUI_PRIVATE_KEY in .env file'); } // First, get token information using a quote console.log("Getting token information..."); const fromTokenAddress = TOKENS.SUI; // Or use directly: "0x2::sui::SUI" const toTokenAddress = TOKENS.USDC; // Or use directly: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC" const quote = await client.dex.getQuote({ chainIndex: '784', // Sui chain ID fromTokenAddress, toTokenAddress, amount: '1000000', // Small amount for quote slippagePercent: '0.5' // 0.5% slippagePercent }); const tokenInfo = { fromToken: { symbol: quote.data[0].fromToken.tokenSymbol, decimals: parseInt(quote.data[0].fromToken.decimal), price: quote.data[0].fromToken.tokenUnitPrice }, toToken: { symbol: quote.data[0].toToken.tokenSymbol, decimals: parseInt(quote.data[0].toToken.decimal), price: quote.data[0].toToken.tokenUnitPrice } }; // Convert amount to base units const humanReadableAmount = 1.5; // 1.5 SUI const rawAmount = (humanReadableAmount * Math.pow(10, tokenInfo.fromToken.decimals)).toString(); console.log("\nSwap Details:"); console.log("--------------------"); console.log(`From: ${tokenInfo.fromToken.symbol}`); console.log(`To: ${tokenInfo.toToken.symbol}`); console.log(`Amount: ${humanReadableAmount} ${tokenInfo.fromToken.symbol}`); console.log(`Amount in base units: ${rawAmount}`); console.log(`Approximate USD value: $${(humanReadableAmount * parseFloat(tokenInfo.fromToken.price)).toFixed(2)}`); // Execute the swap console.log("\nExecuting swap..."); const swapResult = await client.dex.executeSwap({ chainIndex: '784', // Sui chain ID fromTokenAddress, toTokenAddress, amount: rawAmount, slippagePercent: '0.5', // 0.5% slippagePercent userWalletAddress: process.env.SUI_WALLET_ADDRESS! }); console.log('Swap executed successfully:'); console.log("\nTransaction ID:", swapResult.transactionId); console.log("Explorer URL:", swapResult.explorerUrl); if (swapResult.details) { console.log("\nDetails:"); console.log(`Input: ${swapResult.details.fromToken.amount} ${swapResult.details.fromToken.symbol}`); console.log(`Output: ${swapResult.details.toToken.amount} ${swapResult.details.toToken.symbol}`); if (swapResult.details.priceImpact) { console.log(`Price Impact: ${swapResult.details.priceImpact}%`); } } return swapResult; } catch (error) { if (error instanceof Error) { console.error('Error executing swap:', error.message); // API errors include details in the message if (error.message.includes('API Error:')) { const match = error.message.match(/API Error: (.*)/); if (match) console.error('API Error Details:', match[1]); } } throw error; } } // Run if this file is executed directly if (require.main === module) { executeSwap() .then(() => process.exit(0)) .catch((error) => { console.error('Error:', error); process.exit(1); }); } export { executeSwap }; ``` ## 6. Additional SDK functionality The SDK provides additional methods that simplify development: Get a quote for a token pair ```javascript const quote = await client.dex.getQuote({ chainIndex: '784', // Sui fromTokenAddress: '0x2::sui::SUI', // SUI toTokenAddress: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC', // USDC amount: '100000000', // In base units slippagePercent: '0.5' // 0.5% slippagePercent }); ``` - [Build Swap Applications on Ton](https://web3.okx.com/onchainos/dev-docs/trade/dex-use-swap-ton-quick-start.md) # Build Swap Applications on Ton In this guide, we’ll provide an example token swap through OKX DEX, using Ton from the Ton network to purchase JETTON. The process is as follows: 1. Set up your environment 2. Request the /quote endpoint and get the quote data 3. Request the /swap endpoint send the swap transaction ## 1. Set Up Your Environment ```javascript # --------------------- npm package --------------------- npm install @ton/ton @ton/crypto @ton/core buffer @orbs-network/ton-access ``` ```js const cryptoJS = require('crypto-js'); // Import encryption modules for subsequent encryption calculations const { TonClient, WalletContractV4, internal } = require("@ton/ton"); const { toNano, Cell } = require("@ton/core"); const { mnemonicToPrivateKey } = require("@ton/crypto"); const { getHttpEndpoint } = require("@orbs-network/ton-access"); // --------------------- environment variable --------------------- const apiBaseUrl = 'https://web3.okx.com/api/v6/dex/aggregator'; const chainIndex = '607'; // Native token contract address const fromTokenAddress = 'EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c'; // JETTON token contract address const toTokenAddress = 'EQAQXlWJvGbbFfE8F3oS8s87lIgdovS455IsWFaRdmJetTon'; // your wallet address const user = 'UQDoI2kiSNQZxxxxxxxxxxxx6lM2ZSxKkEw3k1' const fromAmount = '1000000' // user wallet private key const privateKey = 'xxxxx'; // open api Secret key const secretkey = 'xxxxx' // Get the current time const date = new Date(); // --------------------- util function --------------------- function getAggregatorRequestUrl(methodName, queryParams) { return apiBaseUrl + methodName + '?' + (new URLSearchParams(queryParams)).toString(); } // Check https://web3.okx.com/zh-hans/web3/build/docs/waas/rest-authentication for api-key const headersParams = { 'Content-Type': 'application/json', // The api Key obtained from the previous application 'OK-ACCESS-KEY': 'xxxxx', 'OK-ACCESS-SIGN': cryptoJS.enc.Base64.stringify( // The field order of headersParams should be consistent with the order of quoteParams. // example : quote ==> cryptoJS.HmacSHA256(date.toISOString() + 'GET' + '/api/v6/dex/aggregator/quote?amount=1000000&chainIndex=607&toTokenAddress=EQAQXlWJvGbbFfE8F3oS8s87lIgdovS455IsWFaRdmJetTon&fromTokenAddress=EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c', secretKey) cryptoJS.HmacSHA256(date.toISOString() + 'GET' + '/api/v6/dex/aggregator/xxx/xxx/xxx', secretKey) ), // Convert the current time to the desired format 'OK-ACCESS-TIMESTAMP': date.toISOString(), // The password created when applying for the key 'OK-ACCESS-PASSPHRASE': 'xxxxxxx', }; ``` **Additional receiving addresses aren’t supported.** ## 2. Request the /quote Endpoint and Get the Quote Data ### 2.1 Define Quote Parameters - Next, define the parameters to get basic information of the quote and the router list. ```js const quoteParams = { amount: fromAmount, chainIndex: chainIndex, toTokenAddress: toTokenAddress, fromTokenAddress: fromTokenAddress, }; ``` ### 2.2 Define helper functions - Define helper functions to interact with the DEX API. ```js const getQuote = async () => { const apiRequestUrl = getAggregatorRequestUrl('/quote', quoteParams); return fetch(apiRequestUrl, { method: 'get', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` ## 3. Request the /swap Endpoint and Send the Transaction ### 3.1 Define Swap Parameters - Next, define the parameters of the swap, and get the tx information. ```js const swapParams = { chainIndex: 1, fromTokenAddress: 'fromTokenAddress', toTokenAddress: 'toTokenAddress', amount: '1000000', slippagePercent: '0.5', // 0.5% slippagePercent userWalletAddress: user }; ``` ### 3.2 Define Helper Functions Define helper functions to interact with the DEX API ```js const getSwapData = async () => { const apiRequestUrl = getAggregatorRequestUrl('/swap', swapParams); return fetch(apiRequestUrl, { method: 'get', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` ### 3.3 Request Swap Data and Send the Transaction ```js let tx = { "data": "te6cckEBBAEAwAABsA+KfqUAALgW1FkYQkBfXhAIAK3+NxydEq8Qc4csyQ7botOnBqxp3L54Fn7Zof9EjDx5ADoI2kiSNQZdnOIVsRSLrVMtiBySHg0Lt6lM2ZSxKkEwyC592wEBAZ8RMwAAAvrwgIALyzu3/eo7h8wFCa+0XsOg6z0IG/43fUuMnumWS8xS91AD0F/w35CTWUxTWRjefoV+400KRA2jX51X4ezIgmUUY/0AX5sDCAIBAQwDABgAAAABAAAAAAAAA+cKUcDO", "from": "UQDoI2kiSNQZdnOIVsRSLrVMtiBySHg0Lt6lM2ZSxKkEw3k1", "gas": "80234000", "gasPrice": "5000", "maxPriorityFeePerGas": "", "minReceiveAmount": "25062412", "to": "UQBXp1W7_UJWvsBrbaO8s-9i8O53s7hNNeZ0XqEEz12i0oDS", "value": "440000000" } // This is the response of the /swap endpoint async function sendTx() { const endpoint = await getHttpEndpoint(); const client = new TonClient({ endpoint }); const mnemonic = ['range', 'xxxxxx']; // Your mnemonic words Decimal conversion const keyPair = await mnemonicToPrivateKey(mnemonic); const wallet = WalletContractV4.create({workchain: 0, publicKey: keyPair.publicKey}); const contract = client.open(wallet) let seqno = await contract.getSeqno(); const body = Cell.fromBase64(tx.data); const value = tx.value / Math.pow(10, 9); // Decimal conversion const to = tx.to; await contract.sendTransfer({ seqno, secretKey: keyPair.secretKey, messages: [internal({ value: toNano(value), to, body: body, })] }); } ``` - [DEX SDK ](https://web3.okx.com/onchainos/dev-docs/trade/dex-sdk-introduction.md) # DEX SDK The OKX DEX SDK is a typescript toolkit for developers to integrate OKX DEX API functionalities into their applications. GitHub Repository https://github.com/okx/okx-dex-sdk To get started, follow the guide here: https://github.com/okx/okx-dex-sdk?tab=readme-ov-file#usage ## Install the SDK ```bash npm install @okx-dex/okx-dex-sdk # or yarn add @okx-dex/okx-dex-sdk # or pnpm add @okx-dex/okx-dex-sdk ``` ## Setup Your Environment Create a .env file with your API credentials and wallet information. ```bash # OKX API Credentials OKX_API_KEY=your_api_key OKX_SECRET_KEY=your_secret_key OKX_API_PASSPHRASE=your_passphrase OKX_PROJECT_ID=your_project_id # Solana Configuration SOLANA_RPC_URL=your_solana_rpc_url SOLANA_WALLET_ADDRESS=your_solana_wallet_address SOLANA_PRIVATE_KEY=your_solana_private_key # EVM Configuration EVM_RPC_URL=your_evm_rpc_url EVM_PRIVATE_KEY=your_evm_private_key ``` ## Initialize the Client Create a file for your DEX client (e.g., DexClient.ts): ```typescript // example.ts or test.ts import { OKXDexClient } from '@okx-dex/okx-dex-sdk'; import { Connection } from '@solana/web3.js'; import { createWallet } from '@okx-dex/okx-dex-sdk/core/wallet'; import 'dotenv/config'; import { createEVMWallet } from '@okx-dex/okx-dex-sdk/core/evm-wallet'; import { ethers } from 'ethers'; // Validate environment variables const requiredEnvVars = [ 'OKX_API_KEY', 'OKX_SECRET_KEY', 'OKX_API_PASSPHRASE', 'OKX_PROJECT_ID', 'SOLANA_RPC_URL', 'SOLANA_PRIVATE_KEY', 'EVM_RPC_URL', 'EVM_PRIVATE_KEY' ]; for (const envVar of requiredEnvVars) { if (!process.env[envVar]) { throw new Error(`Missing required environment variable: ${envVar}`); } } // Create Solana connection and wallet const connection = new Connection(process.env.SOLANA_RPC_URL!); const wallet = createWallet(process.env.SOLANA_PRIVATE_KEY!, connection); // Create EVM provider and wallet const provider = new ethers.JsonRpcProvider(process.env.EVM_RPC_URL!); const evmWallet = createEVMWallet(process.env.EVM_PRIVATE_KEY!, provider); // Initialize the client with both Solana and EVM support export const client = new OKXDexClient({ apiKey: process.env.OKX_API_KEY!, secretKey: process.env.OKX_SECRET_KEY!, apiPassphrase: process.env.OKX_API_PASSPHRASE!, projectId: process.env.OKX_PROJECT_ID!, solana: { wallet: wallet }, evm: { wallet: evmWallet } }); ``` ## Using the Client Once initialized, you can use the client to make DEX API calls: ```typescript async function main() { try { // Get tokens for Solana (chainIndex: 501) const tokens = await client.dex.getTokens("501"); console.log('Supported tokens:', JSON.stringify(tokens, null, 2)); // Get tokens for Ethereum (chainIndex: 1) const ethTokens = await client.dex.getTokens("1"); console.log('Ethereum tokens:', JSON.stringify(ethTokens, null, 2)); } catch (error) { console.error('Error:', error); } } main(); ``` - [EVM Example](https://web3.okx.com/onchainos/dev-docs/trade/dex-sdk-evm.md) # EVM Example ## Create an Approval ```javaScript // approval.ts import { client } from './DexClient'; // Helper function to convert human-readable amounts to base units export function toBaseUnits(amount: string, decimals: number): string { // Remove any decimal point and count the decimal places const [integerPart, decimalPart = ''] = amount.split('.'); const currentDecimals = decimalPart.length; // Combine integer and decimal parts, removing the decimal point let result = integerPart + decimalPart; // Add zeros if we need more decimal places if (currentDecimals < decimals) { result = result + '0'.repeat(decimals - currentDecimals); } // Remove digits if we have too many decimal places else if (currentDecimals > decimals) { result = result.slice(0, result.length - (currentDecimals - decimals)); } // Remove leading zeros result = result.replace(/^0+/, '') || '0'; return result; } /** * Example: Approve a token for swapping */ async function executeApproval(tokenAddress: string, amount: string) { try { // Get token information using quote console.log("Getting token information..."); const tokenInfo = await client.dex.getQuote({ chainIndex: '8453', // Base Chain fromTokenAddress: tokenAddress, toTokenAddress: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // Native token amount: '1000000', // Use a reasonable amount for quote slippagePercent: '0.5'// 0.5% slippagePercent }); const tokenDecimals = parseInt(tokenInfo.data[0].fromToken.decimal); const rawAmount = toBaseUnits(amount, tokenDecimals); console.log(`\nApproval Details:`); console.log(`--------------------`); console.log(`Token: ${tokenInfo.data[0].fromToken.tokenSymbol}`); console.log(`Amount: ${amount} ${tokenInfo.data[0].fromToken.tokenSymbol}`); console.log(`Amount in base units: ${rawAmount}`); // Execute the approval console.log("\nExecuting approval..."); const result = await client.dex.executeApproval({ chainIndex: '8453', // Base Chain tokenContractAddress: tokenAddress, approveAmount: rawAmount }); if ('alreadyApproved' in result) { console.log("\nToken already approved for the requested amount!"); return { success: true, alreadyApproved: true }; } else { console.log("\nApproval completed successfully!"); console.log("Transaction Hash:", result.transactionHash); console.log("Explorer URL:", result.explorerUrl); return result; } } catch (error) { if (error instanceof Error) { console.error('Error executing approval:', error.message); } throw error; } } // Run if this file is executed directly if (require.main === module) { // Example usage: ts-node approval.ts 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 1000 const args = process.argv.slice(2); if (args.length !== 2) { console.log("Usage: ts-node approval.ts "); console.log("\nExamples:"); console.log(" # Approve 1000 USDC"); console.log(` ts-node approval.ts 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 1000`); process.exit(1); } const [tokenAddress, amount] = args; executeApproval(tokenAddress, amount) .then(() => process.exit(0)) .catch((error) => { console.error('Error:', error); process.exit(1); }); } export { executeApproval }; ``` ## Create a Swap ```javaScript // swap.ts import { client } from './DexClient'; /** * Example: Execute a swap from ETH to USDC on Base chain */ async function executeSwap() { try { if (!process.env.EVM_PRIVATE_KEY) { throw new Error('Missing EVM_PRIVATE_KEY in .env file'); } // You can change this to any EVM chain // For example, for Base, use chainIndex: '8453' // For example, for baseSepolia, use chainIndex: '84532' // You can also use SUI, use chainIndex: '784' // When using another Chain, you need to change the fromTokenAddress and toTokenAddress to the correct addresses for that chain const swapResult = await client.dex.executeSwap({ chainIndex: '8453', // Base chain ID fromTokenAddress: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // Native ETH toTokenAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC on Base amount: String(10 * 10 ** 14), // .0001 ETH slippagePercent: '0.5', // 0.5% slippagePercent userWalletAddress: process.env.EVM_WALLET_ADDRESS! }); console.log('Swap executed successfully:'); console.log(JSON.stringify(swapResult, null, 2)); return swapResult; } catch (error) { if (error instanceof Error) { console.error('Error executing swap:', error.message); // API errors include details in the message if (error.message.includes('API Error:')) { const match = error.message.match(/API Error: (.*)/); if (match) console.error('API Error Details:', match[1]); } } throw error; } } // Run if this file is executed directly if (require.main === module) { executeSwap() .then(() => process.exit(0)) .catch((error) => { console.error('Error:', error); process.exit(1); }); } export { executeSwap }; ``` ## Get a Quote ```javaScript const quote = await client.dex.getQuote({ chainIndex: '8453', // Base Chain fromTokenAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC toTokenAddress: '0x4200000000000000000000000000000000000006', // WETH amount: '1000000', // 1 USDC (in smallest units) slippagePercent: '0.5' // 0.5% slippagePercent }); ``` - [Solana Example](https://web3.okx.com/onchainos/dev-docs/trade/dex-sdk-solana.md) # Solana Example ## Create a Swap ```javaScript // swap.ts import { client } from './DexClient'; /** * Example: Execute a swap from SOL to USDC */ async function executeSwap() { try { if (!process.env.SOLANA_PRIVATE_KEY) { throw new Error('Missing SOLANA_PRIVATE_KEY in .env file'); } // Get quote to fetch token information console.log("Getting token information..."); const quote = await client.dex.getQuote({ chainIndex: '501', fromTokenAddress: '11111111111111111111111111111111', // SOL toTokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC amount: '1000000', // Small amount for quote slippagePercent: '0.5' // 0.5% slippagePercent }); const tokenInfo = { fromToken: { symbol: quote.data[0].fromToken.tokenSymbol, decimals: parseInt(quote.data[0].fromToken.decimal), price: quote.data[0].fromToken.tokenUnitPrice }, toToken: { symbol: quote.data[0].toToken.tokenSymbol, decimals: parseInt(quote.data[0].toToken.decimal), price: quote.data[0].toToken.tokenUnitPrice } }; // Convert amount to base units (for display purposes) const humanReadableAmount = 0.1; // 0.1 SOL const rawAmount = (humanReadableAmount * Math.pow(10, tokenInfo.fromToken.decimals)).toString(); console.log("\nSwap Details:"); console.log("--------------------"); console.log(`From: ${tokenInfo.fromToken.symbol}`); console.log(`To: ${tokenInfo.toToken.symbol}`); console.log(`Amount: ${humanReadableAmount} ${tokenInfo.fromToken.symbol}`); console.log(`Amount in base units: ${rawAmount}`); console.log(`Approximate USD value: $${(humanReadableAmount * parseFloat(tokenInfo.fromToken.price)).toFixed(2)}`); // Execute the swap console.log("\nExecuting swap..."); const swapResult = await client.dex.executeSwap({ chainIndex: '501', // Solana chain ID fromTokenAddress: '11111111111111111111111111111111', // SOL toTokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC amount: rawAmount, slippagePercent: '0.5', // 0.5% slippagePercent userWalletAddress: process.env.SOLANA_WALLET_ADDRESS! }); console.log('Swap executed successfully:'); console.log(JSON.stringify(swapResult, null, 2)); return swapResult; } catch (error) { if (error instanceof Error) { console.error('Error executing swap:', error.message); // API errors include details in the message if (error.message.includes('API Error:')) { const match = error.message.match(/API Error: (.*)/); if (match) console.error('API Error Details:', match[1]); } } throw error; } } // Run if this file is executed directly if (require.main === module) { executeSwap() .then(() => process.exit(0)) .catch((error) => { console.error('Error:', error); process.exit(1); }); } export { executeSwap }; ``` ## Get a Quote ```javaScript const quote = await client.dex.getQuote({ chainIndex: '501', // Solana fromTokenAddress: '11111111111111111111111111111111', // SOL toTokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC amount: '100000000', // 0.1 SOL (in lamports) slippagePercent: '0.5' // 0.5% slippagePercent }); ``` ## Swap-Instructions Execution Import the necessary libraries: ```javaScript // Required Solana dependencies for DEX interaction import { Connection, // Handles RPC connections to Solana network Keypair, // Manages wallet keypairs for signing PublicKey, // Handles Solana public key conversion and validation TransactionInstruction, // Core transaction instruction type TransactionMessage, // Builds transaction messages (v0 format) VersionedTransaction, // Supports newer transaction format with lookup tables RpcResponseAndContext, // RPC response wrapper type SimulatedTransactionResponse, // Simulation result type AddressLookupTableAccount, // For transaction size optimization PublicKeyInitData // Public key input type } from "@solana/web3.js"; import base58 from "bs58"; // Required for private key decoding ``` Initialize your connection and wallet: ```javaScript // Note: Consider using a reliable RPC endpoint with high rate limits for production const connection = new Connection( process.env.SOLANA_RPC_URL || "https://api.mainnet-beta.solana.com" ); // Initialize wallet for signing // This wallet will be the fee payer and transaction signer const wallet = Keypair.fromSecretKey( Uint8Array.from(base58.decode(userPrivateKey)) ); ``` Set up the parameters for your swap: ```javaScript // Configure swap parameters const baseUrl = "https://web3.okx.com/api/v6/dex/aggregator/swap-instruction"; const params = { chainIndex: "501", // Solana mainnet chain ID feePercent: "1", // Platform fee percentage amount: "1000000", // Amount in smallest denomination (lamports for SOL) fromTokenAddress: "11111111111111111111111111111111", // SOL mint address toTokenAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC mint address slippagePercent: "0.5", // slippagePercent tolerance 0.5% userWalletAddress: userAddress, // Wallet performing the swap autoSlippage: "false", // Use fixed slippage instead of auto pathNum: "3" // Maximum routes to consider }; ``` ## Process the Swap Instructions: ```javaScript // Helper function to convert DEX API instructions to Solana format function createTransactionInstruction(instruction) { return new TransactionInstruction({ programId: new PublicKey(instruction.programId), // DEX program ID keys: instruction.accounts.map((key) => ({ pubkey: new PublicKey(key.pubkey), // Account address isSigner: key.isSigner, // True if account must sign tx isWritable: key.isWritable // True if instruction modifies account })), data: Buffer.from(instruction.data, 'base64') // Instruction parameters }); } // Fetch optimal swap route and instructions from DEX const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/aggregator/swap-instruction"; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); const response = await fetch( `https://web3.okx.com${requestPath}${queryString}`, { method: 'GET', headers } ); const { data } = await response.json(); const { instructionLists, addressLookupTableAccount } = data; // Process DEX instructions into Solana-compatible format const instructions = []; // Remove duplicate lookup table addresses returned by DEX const uniqueLookupTables = Array.from(new Set(addressLookupTableAccount)); console.log("Lookup tables to load:", uniqueLookupTables); // Convert each DEX instruction to Solana format if (instructionLists?.length) { instructions.push(...instructionLists.map(createTransactionInstruction)); } ``` ## Handle Address Lookup Tables ```javaScript // Process lookup tables for transaction optimization // Lookup tables are crucial for complex swaps that interact with many accounts // They significantly reduce transaction size and cost const addressLookupTableAccounts = []; if (uniqueLookupTables?.length > 0) { console.log("Loading address lookup tables..."); // Fetch all lookup tables in parallel for better performance const lookupTableAccounts = await Promise.all( uniqueLookupTables.map(async (address) => { const pubkey = new PublicKey(address); // Get lookup table account data from Solana const account = await connection .getAddressLookupTable(pubkey) .then((res) => res.value); if (!account) { throw new Error(`Could not fetch lookup table account ${address}`); } return account; }) ); addressLookupTableAccounts.push(...lookupTableAccounts); } ``` ## Create and Sign Transaction ```javaScript // Get recent blockhash for transaction timing and uniqueness const latestBlockhash = await connection.getLatestBlockhash('finalized'); // Create versioned transaction message (V0 format required for lookup table support) const messageV0 = new TransactionMessage({ payerKey: wallet.publicKey, // Fee payer address recentBlockhash: latestBlockhash.blockhash, // Transaction timing instructions // Swap instructions from DEX }).compileToV0Message(addressLookupTableAccounts); // Include lookup tables // Create new versioned transaction with optimizations const transaction = new VersionedTransaction(messageV0); // Simulate transaction to check for errors // This helps catch issues before paying fees const result = await connection.simulateTransaction(transaction); // Sign transaction with fee payer wallet transaction.sign([wallet]); ``` ## Execute Transaction ```javaScript // Send transaction to Solana // skipPreflight=false ensures additional validation // maxRetries helps handle network issues const txId = await connection.sendRawTransaction(transaction.serialize(), { skipPreflight: false, // Run preflight validation maxRetries: 5 // Retry on failure }); // Log transaction results console.log("Transaction ID:", txId); console.log("Explorer URL:", `https://solscan.io/tx/${txId}`); // Wait for confirmation await connection.confirmTransaction({ signature: txId, blockhash: latestBlockhash.blockhash, lastValidBlockHeight: latestBlockhash.lastValidBlockHeight }); console.log("Transaction confirmed!"); ``` - [Sui Example](https://web3.okx.com/onchainos/dev-docs/trade/dex-sdk-sui.md) # Sui Example ## Create a Token Helper (Optional) ```javaScript // Common tokens on Sui mainnet export const TOKENS = { SUI: "0x2::sui::SUI", USDC: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC" } as const; ``` ## Create a Swap ```javaScript // swap.ts import { client } from './DexClient'; import { TOKENS } from './Tokens'; // Optional, if you created the token helper /** Example: Execute a swap from SUI to USDC */ async function executeSwap() { try { if (!process.env.SUI_PRIVATE_KEY) { throw new Error('Missing SUI_PRIVATE_KEY in .env file'); } // First, get token information using a quote console.log("Getting token information..."); const fromTokenAddress = TOKENS.SUI; // Or use directly: "0x2::sui::SUI" const toTokenAddress = TOKENS.USDC; // Or use directly: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC" const quote = await client.dex.getQuote({ chainIndex: '784', // Sui chain ID fromTokenAddress, toTokenAddress, amount: '1000000', // Small amount for quote slippagePercent: '0.5' // 0.5% slippagePercent }); const tokenInfo = { fromToken: { symbol: quote.data[0].fromToken.tokenSymbol, decimals: parseInt(quote.data[0].fromToken.decimal), price: quote.data[0].fromToken.tokenUnitPrice }, toToken: { symbol: quote.data[0].toToken.tokenSymbol, decimals: parseInt(quote.data[0].toToken.decimal), price: quote.data[0].toToken.tokenUnitPrice } }; // Convert amount to base units const humanReadableAmount = 1.5; // 1.5 SUI const rawAmount = (humanReadableAmount * Math.pow(10, tokenInfo.fromToken.decimals)).toString(); console.log("\nSwap Details:"); console.log("--------------------"); console.log( From: ${tokenInfo.fromToken.symbol} ); console.log( To: ${tokenInfo.toToken.symbol} ); console.log( Amount: ${humanReadableAmount} ${tokenInfo.fromToken.symbol} ); console.log( Amount in base units: ${rawAmount} ); console.log( Approximate USD value: $${(humanReadableAmount * parseFloat(tokenInfo.fromToken.price)).toFixed(2)} ); // Execute the swap console.log("\nExecuting swap..."); const swapResult = await client.dex.executeSwap({ chainIndex: '784', // Sui chain ID fromTokenAddress, toTokenAddress, amount: rawAmount, slippagePercent: '0.5', // 0.5% slippagePercent userWalletAddress: process.env.SUI_WALLET_ADDRESS! }); console.log('Swap executed successfully:'); console.log("\nTransaction ID:", swapResult.transactionId); console.log("Explorer URL:", swapResult.explorerUrl); if (swapResult.details) { console.log("\nDetails:"); console.log( Input: ${swapResult.details.fromToken.amount} ${swapResult.details.fromToken.symbol} ); console.log( Output: ${swapResult.details.toToken.amount} ${swapResult.details.toToken.symbol} ); if (swapResult.details.priceImpact) { console.log( Price Impact: ${swapResult.details.priceImpact}% ); } } return swapResult; } catch (error) { if (error instanceof Error) { console.error('Error executing swap:', error.message); // API errors include details in the message if (error.message.includes('API Error:')) { const match = error.message.match(/API Error: (.*)/); if (match) console.error('API Error Details:', match[1]); } } throw error; } } // Run if this file is executed directly if (require.main === module) { executeSwap() .then(() => process.exit(0)) .catch((error) => { console.error('Error:', error); process.exit(1); }); } export { executeSwap }; ``` ## Get a quote ```javaScript const quote = await client.dex.getQuote({ chainIndex: '784', // Sui fromTokenAddress: '0x2::sui::SUI', // SUI toTokenAddress: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC', // USDC amount: '100000000', // In base units slippagePercent: '0.5' // 0.5% slippagePercent }); ``` - [Introduction](https://web3.okx.com/onchainos/dev-docs/trade/dex-swap-api-introduction.md) # Introduction OKX DEX is an aggregator of various decentralized exchanges (also known as DEXs, such as Uniswap, Curve, Balancer, etc.) on different blockchains, allowing multi-chain and cross-chain trading. Our goal is to provide users with the best possible prices through intelligent routing. |OKX DEX inquiry and transaction process| |:-| |![image](../images/Swap_API_EN.jpg)| - Comprehensively calculate price, slippage, and transaction costs - Select the best quote for users based on a comprehensive comparison of quotes from various DEXs and PMMs through the smart order splitting algorithm | OKX DEX Swap trading process | |:--------------------------------------------| | ![image](../images/single-swap-english.png) | 1. Get information of the supported networks through /supported/chain. 2. Get information of the supported tokens through /aggregator/all-tokens. 3. Build the request for /quote data based on information of the supported networks and tokens. 4. Following the quote request, obtain the user’s authorization to allow the OKX DEX router to perform asset operations on their wallet. 5. Build the request for /approve-transaction to get the user’s wallet authorization. 6. Build /swap information based on the returned quote router data and obtain the transaction data required for the swap. 7. Broadcast the returned swap transaction information to the blockchain. - [API Reference](https://web3.okx.com/onchainos/dev-docs/trade/dex-api-reference.md) # API Reference - [Get Supported Chains](https://web3.okx.com/onchainos/dev-docs/trade/dex-get-aggregator-supported-chains.md) {/* api-page */} # Get Supported Chains Retrieve information on chains supported for single-chain exchanges. The request returns supported target chains for cross-chain transactions. ### Request URL GET `https://web3.okx.com/api/v6/dex/aggregator/supported/chain` ## Request Parameters | Parameter | Type | Required | Description | |---------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | No | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). |
## Response Parameters | Parameter | Type | Description | |-----------------------|---------|----------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Unique identifier for the chain. | | chainName | String | Chain name (e.g., `Optimism`). | | dexTokenApproveAddress| String | DEX authorization contract address; if no authorization has been made, this field will be empty. |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/aggregator/supported/chain?chainIndex=1' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code":"0", "data":[ { "chainIndex":"1", "chainName":"Ethereum", "dexTokenApproveAddress": "0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f" }, ], "msg":"" } ```
- [Get Tokens](https://web3.okx.com/onchainos/dev-docs/trade/dex-get-tokens.md) {/* api-page */} # Get Tokens It fetches a list of tokens. This interface returns a list of tokens that belong to major platforms or are deemed significant enough by OKX. However, you can still quote and swap other tokens outside of this list on OKX DEX. ### Request URL GET `https://web3.okx.com/api/v6/dex/aggregator/all-tokens` ## Request Parameters | Parameter | Type | Required | Description | |-----------|--------|----------|--------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). |
## Response Parameters | Parameter | Type | Description | |----------------------|--------|--------------------------| | decimals | String | The precision of tokens (e.g., `18`) | | tokenContractAddress | String | Token contract address (e.g., `0x382bb369d343125bfb2117af9c149795c6c65c50`) | | tokenLogoUrl | String | Token logo (e.g., `https://static.okx.com/cdn/wallet/logo/USDT-991ffed9-e495-4d1b-80c2-a4c5f96ce22d.png`) | | tokenName | String | Token full name (e.g., `Tether`) | | tokenSymbol | String | Token symbol (e.g., `USDT`) |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/aggregator/all-tokens?chainIndex=1' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "decimals": "18", "tokenContractAddress": "0x382bb369d343125bfb2117af9c149795c6c65c50", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/USDT-991ffed9-e495-4d1b-80c2-a4c5f96ce22d.png", "tokenName": "Tether", "tokenSymbol": "USDT" }, { "decimals": "18", "tokenContractAddress": "0xc946daf81b08146b1c7a8da2a851ddf2b3eaaf85", "tokenLogoUrl": "https://static.okx.com/cdn/explorer/okexchain/exchain_usdc.png", "tokenName": "USD Coin", "tokenSymbol": "USDC" }, { "decimals": "18", "tokenContractAddress": "0xdf54b6c6195ea4d948d03bfd818d365cf175cfc2", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/okb.png", "tokenName": "OKB", "tokenSymbol": "OKB" }, { "decimals": "18", "tokenContractAddress": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/okt.png", "tokenName": "OKTC", "tokenSymbol": "OKT" }, { "decimals": "18", "tokenContractAddress": "0x218c3c3d49d0e7b37aff0d8bb079de36ae61a4c0", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/BNB-20220308.png", "tokenName": "Binance Coin", "tokenSymbol": "BNB" }, { "decimals": "18", "tokenContractAddress": "0x332730a4f6e03d9c55829435f10360e13cfa41ff", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/BUSD-20220308.png", "tokenName": "Binance USD", "tokenSymbol": "BUSD" }, { "decimals": "18", "tokenContractAddress": "0xdcac52e001f5bd413aa6ea83956438f29098166b", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/eth_usdk.png", "tokenName": "USDK", "tokenSymbol": "USDK" } ], "msg": "" } ``` [//]: # () [//]: # (//移动端页面布局(注释迁移时忽略)) [//]: # () [//]: # (//下一行填写 API名称) [//]: # (# 获取币种列表) [//]: # () [//]: # (获取欧易DEX聚合器协议支持兑换的币种列表) [//]: # () [//]: # () [//]: # () [//]: # () [//]: # (## 请求地址) [//]: # (「GET」https://web3.okx.com/api/v6/dex/aggregator/all-tokens) [//]: # () [//]: # (## 请求参数) [//]: # (// 下方填写请求参数表格(如果存在path 和 query 则分别分点描述)) [//]: # () [//]: # (| 参数名 | 类型 | 是否必须 | 描述 |) [//]: # (|---------|--------|------|---------------------------------|) [//]: # (| chainIndex | String | 是 | 链 ID (如`1`: Ethereum,更多可查看数据字典) |) [//]: # () [//]: # () [//]: # () [//]: # (## 请求示例) [//]: # () [//]: # () [//]: # (//下方填写shell 代码) [//]: # () [//]: # (```shell) [//]: # (curl --location --request GET 'https://web3.okx.com/api/v6/dex/aggregator/all-tokens?chainIndex=1') [//]: # (```) [//]: # () [//]: # () [//]: # (//下方填写java 代码) [//]: # () [//]: # () [//]: # () [//]: # (//此区域可写其他补充性内容) [//]: # () [//]: # () [//]: # (## 响应参数) [//]: # (// 下方填写响应参数表格) [//]: # () [//]: # () [//]: # (## 响应示例) [//]: # () [//]: # () [//]: # () [//]: # () [//]: # (```json) [//]: # ({) [//]: # ( "code": "0",) [//]: # ( "data": [) [//]: # ( {) [//]: # ( "decimals": 18,) [//]: # ( "tokenContractAddress": "0xdf54b6c6195ea4d948d03bfd818d365cf175cfc2",) [//]: # ( "tokenLogoUrl": "https://static.coinall.ltd/cdn/wallet/logo/okb.png",) [//]: # ( "tokenName": "OKB",) [//]: # ( "tokenSymbol": "OKB") [//]: # ( },) [//]: # ( {) [//]: # ( "decimals": 6,) [//]: # ( "tokenContractAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7",) [//]: # ( "tokenLogoUrl": "https://static.coinall.ltd/cdn/wallet/logo/usdt.png",) [//]: # ( "tokenName": "Tether",) [//]: # ( "tokenSymbol": "USDT") [//]: # ( },) [//]: # ( {) [//]: # ( "decimals": 6,) [//]: # ( "tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",) [//]: # ( "tokenLogoUrl": "https://static.oklink.com/cdn/explorer/okexchain/exchain_usdc.png",) [//]: # ( "tokenName": "USD Coin",) [//]: # ( "tokenSymbol": "USDC") [//]: # ( },) [//]: # ( {) [//]: # ( "decimals": 18,) [//]: # ( "tokenContractAddress": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",) [//]: # ( "tokenLogoUrl": "https://static.coinall.ltd/cdn/wallet/logo/eth01.png",) [//]: # ( "tokenName": "Ethereum",) [//]: # ( "tokenSymbol": "ETH") [//]: # ( }) [//]: # ( ],) [//]: # ( "msg": "") [//]: # (}) [//]: # (```) [//]: # () [//]: # () [//]: # () [//]: # (//此区域可写其他补充性内容) [//]: # () [//]: # () [//]: # () [//]: # ()
- [Get Liquidity Sources](https://web3.okx.com/onchainos/dev-docs/trade/dex-get-liquidity.md) {/* api-page */} # Get Liquidity Sources Get a list of liquidity that are available for swap in the OKX aggregation protocol. ### Request URL GET `https://web3.okx.com/api/v6/dex/aggregator/get-liquidity` ## Request Parameters | Parameter | Type | Required | Description | |-----------|--------|----------|--------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). |
## Response Parameters | Parameter | Type | Description | |----------------------|--------|--------------------------| | id | String | The id of the liquidity pool (e.g., `34`) | | name | String | The name of the liquidity pool (e.g., `Uniswap V2`) | | logo | String | Liquidity Logo URL (e.g., `https://static.okx.com/cdn/wallet/logo/UNI.png`) |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/aggregator/get-liquidity?chainIndex=1' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "id": "34", "logo": "https://static.okx.com/cdn/wallet/logo/UNI.png", "name": "Uniswap V2" }, { "id": "29", "logo": "https://static.okx.com/cdn/wallet/logo/SUSHI.png", "name": "SushiSwap" }, { "id": "47", "logo": "https://static.okx.com/cdn/explorer/dex/logo/Dex_DefiSwap.png", "name": "DeFi Swap" }, { "id": "49", "logo": "https://static.okx.com/cdn/wallet/logo/convxswap.png", "name": "Convergence" }, { "id": "48", "logo": "https://static.okx.com/cdn/wallet/logo/luaswap.png", "name": "LuaSwap" }, { "id": "40", "logo": "https://static.okx.com/cdn/wallet/logo/SHIB.png", "name": "ShibaSwap" }, { "id": "30", "logo": "https://static.okx.com/cdn/wallet/logo/pancake.png", "name": "PancakeSwap" }, { "id": "53", "logo": "https://static.okx.com/cdn/wallet/logo/UNI.png", "name": "Uniswap V3" }, { "id": "54", "logo": "https://static.okx.com/cdn/wallet/logo/balancer.png", "name": "Balancer V1" }, { "id": "51", "logo": "https://static.okx.com/cdn/wallet/logo/balancer.png", "name": "Balancer V2" }, { "id": "55", "logo": "https://static.okx.com/cdn/wallet/logo/Curve.png", "name": "Curve V1" }, { "id": "58", "logo": "https://static.okx.com/cdn/wallet/logo/Curve.png", "name": "Curve V2" }, { "id": "52", "logo": "https://static.okx.com/cdn/wallet/logo/bancor.png", "name": "Bancor" }, { "id": "59", "logo": "https://static.okx.com/cdn/wallet/logo/Kyber.png", "name": "Kyber" }, { "id": "81", "logo": "https://static.okx.com/cdn/wallet/logo/Synapse.png", "name": "Synapse" }, { "id": "83", "logo": "https://static.okx.com/cdn/wallet/logo/Wombat.png", "name": "Wombat" }, { "id": "80", "logo": "https://static.okx.com/cdn/wallet/logo/DODO.png", "name": "DODO" }, { "id": "82", "logo": "https://static.okx.com/cdn/wallet/logo/Shell.png", "name": "Shell" }, { "id": "88", "logo": "https://static.okx.com/cdn/wallet/logo/DODO.png", "name": "DODO V2" }, { "id": "91", "logo": "https://static.okx.com/cdn/wallet/logo/Smoothy.png", "name": "Smoothy" }, { "id": "92", "logo": "https://static.okx.com/cdn/wallet/logo/RadioShack.png", "name": "RadioShack" }, { "id": "90", "logo": "https://static.okx.com/cdn/wallet/logo/ORION.png", "name": "Orion" }, { "id": "89", "logo": "https://static.okx.com/cdn/wallet/logo/FraxFinance.png", "name": "FraxSwap" }, { "id": "99", "logo": "https://static.okx.com/cdn/wallet/logo/okb.png", "name": "OKX DEX" }, { "id": "101", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Swapr.png", "name": "Swapr" }, { "id": "351", "logo": "https://static.okx.com/cdn/wallet/logo/dex_DFX.png", "name": "DFX Finance V3" }, { "id": "104", "logo": "https://static.okx.com/cdn/wallet/logo/dex_bancor.png", "name": "Bancor V3" }, { "id": "105", "logo": "https://static.okx.com/cdn/wallet/logo/dex_PSM.png", "name": "PSM" }, { "id": "108", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Verse.png", "name": "Verse" }, { "id": "248", "logo": "https://static.okx.com/cdn/wallet/logo/okb.png", "name": "OKX Limit Order" }, { "id": "132", "logo": "https://static.okx.com/cdn/wallet/logo/dex_defiplaza.png", "name": "DefiPlaza" }, { "id": "114", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Swerve.png", "name": "Swerve" }, { "id": "113", "logo": "https://static.okx.com/cdn/wallet/logo/Kyber.png", "name": "Kyber Elastic" }, { "id": "131", "logo": "https://static.okx.com/cdn/wallet/logo/dex_defiplaza.png", "name": "StablePlaza" }, { "id": "134", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Lido.png", "name": "Lido" }, { "id": "135", "logo": "https://static.okx.com/cdn/wallet/logo/dex_NOMISWAP.png", "name": "Nomiswap Stable" }, { "id": "136", "logo": "https://static.okx.com/cdn/explorer/dex/logo/solidly.png", "name": "Solidly" }, { "id": "215", "logo": "https://static.okx.com/cdn/wallet/logo/traderjoexyz.png", "name": "Trader Joe V2.1" }, { "id": "153", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Cafe_Swap.png", "name": "Cafe Swap" }, { "id": "141", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_ELK.png", "name": "ELK" }, { "id": "102", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Unifi.png", "name": "Unifi" }, { "id": "159", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_LINKSWAP.png", "name": "LINKSWAP" }, { "id": "160", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Sake_Swap.png", "name": "Sake Swap" }, { "id": "27", "logo": "https://static.okx.com/cdn/wallet/logo/Curve.png", "name": "Curve 3CRV" }, { "id": "202", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Aave.png", "name": "Aave V2" }, { "id": "230", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Aave.png", "name": "Aave V3" }, { "id": "199", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Compound.png", "name": "Compound" }, { "id": "266", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Compound.png", "name": "Compound V3" }, { "id": "184", "logo": "https://static.okx.com/cdn/wallet/logo/dex_logo_Frax.png", "name": "sfrxETH" }, { "id": "356", "logo": "https://static.okx.com/cdn/wallet/logo/dex_logo_Frax.png", "name": "sFRAX" }, { "id": "186", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Lido.png", "name": "stMatic" }, { "id": "200", "logo": "https://static.okx.com/cdn/wallet/logo/pancake.png", "name": "PancakeSwap V3" }, { "id": "203", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Rocketpool.png", "name": "RocketPool" }, { "id": "204", "logo": "https://static.okx.com/cdn/wallet/logo/dex_1inch_limit_order.png", "name": "1inch LP v1.1" }, { "id": "210", "logo": "https://static.okx.com/cdn/wallet/logo/Curve.png", "name": "Curve TNG" }, { "id": "330", "logo": "https://static.okx.com/cdn/wallet/logo/Curve.png", "name": "CurveNG" }, { "id": "214", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Mooniswap.png", "name": "Mooniswap" }, { "id": "213", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Integral.png", "name": "Integral" }, { "id": "218", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Maverick.png", "name": "Maverick V1" }, { "id": "226", "logo": "https://static.okx.com/cdn/wallet/logo/Curve.png", "name": "Curve LLAMMA" }, { "id": "234", "logo": "https://static.okx.com/cdn/explorer/dex/logo/Dex_xSigma.png", "name": "xSigma" }, { "id": "239", "logo": "https://static.okx.com/cdn/explorer/dex/logo/Dex_Sushiswap_V3.png", "name": "Sushiswap V3" }, { "id": "257", "logo": "https://static.okx.com/cdn/explorer/dex/logo/Synthetix.png", "name": "Wrapped Synthetix" }, { "id": "262", "logo": "https://static.okx.com/cdn/explorer/dex/logo/solidly.png", "name": "Solidly V3" }, { "id": "265", "logo": "https://static.okx.com/cdn/explorer/dex/logo/SmarDex.png", "name": "SmarDex" }, { "id": "323", "logo": "https://static.okx.com/cdn/explorer/dex/logo/Synthetix.png", "name": "sETH Wrapper" }, { "id": "476", "logo": "https://static.okx.com/cdn/web3/dex/logo/Ekubo.png", "name": "Ekubo ETH" }, { "id": "328", "logo": "https://static.okx.com/cdn/web3/dex/logo/sDai.png", "name": "sDai" }, { "id": "333", "logo": "https://static.okx.com/cdn/web3/dex/logo/RingProtocol.png", "name": "Ring Protocol" }, { "id": "365", "logo": "https://static.okx.com/cdn/web3/dex/logo/Angle.png", "name": "Angle" }, { "id": "352", "logo": "https://static.okx.com/cdn/web3/dex/logo/Angle.png", "name": "Angle Stake" }, { "id": "354", "logo": "https://static.okx.com/cdn/web3/dex/logo/Origin.png", "name": "Origin Wrapper" }, { "id": "355", "logo": "https://static.okx.com/cdn/web3/dex/logo/Origin.png", "name": "Origin" }, { "id": "379", "logo": "https://static.okx.com/cdn/web3/dex/logo/Unicly.png", "name": "Unicly" }, { "id": "380", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Maverick.png", "name": "Maverick V2" }, { "id": "394", "logo": "https://static.okx.com/cdn/web3/dex/logo/novabits.png", "name": "Novabits V3" }, { "id": "399", "logo": "https://static.okx.com/cdn/wallet/logo/UNI.png", "name": "Uniswap V1" }, { "id": "401", "logo": "https://static.okx.com/cdn/web3/dex/logo/Fluid.png", "name": "Fluid" }, { "id": "404", "logo": "https://static.okx.com/cdn/wallet/logo/dex_PSM.png", "name": "LitePSM" }, { "id": "409", "logo": "https://static.okx.com/cdn/wallet/logo/balancer.png", "name": "Balancer CoW AMM" }, { "id": "406", "logo": "https://static.okx.com/cdn/web3/dex/logo/native.png", "name": "Native" }, { "id": "427", "logo": "https://static.okx.com/cdn/web3/dex/logo/Saving_USDS.png", "name": "Saving USDS" }, { "id": "431", "logo": "https://static.okx.com/cdn/wallet/logo/Curve.png", "name": "Saving CRV Stake Factory" }, { "id": "428", "logo": "https://static.okx.com/cdn/web3/dex/logo/Saving_GYD.png", "name": "Saving GYD" }, { "id": "433", "logo": "https://static.okx.com/cdn/web3/dex/logo/EtherFi.png", "name": "EtherFi weETH" }, { "id": "437", "logo": "https://static.okx.com/cdn/web3/dex/logo/EtherFi.png", "name": "EtherFi eETH" }, { "id": "436", "logo": "https://static.okx.com/cdn/web3/dex/logo/EtherFi.png", "name": "EtherFi eBTC" }, { "id": "438", "logo": "https://static.okx.com/cdn/wallet/logo/UNI.png", "name": "Uniswap V4" }, { "id": "450", "logo": "https://static.okx.com/cdn/web3/dex/logo/native.png", "name": "NativeV3" }, { "id": "466", "logo": "https://static.okx.com/cdn/web3/dex/logo/Gamma_Swap.png", "name": "Gamma Swap" }, { "id": "482", "logo": "https://static.okx.com/cdn/web3/dex/logo/Amber.png", "name": "Amber" }, { "id": "522", "logo": "https://static.okx.com/cdn/web3/dex/logo/Fluid_Lite.png", "name": "Fluid Lite" }, { "id": "523", "logo": "https://static.okx.com/cdn/web3/dex/logo/1010_Trading.png", "name": "1010 Trading" } ], "msg": "" } ```
- [Approve Transactions](https://web3.okx.com/onchainos/dev-docs/trade/dex-approve-transaction.md) {/* api-page */} # Approve Transactions According to the [ERC-20 standard ](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/), we need to make sure that the OKX router has permission to spend funds with the user's wallet before making a transaction. This API will generate the relevant data for calling the contract. ### Request URL GET `https://web3.okx.com/api/v6/dex/aggregator/approve-transaction` ## Request Parameters | Parameter | Type | Required | Description | |----------------------|--------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). | | tokenContractAddress | String | Yes | Token contract address (e.g., `0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`) | | approveAmount | String | Yes | The amount of token that needs to be permitted (set in minimal divisible units, e.g., `1.00` USDT set as `1000000`, `1.00` DAI set as `1000000000000000000`,you could get the minimal divisible units from [Token Basic Information](../market/market-token-basic-info).) |
## Response Parameters | Parameter | Type | Description | |--------------------|--------|----------------------------------------| | data | String | Call data | | dexContractAddress | String | The contract address of OKX DEX approver (e.g., `0x6f9ffea7370310cd0f890dfde5e0e061059dcfd9`) | | gasLimit | String | Gas limit (e.g., `50000`).
To get accurate data, please take a look at [/gas-limit](onchain-gateway-api-gas-limit) API | | gasPrice | String | Gas price in wei (e.g., `110000000`) |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/aggregator/approve-transaction?chainIndex=1&tokenContractAddress=0x6f9ffea7370310cd0f890dfde5e0e061059dcfd9&approveAmount=1000000' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "data": "0x095ea7b3000000000000000000000000c67879f4065d3b9fe1c09ee990b891aa8e3a4c2f00000000000000000000000000000000000000000000000000000000000f4240", "dexContractAddress": "0xc67879F4065d3B9fe1C09EE990B891Aa8E3a4c2f", "gasLimit": "50000", "gasPrice": "110000000" } ], "msg": "" } ```
- [Get Quotes](https://web3.okx.com/onchainos/dev-docs/trade/dex-get-quote.md) {/* api-page */} # Get Quotes Get the best quote for a swap through OKX DEX. ### Request URL GET `https://web3.okx.com/api/v6/dex/aggregator/quote` ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). | | amount | String | Yes | The input amount of a token to be sold (if swapMode=exactIn) or buy (if swapMode=exactOut), set in minimal divisible units, e.g., 1.00 USDT set as 1000000, 1.00 DAI set as 1000000000000000000, you could get the minimal divisible units from [Token Basic Information](../market/market-token-basic-info). | | swapMode | String | Yes | Possible values: [`exactIn`, `exactOut`].
Default: `exactIn`.
`exactOut` is for supporting use cases where you need an exact output amount.

Note:
1.ExactOut feature currently only support **Ethereum、Base、BSC 、Arbitrum chain**.
2.ExactOut feature currently support only **Uni v3 protocols**
3. In this case the slippage is on the input token. | | fromTokenAddress | String | Yes | The contract address of a token to be sold (e.g., `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`) | | toTokenAddress | String | Yes | The contract address of a token to be bought (e.g., `0xa892e1fef8b31acc44ce78e7db0a2dc610f92d00`) | | dexIds | String | No | DexId of the liquidity pool for limited quotes, multiple combinations separated by `,` (e.g.,`1,50,180`, see liquidity list for more) | | directRoute | Boolean| No | The default setting is false. When enabled, Direct Routes restrict our routing to a single liquidity pool only. Currently, this feature is only active for Solana swaps. | | singleRouteOnly | Boolean| No | Default is false. When enabled, routing is restricted to a single route.Multi-hop and multi-pool routes are allowed, but no parallel split routes will be constructed | | singlePoolPerHop | Boolean| No | Default is false. When enabled, each hop in the route is restricted to a single pool. | | priceImpactProtectionPercent | String | No | This is an optional feature. The default value is 90 (representing 90%). The priceImpactProtectionPercent parameter can be set between 0 and 100.
When it’s set to 100, the feature is disabled and every transaction will be allowed to pass.
If the estimated price impact is above the percentage indicated, an error will be returned. For example, if priceImpactProtectionPercent = 25 (25%), any quote with a price impact higher than 25% will return an error.
Note: If we’re unable to calculate the price impact, we’ll return null, and the price impact protection will be disabled. | | feePercent | String | No | The percentage of fromTokenAmount will be sent to the referrer's address, the rest will be set as the input amount to be sold.
min percentage> 0
max percentage: 10 for Solana, 3 for all other chains.
By configuring this parameter, you can obtain the final amount of totoken provided to the user after deducting the commission from fromtoken.
A maximum of nine decimal places is allowed.
If more decimals are entered, the system will automatically round up.|
## Response Parameters | Parameter | Type | Description | |-----------------|--------|-------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Unique identifier for the chain. | | swapMode | String | Swap mode of this quote. | | ***dexRouterList*** | ***Array*** | ***Quote path data set*** | | fromTokenAmount | String | The input amount of a token to be sold (e.g., `500000000000000000000000`) | | toTokenAmount | String | The resulting amount of a token to be bought (e.g., `168611907733361`) | | tradeFee | String | Estimated network fee (USD) of the quote route | | estimateGasFee | String | Estimated gas consumption is returned in the smallest units of each chain, such as wei. | | router | String | Main path for the token swap | | ***dexProtocol*** | ***Object*** | ***Liquidity protocols used on the main path*** (e.g., `Verse`) | | percent | String | The percentage of assets handled by the protocol (e.g., `100`)| | dexName | String | The name of the liquidity protocol | | fromTokenIndex | String | Token index of fromToken in the swap path. | | ***fromToken*** | ***Object*** | ***The information of a token to be sold*** | | tokenContractAddress | String | Token contract address (e.g., `0xa892e1fef8b31acc44ce78e7db0a2dc610f92d00`) | | tokenSymbol | String | Token symbol (e.g., `0xa892e1fef8b31acc44ce78e7db0a2dc610f92d00`) | | tokenUnitPrice | String | The token unit price returned by this interface is a general USD real time price based on data from on-chain sources. Note: This price is only a recommended price. For some special cases, the token unit price may be 'null' | | decimal | String | The decimal number defines the smallest unit into which a single currency token can be divided. For example, if the decimal number of a token is 8, it means that a single such token can be divided into 100,000,000 of its smallest units. ***Note: This parameter is for reference only. It may change due to reasons such as settings adjustments by the contract owner.*** | | isHoneyPot | Boolean | If the token is a honeypot token. `yes:true` `no:false ` | | taxRate | String | Token tax rate for selling: Applicable to tokens with configurable tax mechanisms (e.g., SafeMoon, SPL2022 tokens). Returns 0 for regular tokens without tax. The value ranges from 0 to 1, where 0.01 represents 1%. | | toTokenIndex | String | Token index of toToken in the swap path. | | ***toToken*** | ***Object*** | ***The information of a token to be bought*** | | tokenContractAddress | String | Token contract address (e.g., `0xa892e1fef8b31acc44ce78e7db0a2dc610f92d00`) | | tokenSymbol | String | Token symbol (e.g., `0xa892e1fef8b31acc44ce78e7db0a2dc610f92d00`) | | tokenUnitPrice | String | The token unit price returned by this interface is a general USD price based on data from on-chain, exchange, and other third-party sources. Note: This price is only a recommended price. For some special cases, the token unit price may be 'null' | | decimal | String | The decimal number defines the smallest unit into which a single currency token can be divided. For example, if the decimal number of a token is 8, it means that a single such token can be divided into 100,000,000 of its smallest units. ***Note: This parameter is for reference only. It may change due to reasons such as settings adjustments by the contract owner.*** | | isHoneyPot | Boolean | If the token is a honeypot token. `yes:true` `no:false ` | | taxRate | String | Token tax rate for buying: Applicable to tokens with configurable tax mechanisms (e.g., SafeMoon, SPL2022 tokens). Returns 0 for regular tokens without tax. The value ranges from 0 to 1, where 0.01 represents 1%. | | dexName | String | DEX name of the quote route | | dexLogo | String | DEX logo of the quote route | | tradeFee | String | Estimated network fee (USD) of the quote route | | amountOut | String | Received amount of the quote route | | priceImpactPercent | String | Percentage = (Received value – Paid value) / Paid value. The swap amount will affect the depth of the liquidity pool, causing a value difference. This percentage can be positive if the received value exceeds the paid value, e.g., 5 represents 5%. |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/aggregator/quote?amount=10000000000000000000&chainIndex=1&toTokenAddress=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48&fromTokenAddress=0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "chainIndex": "130", "contextSlot": 0, "dexRouterList": [ { "dexProtocol": { "dexName": "Uniswap V4", "percent": "30" }, "fromToken": { "decimal": "18", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x4200000000000000000000000000000000000006", "tokenSymbol": "WETH", "tokenUnitPrice": "4191.043356462183138854" }, "fromTokenIndex": "0", "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x078d782b760474a361dda0af3839290b0ef57ad6", "tokenSymbol": "USDC", "tokenUnitPrice": "0.999692348812448693" }, "toTokenIndex": "4" }, { "dexProtocol": { "dexName": "Uniswap V4", "percent": "5" }, "fromToken": { "decimal": "18", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x4200000000000000000000000000000000000006", "tokenSymbol": "WETH", "tokenUnitPrice": "4191.043356462183138854" }, "fromTokenIndex": "0", "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x9151434b16b9763660705744891fa906f660ecc5", "tokenSymbol": "USDT", "tokenUnitPrice": "1.000313193103130296" }, "toTokenIndex": "3" }, { "dexProtocol": { "dexName": "Uniswap V4", "percent": "5" }, "fromToken": { "decimal": "18", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x4200000000000000000000000000000000000006", "tokenSymbol": "WETH", "tokenUnitPrice": "4191.043356462183138854" }, "fromTokenIndex": "0", "toToken": { "decimal": "8", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x0555e30da8f98308edb960aa94c0db47230d2b9c", "tokenSymbol": "WBTC", "tokenUnitPrice": "112879.983830393508167243" }, "toTokenIndex": "2" }, { "dexProtocol": { "dexName": "Uniswap V4", "percent": "5" }, "fromToken": { "decimal": "18", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x4200000000000000000000000000000000000006", "tokenSymbol": "WETH", "tokenUnitPrice": "4191.043356462183138854" }, "fromTokenIndex": "0", "toToken": { "decimal": "8", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x927b51f251480a681271180da4de28d44ec4afb8", "tokenSymbol": "WBTC", "tokenUnitPrice": "112634.107075070841530997" }, "toTokenIndex": "1" }, { "dexProtocol": { "dexName": "Uniswap V4", "percent": "55" }, "fromToken": { "decimal": "18", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x4200000000000000000000000000000000000006", "tokenSymbol": "WETH", "tokenUnitPrice": "4191.043356462183138854" }, "fromTokenIndex": "0", "toToken": { "decimal": "8", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x927b51f251480a681271180da4de28d44ec4afb8", "tokenSymbol": "WBTC", "tokenUnitPrice": "112634.107075070841530997" }, "toTokenIndex": "1" }, { "dexProtocol": { "dexName": "Uniswap V4", "percent": "3" }, "fromToken": { "decimal": "8", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x927b51f251480a681271180da4de28d44ec4afb8", "tokenSymbol": "WBTC", "tokenUnitPrice": "112634.107075070841530997" }, "fromTokenIndex": "1", "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x9151434b16b9763660705744891fa906f660ecc5", "tokenSymbol": "USDT", "tokenUnitPrice": "1.000313193103130296" }, "toTokenIndex": "3" }, { "dexProtocol": { "dexName": "Uniswap V4", "percent": "97" }, "fromToken": { "decimal": "8", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x927b51f251480a681271180da4de28d44ec4afb8", "tokenSymbol": "WBTC", "tokenUnitPrice": "112634.107075070841530997" }, "fromTokenIndex": "1", "toToken": { "decimal": "8", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x0555e30da8f98308edb960aa94c0db47230d2b9c", "tokenSymbol": "WBTC", "tokenUnitPrice": "112879.983830393508167243" }, "toTokenIndex": "2" }, { "dexProtocol": { "dexName": "Uniswap V4", "percent": "48" }, "fromToken": { "decimal": "8", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x0555e30da8f98308edb960aa94c0db47230d2b9c", "tokenSymbol": "WBTC", "tokenUnitPrice": "112879.983830393508167243" }, "fromTokenIndex": "2", "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x078d782b760474a361dda0af3839290b0ef57ad6", "tokenSymbol": "USDC", "tokenUnitPrice": "0.999692348812448693" }, "toTokenIndex": "4" }, { "dexProtocol": { "dexName": "Uniswap V4", "percent": "52" }, "fromToken": { "decimal": "8", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x0555e30da8f98308edb960aa94c0db47230d2b9c", "tokenSymbol": "WBTC", "tokenUnitPrice": "112879.983830393508167243" }, "fromTokenIndex": "2", "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x9151434b16b9763660705744891fa906f660ecc5", "tokenSymbol": "USDT", "tokenUnitPrice": "1.000313193103130296" }, "toTokenIndex": "3" }, { "dexProtocol": { "dexName": "Euler", "percent": "73" }, "fromToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x9151434b16b9763660705744891fa906f660ecc5", "tokenSymbol": "USDT", "tokenUnitPrice": "1.000313193103130296" }, "fromTokenIndex": "3", "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x078d782b760474a361dda0af3839290b0ef57ad6", "tokenSymbol": "USDC", "tokenUnitPrice": "0.999692348812448693" }, "toTokenIndex": "4" }, { "dexProtocol": { "dexName": "Euler", "percent": "26" }, "fromToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x9151434b16b9763660705744891fa906f660ecc5", "tokenSymbol": "USDT", "tokenUnitPrice": "1.000313193103130296" }, "fromTokenIndex": "3", "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x078d782b760474a361dda0af3839290b0ef57ad6", "tokenSymbol": "USDC", "tokenUnitPrice": "0.999692348812448693" }, "toTokenIndex": "4" }, { "dexProtocol": { "dexName": "Uniswap V4", "percent": "1" }, "fromToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x9151434b16b9763660705744891fa906f660ecc5", "tokenSymbol": "USDT", "tokenUnitPrice": "1.000313193103130296" }, "fromTokenIndex": "3", "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x078d782b760474a361dda0af3839290b0ef57ad6", "tokenSymbol": "USDC", "tokenUnitPrice": "0.999692348812448693" }, "toTokenIndex": "4" } ], "estimateGasFee": "1002000", "fromToken": { "decimal": "18", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "tokenSymbol": "UNICHAIN_ETH", "tokenUnitPrice": "4191.043356462183138854" }, "fromTokenAmount": "10000000000000000000000", "priceImpactPercent": "-67.53", "router": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee--0x927b51f251480a681271180da4de28d44ec4afb8--0x0555e30da8f98308edb960aa94c0db47230d2b9c--0x9151434b16b9763660705744891fa906f660ecc5--0x078d782b760474a361dda0af3839290b0ef57ad6", "swapMode": "exactIn", "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x078d782b760474a361dda0af3839290b0ef57ad6", "tokenSymbol": "USDC", "tokenUnitPrice": "0.999692348812448693" }, "toTokenAmount": "13614286937853", "tradeFee": "0.00001607688116316" } ], "msg": "" } ```
- [Get Solana Swap Instructions](https://web3.okx.com/onchainos/dev-docs/trade/dex-solana-swap-instruction.md) {/* api-page */} # Get Solana Swap Instructions Obtain transaction instruction data for redemption or custom assembly in Solana. ### Request URL GET `https://web3.okx.com/api/v6/dex/aggregator/swap-instruction` ## Request Parameters | Parameter | Type | Required | Description | |----------------------------------|---------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `501`: Solana.
See more [here](../home/supported-chain). | | amount | String | Yes | Token amount for the quote.
(The amount must include its precision. For example, exchanging 1.00 USDT requires inputting `1000000`, while exchanging 1.00 DAI requires `1000000000000000000`. Token precision can be obtained from the [Token Basic Information](../market/market-token-basic-info).) | | fromTokenAddress | String | Yes | Address of the token contract being swapped from (e.g., `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`). | | toTokenAddress | String | Yes | Address of the token contract being swapped to (e.g., `0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`). | | userWalletAddress | String | Yes | User’s wallet address (e.g., `0x3f6a3f57569358a512ccc0e513f171516b0fd42a`). | | slippagePercent | String | Yes | Slippage limit.

Note:
1. For EVM networks, the slippage setting has a minimum value of `0` and a maximum value of `100`.
2. For Solana, the slippage setting has a minimum value of `0` and a maximum value of less than `100`.
(For example: `0.5` means that the maximum slippage for this transaction is `0.5%`.) | | autoSlippage | Boolean | No | Default is false. When set to true, the original slippage (if set) will be covered by the autoSlippage and the API will calculate and return auto slippage recommendations based on current market data. | | maxAutoSlippagePercent | String | No | When autoSlippage is set to true, this value is the maximum auto slippage returned by the API(e.g., 0.5 represents 0.5%). We recommend that users adopt this value to ensure risk control. | | swapReceiverAddress | String | No | Recipient address for the purchased asset. If not set, the asset will be sent to the `userWalletAddress`. (e.g., `0x3f6a3f57569358a512ccc0e513f171516b0fd42a`). | | feePercent | String | No | The percentage of fromTokenAmount will be sent to the referrer's address, the rest will be set as the input amount to be sold.
min percentage> 0
max percentage: 10 for Solana, 3 for all other chains.
By configuring this parameter, you can obtain the final amount of totoken provided to the user after deducting the commission from fromtoken.
A maximum of nine decimal places is allowed.
If more decimals are entered, the system will automatically round up.| | fromTokenReferrerWalletAddress | String | No | Wallet address receiving the referral fee in `fromToken`.
Must be used with `feePercent`, and a single transaction can only apply either `fromToken` or `toToken` referral fees.

**Note:**
**Solana:** The referral address must hold some SOL for activation. | | toTokenReferrerWalletAddress | String | No | Wallet address receiving the referral fee in `toToken`.
Must be used with `feePercent`, and a single transaction can only apply either `fromToken` or `toToken` referral fees.

**Note:**
**Solana:** The referral address must hold some SOL for activation. | | positiveSlippagePercent | String | No | This feature is open to **whitelist or enterprise clients** only. If you want to access it , please contact dexapi@okx.com

Once configured, a fee can be charged on the quote improvement portion, capped at 10% of the total trade amount.

The cap can be adjusted by specifying a custom percentage parameter.The default setting is 0. `Min percentage`: 0 ,`Max percentage`: 10 , Maximum of 1 decimal point.
Currently, this parameter is only supported on the **Solana chain**. | | positiveSlippageFeeAddress | String | No | This feature is open to **whitelist or enterprise clients** only. If you want to use it , please contact dexapi@okx.com

The wallet address that receives positive slippage. You must set positiveSlippagePercent parameter together to specify the proportion. If provided, all positive slippage earnings will be sent to this address; if not provided, the wallet address used for collecting referral fees will be used instead. | | dexIds | String | No | Restrict the quote to specific liquidity pools by `dexId`. Multiple IDs should be comma-separated (e.g., `1,50,180`. See liquidity list for more details). | | excludeDexIds | String | No | The dexId of the liquidity pool will not be used, multiple combinations separated by `,` (e.g.,`1,50,180`, see liquidity list for more) | | disableRFQ | Boolean | No | Disable all liqudity source classified as RFQs that have dependencies on time-sensitive quotes. The default setting is false. | | directRoute | Boolean | No | The default setting is false. When enabled, Direct Routes restrict our routing to a single liquidity pool only. Currently, this feature is only active for Solana swaps. | | singleRouteOnly | Boolean| No | Default is false. When enabled, routing is restricted to a single route.Multi-hop and multi-pool routes are allowed, but no parallel split routes will be constructed | | singlePoolPerHop | Boolean| No | Default is false. When enabled, each hop in the route is restricted to a single pool. | | priceImpactProtectionPercent | String | No | This is an optional feature. The default value is 90 (representing 90%).
The priceImpactProtectionPercent can be set between 0 and 100. When it’s set to 100 (representing 100%), the feature is disabled and every transaction will be allowed to pass.
If the estimated price impact is above the percentage indicated, an error will be returned.
For example, if priceImpactProtectionPercent = 25 (25%), any quote with a price impact higher than 25% will return an error.
Note: If we’re unable to calculate the price impact, we’ll return null, and the price impact protection will be disabled. | | useTokenLedger | Boolean | No | The Token Ledger records your token balance before the swap executes. This is useful when you don't know the exact input amount upfront. For example, when the input comes from a previous instruction in the same transaction. | | computeUnitPrice | String | No | Used for transactions on the Solana network and similar to gasPrice on Ethereum. This price determines the priority level of the transaction. The higher the price, the more likely that the transaction can be processed faster. | | computeUnitLimit | String | No | Used for transactions on the Solana network and analogous to gasLimit on Ethereum, which ensures that the transaction won’t take too much computing resource. |
## Response Parameters | Parameter | Type | Description | |------------------------------------|-----------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | addressLookupTableAccount | Array | Address Lookup Table Account. A data structure in the Solana blockchain used to optimize the management and referencing of addresses in transactions. It allows developers to store a group of related addresses in a table and reference them in transactions via index values (instead of the full 32-byte address), significantly improving transaction efficiency and scalability. | | instructionLists | Array | Detailed transaction instruction information | | data | String | Instruction data | | accounts | Array | Instruction account information | | isSigner | Boolean | Whether the account is a signer | | isWritable | Boolean | Whether the account is writable | | pubkey | Boolean | Public key address of the account | | programId | String | Program ID for instruction execution | | ***routerResult*** | ***Object*** | ***Quote path data*** | | chainIndex | String | Unique identifier for the chain. | | swapMode | String | Swap mode of this quote. | | fromTokenAmount | String | The input amount of a token to be sold ( e.g.,`500000000000000000000000`) | | toTokenAmount | String | The resulting amount of a token to be bought ( e.g.,`168611907733361`) | | tradeFee | String | Estimated network fee (USD) of the quote route | | estimateGasFee | String | Estimated gas consumption is returned in the smallest units of each chain, such as wei. | | ***dexRouterList*** | ***Array*** | ***Quote path data set*** | | router | String | One of the main paths for the token swap | | ***dexProtocol*** | ***Object*** | ***Liquidity protocols used on the main path*** | | dexName | String | The name of the liquidity protocol (e.g.,`Verse`) | | fromTokenIndex | String | Token index of fromToken in the swap path. | | percent | String | The percentage of assets handled by the protocol (e.g.,`100`) | | ***fromToken*** | ***Object*** | ***The information of a token to be sold*** | | tokenContractAddress | String | Token contract address (e.g.,`0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`) | | tokenSymbol | String | Token symbol (e.g.,`USDC`) | | tokenUnitPrice | String | The token unit price returned by this interface is a general USDis a general USD real time price based on data from on-chain sources. Note: This price is only a recommended price. For some special cases, the token unit price may be 'null' | | decimal | String | The decimal number defines the smallest unit into which a single currency token can be divided. For example, if the decimal number of a token is 8, it means that a single such token can be divided into 100,000,000 of its smallest units. ***Note: This parameter is for reference only. It may change due to reasons such as settings adjustments by the contract owner.*** | | isHoneyPot | Boolean | If the token is a honeypot token. `yes:true` `no:false ` | | taxRate | String | Token tax rate for selling: Applicable to tokens with configurable tax mechanisms (e.g., SafeMoon, SPL2022 tokens). Returns 0 for regular tokens without tax. The value ranges from 0 to 1, where 0.01 represents 1%. | | toTokenIndex | String | Token index of toToken in the swap path. | | ***toToken*** | ***Object*** | ***The information of a token to be bought*** | | tokenContractAddress | String | Token contract address (e.g.,`0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`) | | tokenSymbol | String | Token symbol (e.g.,`USDC`) | | tokenUnitPrice | String | The token unit price returned by this interface is a general USD price based on data from on-chain, exchange, and other third-party sources. Note: This price is only a recommended price. For some special cases, the token unit price may be 'null' | | decimal | String | The decimal number defines the smallest unit into which a single currency token can be divided. For example, if the decimal number of a token is 8, it means that a single such token can be divided into 100,000,000 of its smallest units. ***Note: This parameter is for reference only. It may change due to reasons such as settings adjustments by the contract owner.*** | | isHoneyPot | Boolean | If the token is a honeypot token. `yes:true` `no:false ` | | taxRate | String | Token tax rate for buying: Applicable to tokens with configurable tax mechanisms (e.g., SafeMoon, SPL2022 tokens). Returns 0 for regular tokens without tax. The value ranges from 0 to 1, where 0.01 represents 1%. | | priceImpactPercent | String | Percentage = (Received value – Paid value) / Paid value. The swap amount will affect the depth of the liquidity pool, causing a value difference. This percentage can be positive if the received value exceeds the paid value. | | ***tx*** | ***Object*** | ***contract data model*** | | from | String | User's wallet address (e.g.,`0x3f6a3f57569358a512ccc0e513f171516b0fd42a`) | | to | String | The contract address of OKX DEX router (e.g.,`0x3b3ae790Df4F312e745D270119c6052904FB6790`) | | minReceiveAmount | String | The minimum amount of a token to buy when the price reaches the upper limit of slippage (e.g.,`900645839798`) | | slippagePercent | String | The value of current transaction slippage |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/aggregator/swap-instruction?chainIndex=501&userWalletAddress=J5CBzXpcYn6WR2JBah8zU4Yxct985CAFGwXRcFaX2pbS&autoSlippage=true&toTokenReferrerWalletAddress=A9bBCSy9y4vggKgcT7jkUiN77Q95soLbLYhCcbWUpy3g&amount=100000&fromTokenAddress=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v&toTokenAddress=11111111111111111111111111111111&feePercent=0.875&slippagePercent=0.05&useTokenLedger=true \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": { "addressLookupTableAccount": [ "Ga7MuV4c198RzhFvvpEHFVLUHaEDAM1VqW2rr2sJqfxe", "2WejwkssZt7cd2At71Cc4yiev5cAKc5iZt3cZdyL5tkQ" ], "createTokenAccountList": [ "FZcMUbUG4qaptFXmpX8xB2ivFKkxHywoEWpqskM6Md6D", "H1KZidz2CNt5VjNaoV2bpSDsspaPtrKCLoLKXZEZrEB9", "8XrtGP8RG33AnrN2yJ6H3gnXPNQ3dYXKqM72bpzhcsd6", "DT2krA8vSP96D68nH86eAztZHVM18YB5i4gDXjLBDXm7", "A9bBCSy9y4vggKgcT7jkUiN77Q95soLbLYhCcbWUpy3g", "D9GYt4W7VvteKCSvTgyjzuiBJyTy94Kmr6YiC9fbxGjW" ], "instructionLists": [ { "data": "AgY6BAA=", "accounts": [], "programId": "ComputeBudget111111111111111111111111111111" }, { "data": "Axm5AgAAAAAA", "accounts": [], "programId": "ComputeBudget111111111111111111111111111111" }, { "data": "AgAAAPAdHwAAAAAA", "accounts": [ { "isSigner": true, "isWritable": true, "pubkey": "J5CBzXpcYn6WR2JBah8zU4Yxct985CAFGwXRcFaX2pbS" }, { "isSigner": false, "isWritable": true, "pubkey": "H1KZidz2CNt5VjNaoV2bpSDsspaPtrKCLoLKXZEZrEB9" } ], "programId": "11111111111111111111111111111111" }, { "data": "k/F7ZPSErnb9", "accounts": [ { "isSigner": true, "isWritable": true, "pubkey": "J5CBzXpcYn6WR2JBah8zU4Yxct985CAFGwXRcFaX2pbS" }, { "isSigner": false, "isWritable": false, "pubkey": "J5CBzXpcYn6WR2JBah8zU4Yxct985CAFGwXRcFaX2pbS" }, { "isSigner": false, "isWritable": true, "pubkey": "H1KZidz2CNt5VjNaoV2bpSDsspaPtrKCLoLKXZEZrEB9" }, { "isSigner": false, "isWritable": false, "pubkey": "So11111111111111111111111111111111111111112" }, { "isSigner": false, "isWritable": false, "pubkey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" }, { "isSigner": false, "isWritable": false, "pubkey": "11111111111111111111111111111111" } ], "programId": "proVF4pMXVaYqmy4NjniPh4pqKNfMmsihgd4wdkCX3u" }, { "data": "5FW5cE5PTQI=", "accounts": [ { "isSigner": false, "isWritable": true, "pubkey": "H9sbECFAyQXYJpvy5a3REamkZbGx8MnvUQ9wUZEJgANb" }, { "isSigner": false, "isWritable": false, "pubkey": "FZcMUbUG4qaptFXmpX8xB2ivFKkxHywoEWpqskM6Md6D" } ], "programId": "proVF4pMXVaYqmy4NjniPh4pqKNfMmsihgd4wdkCX3u" }, { "data": "JFyT2xqwn1o3PQMAAAAAAJdQCQAAAAAAMgABAAAARRAnAbCDhUAAAGQ=", "accounts": [ { "isSigner": true, "isWritable": true, "pubkey": "J5CBzXpcYn6WR2JBah8zU4Yxct985CAFGwXRcFaX2pbS" }, { "isSigner": false, "isWritable": true, "pubkey": "FZcMUbUG4qaptFXmpX8xB2ivFKkxHywoEWpqskM6Md6D" }, { "isSigner": false, "isWritable": true, "pubkey": "H1KZidz2CNt5VjNaoV2bpSDsspaPtrKCLoLKXZEZrEB9" }, { "isSigner": false, "isWritable": false, "pubkey": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" }, { "isSigner": false, "isWritable": false, "pubkey": "So11111111111111111111111111111111111111112" }, { "isSigner": false, "isWritable": true, "pubkey": "A9bBCSy9y4vggKgcT7jkUiN77Q95soLbLYhCcbWUpy3g" }, { "isSigner": false, "isWritable": false, "pubkey": "proVF4pMXVaYqmy4NjniPh4pqKNfMmsihgd4wdkCX3u" }, { "isSigner": false, "isWritable": true, "pubkey": "ARu4n5mFdZogZAravu7CcizaojWnS6oqka37gdLT5SZn" }, { "isSigner": false, "isWritable": true, "pubkey": "8XrtGP8RG33AnrN2yJ6H3gnXPNQ3dYXKqM72bpzhcsd6" }, { "isSigner": false, "isWritable": true, "pubkey": "DT2krA8vSP96D68nH86eAztZHVM18YB5i4gDXjLBDXm7" }, { "isSigner": false, "isWritable": false, "pubkey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" }, { "isSigner": false, "isWritable": false, "pubkey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" }, { "isSigner": false, "isWritable": false, "pubkey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" }, { "isSigner": false, "isWritable": false, "pubkey": "11111111111111111111111111111111" }, { "isSigner": false, "isWritable": false, "pubkey": "H9sbECFAyQXYJpvy5a3REamkZbGx8MnvUQ9wUZEJgANb" }, { "isSigner": false, "isWritable": false, "pubkey": "Ag3hiK9svNixH9Vu5sD2CmK5fyDWrx9a1iVSbZW22bUS" }, { "isSigner": false, "isWritable": false, "pubkey": "proVF4pMXVaYqmy4NjniPh4pqKNfMmsihgd4wdkCX3u" }, { "isSigner": false, "isWritable": false, "pubkey": "goonERTdGsjnkZqWuVjs73BZ3Pb9qoCUdBUL17BnS5j" }, { "isSigner": false, "isWritable": true, "pubkey": "ARu4n5mFdZogZAravu7CcizaojWnS6oqka37gdLT5SZn" }, { "isSigner": false, "isWritable": true, "pubkey": "8XrtGP8RG33AnrN2yJ6H3gnXPNQ3dYXKqM72bpzhcsd6" }, { "isSigner": false, "isWritable": true, "pubkey": "DT2krA8vSP96D68nH86eAztZHVM18YB5i4gDXjLBDXm7" }, { "isSigner": false, "isWritable": true, "pubkey": "JAQxrJ2WuDF4APfSifurJJ4HzV5Z3FyBuBeSMj7mo9aw" }, { "isSigner": false, "isWritable": true, "pubkey": "4ynTYgJK5ruYx3AZMRjCHrJk1qkm61fePF7dkbvRQD46" }, { "isSigner": false, "isWritable": true, "pubkey": "AABxS823DPBxDkxEcdFSduUH1p3XmKjL5AuVgbH5qB3U" }, { "isSigner": false, "isWritable": true, "pubkey": "CyCg79QpzH8MbnPDMEJEvbw3ugJXWisWYPHEE363eUuJ" }, { "isSigner": false, "isWritable": false, "pubkey": "2pA6DAAPdrHZd1knT75Dy3Q3ZwyVWQ9gL4zZJSYqSuSR" }, { "isSigner": false, "isWritable": false, "pubkey": "Sysvar1nstructions1111111111111111111111111" }, { "isSigner": false, "isWritable": false, "pubkey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" }, { "isSigner": false, "isWritable": true, "pubkey": "D9GYt4W7VvteKCSvTgyjzuiBJyTy94Kmr6YiC9fbxGjW" } ], "programId": "proVF4pMXVaYqmy4NjniPh4pqKNfMmsihgd4wdkCX3u" } ], "routerResult": { "chainIndex": "501", "contextSlot": 395101989, "dexRouterList": [ { "dexProtocol": { "dexName": "GoonFi", "percent": "100" }, "fromToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "tokenSymbol": "USDC", "tokenUnitPrice": "0.99975" }, "fromTokenIndex": "0", "toToken": { "decimal": "9", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "So11111111111111111111111111111111111111112", "tokenSymbol": "wSOL", "tokenUnitPrice": "129.9" }, "toTokenIndex": "1" } ], "estimateGasFee": "276998", "fromToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "tokenSymbol": "USDC", "tokenUnitPrice": "0.99975" }, "fromTokenAmount": "100000", "priceImpactPercent": "0.02", "router": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v--11111111111111111111111111111111", "swapMode": "exactIn", "toToken": { "decimal": "9", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "11111111111111111111111111111111", "tokenSymbol": "SOL", "tokenUnitPrice": "129.9" }, "toTokenAmount": "610455", "tradeFee": "0.0006497" }, "tx": { "from": "J5CBzXpcYn6WR2JBah8zU4Yxct985CAFGwXRcFaX2pbS", "minReceiveAmount": "607402", "slippagePercent": "0.5", "to": "proVF4pMXVaYqmy4NjniPh4pqKNfMmsihgd4wdkCX3u" }, "wsolRentFee": 2039280 }, "msg": "" } ```
- [Swap](https://web3.okx.com/onchainos/dev-docs/trade/dex-swap.md) {/* api-page */} # Swap Generate the data to call the OKX DEX router to execute a swap. In Uni v3 pools, the following scenario may occur:
If the liquidity for the desired token pair in the pool is depleted, the pool will only consume part of the payment token, leaving a remainder.
As a fully decentralized smart contract, the OKX DEX Router will automatically refund the remainder.
During your integration, please ensure compatibility with this scenario by configuring your contract to support token refunds, thereby ensuring a smooth user experience.
### Request URL GET `https://web3.okx.com/api/v6/dex/aggregator/swap` ## Request Parameters | Parameter | Type | Required | Description | |-------------------|--------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | No | Unique identifier for the chain. | | amount | String | Yes | The input amount of a token to be sold
(set in minimal divisible units, e.g., 1.00 USDT set as 1000000, 1.00 DAI set as 1000000000000000000), you could get the minimal divisible units from [Token Basic Information](../market../market/market-token-basic-info). | | swapMode | String | Yes | Possible values: [`exactIn`, `exactOut`].
Default: `exactIn`.
`exactOut` is for supporting use cases where you need an exact output amount.

Note:
1.ExactOut feature currently only support **Ethereum、Base、BSC 、Arbitrum chain**.
2.ExactOut feature currently support only **Uni v3 protocols**
3.In this case the slippage is on the input token.| | fromTokenAddress | String | Yes | The contract address of a token you want to send (e.g.,`0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`) | | toTokenAddress | String | Yes | The contract address of a token you want to receive (e.g.,`0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`) | | slippagePercent | String | Yes | Slippage limit.

Note:
1. For EVM networks, the slippage setting has a minimum value of `0` and a maximum value of `100`.
2. For Solana, the slippage setting has a minimum value of `0` and a maximum value of less than `100`.
(For example: `0.5` means that the maximum slippage for this transaction is `0.5%`.) | | userWalletAddress | String | Yes | User's wallet address (e.g.,`0x3f6a3f57569358a512ccc0e513f171516b0fd42a`) | | approveTransaction | Boolean | No | Defaults to false. When enabled, the authorized address and the authorized calldata will be returned in `signatureData`. | | approveAmount | String | No | The amount of token that needs to be permitted (set in minimal divisible units, e.g., `1.00` USDT set as `1000000`, you could get the minimal divisible units from [Token Basic Information](../market/market-token-basic-info).) | | swapReceiverAddress | String | No | Recipient address of a purchased token if not set, `userWalletAddress` will receive a purchased token (e.g.,`0x3f6a3f57569358a512ccc0e513f171516b0fd42a`) | | feePercent | String | No | The percentage of fromTokenAmount will be sent to the referrer's address, the rest will be set as the input amount to be sold.
min percentage> 0
max percentage: 10 for Solana, 3 for all other chains.
By configuring this parameter, you can obtain the final amount of totoken provided to the user after deducting the commission from fromtoken.
A maximum of nine decimal places is allowed.
If more decimals are entered, the system will automatically round up.| | fromTokenReferrerWalletAddress | String | No | The wallet address that receives the commission fee for the fromToken.
When using the API, you must set the commission rate together with feePercent, and for each transaction, you can only choose either fromToken commission or toToken commission.

Note:
1. For **Solana**: The referrer wallet must have some SOL deposited in advance to activate the address.
2. For **TON**: Only commission through liquidity pools of Stonfi V2 and Dedust is supported; commission through Stonfi V1 liquidity pools is not supported.
3.For **BSC Chain**: Commission split for swaps via Four.meme is not supported| | toTokenReferrerWalletAddress | String | No | The wallet address that receives the commission fee for the toToken.
When using the API, you must set the commission rate together with feePercent, and for each transaction, you can only choose either fromToken commission or toToken commission.

Note:
1. For **Solana**: The referrer wallet must have some SOL deposited in advance to activate the address.
2. For **TON**: Only commission through liquidity pools of Stonfi V2 is supported.
3.For **BSC Chain**: Commission split for swaps via Four.meme is not supported | | positiveSlippagePercent | String | No | This feature is open to **whitelist or enterprise clients** only. If you want to access it , please contact dexapi@okx.com

Once configured, a fee can be charged on the quote improvement portion, capped at 10% of the total trade amount.

The cap can be adjusted by specifying a custom percentage parameter.The default setting is 0. `Min percentage`: 0 ,`Max percentage`: 10 , Maximum of 1 decimal point.
Currently, this parameter is only supported on the **Solana chain**. | | positiveSlippageFeeAddress | String | No | This feature is open to **whitelist or enterprise clients** only. If you want to use it , please contact dexapi@okx.com

The wallet address that receives positive slippage. You must set positiveSlippagePercent parameter together to specify the proportion. If provided, all positive slippage earnings will be sent to this address; if not provided, the wallet address used for collecting referral fees will be used instead. | | gasLimit | String | No | The gas(In smallest units : wei) for the swap transaction. If the value is too low to achieve the quote, an error will be returned.
Only applicable to EVM| | gasLevel | String | No | ( defaults to `average`) The target gas price level for the swap transaction,set to `average` or `fast` or `slow` | | computeUnitPrice | String | No | Used for transactions on the Solana network and similar to gasPrice on Ethereum. This price determines the priority level of the transaction. The higher the price, the more likely that the transaction can be processed faster. | | computeUnitLimit | String | No | Used for transactions on the Solana network and analogous to gasLimit on Ethereum, which ensures that the transaction won’t take too much computing resource.
If the parameter `tips` is not 0, then `computeUnitPrice` should be set to 0. Otherwise, the fee is wasted. | | tips | String | No | Jito tips in SOL. The maximum is "2" and the minimum is "0.0000000001".
This is used for MEV protection. Specify `tips` to obtain calldata and call the [broadcast transaction API](./onchain-gateway-api-broadcast-transaction)。 | dexIds | String | No | DexId of the liquidity pool for limited quotes, multiple combinations separated by `,` (e.g., `1,50,180`, see liquidity list for more) | | excludeDexIds | String | No | The dexId of the liquidity pool will not be used, multiple combinations separated by `,` (e.g.,`1,50,180`, see liquidity list for more) | | disableRFQ | Boolean| No | Disable all liqudity source classified as RFQs that have dependencies on time-sensitive quotes. The default setting is false. | | directRoute | Boolean | No | The default setting is false. When enabled, Direct Routes restrict our routing to a single liquidity pool only. Currently, this feature is only active for Solana swaps. | | singleRouteOnly | Boolean| No | Default is false. When enabled, routing is restricted to a single route.Multi-hop and multi-pool routes are allowed, but no parallel split routes will be constructed | | singlePoolPerHop | Boolean| No | Default is false. When enabled, each hop in the route is restricted to a single pool. | | priceImpactProtectionPercent | String | No | ( The default is 90%.) The percentage (between 0 - 100) of the price impact allowed.

When the priceImpactProtectionPercent is set, if the estimated price impact is above the percentage indicated, an error will be returned. For example, if priceImpactProtectionPercent = 25, any quote with a price impact higher than 25% will return an error.
When it’s set to 100, the feature will be disabled, which means that every transaction will be allowed to pass.
Note: If we’re unable to calculate the price impact, we’ll return null, and the price impact protection will be disabled. | | callDataMemo | String | No | You can customize the parameters to be sent on the blockchain in callData by encoding the data into a 128-character 64-bytes hexadecimal string. For example, the string “0x...111” needs to keep the “0x” at its start. | | autoSlippage | Boolean | No | Default is false. When set to true, the original slippage (if set) will be covered by the autoSlippage and the API will calculate and return auto slippage recommendations based on current market data. | | maxAutoSlippagePercent | String | No | When autoSlippage is set to true, this value is the maximum auto slippage returned by the API(e.g., 0.5 represents 0.5%). We recommend that users adopt this value to ensure risk control. |
## Response Parameters | Parameter | Type | Description | |------------------|--------|---------------------------------------------------------------------------------------------------------------------------------------| | ***routerResult*** | ***Object*** | ***Quote path data*** | | chainIndex | String | Unique identifier for the chain. | | swapMode | String | Swap mode of this quote. | | fromTokenAmount | String | The input amount of a token to be sold ( e.g.,`500000000000000000000000`) | | toTokenAmount | String | The resulting amount of a token to be bought ( e.g.,`168611907733361`) | | tradeFee | String | Estimated network fee (USD) of the quote route | | estimateGasFee | String | Estimated gas consumption is returned in the smallest units of each chain, such as wei. | | ***dexRouterList*** | ***Array*** | ***Quote path data set*** | | router | String | Main path for the token swap | | ***dexProtocol*** | ***Object*** | ***Liquidity protocols used on the main path*** | | dexName | String | The name of the liquidity protocol (e.g.,`Verse`) | | percent | String | The percentage of assets handled by the protocol (e.g.,`100`) | | ***fromTokeIndexn*** | ***String*** | ***Token Index represents the position of from token during routing.*** | | ***fromToken*** | ***Object*** | ***The information of a token to be sold*** | | tokenContractAddress | String | Token contract address (e.g.,`0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`) | | tokenSymbol | String | Token symbol (e.g.,`USDC`) | | tokenUnitPrice | String | The token unit price returned by this interface is a general USDis a general USD real time price based on data from on-chain sources. Note: This price is only a recommended price. For some special cases, the token unit price may be 'null' | | decimal | String | The decimal number defines the smallest unit into which a single currency token can be divided. For example, if the decimal number of a token is 8, it means that a single such token can be divided into 100,000,000 of its smallest units. ***Note: This parameter is for reference only. It may change due to reasons such as settings adjustments by the contract owner.*** | | isHoneyPot | Boolean | If the token is a honeypot token. `yes:true` `no:false ` | | taxRate | String | Token tax rate for selling: Applicable to tokens with configurable tax mechanisms (e.g., SafeMoon, SPL2022 tokens). Returns 0 for regular tokens without tax. The value ranges from 0 to 1, where 0.01 represents 1%. | | ***toTokenIndex*** | ***String*** | ***Token Index represents the position of to token during routing.*** | | ***toToken*** | ***Object*** | ***The information of a token to be bought*** | | tokenContractAddress | String | Token contract address (e.g.,`0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`) | | tokenSymbol | String | Token symbol (e.g.,`USDC`) | | tokenUnitPrice | String | The token unit price returned by this interface is a general USD price based on data from on-chain, exchange, and other third-party sources. Note: This price is only a recommended price. For some special cases, the token unit price may be 'null' | | decimal | String | The decimal number defines the smallest unit into which a single currency token can be divided. For example, if the decimal number of a token is 8, it means that a single such token can be divided into 100,000,000 of its smallest units. ***Note: This parameter is for reference only. It may change due to reasons such as settings adjustments by the contract owner.*** | | isHoneyPot | Boolean | If the token is a honeypot token. `yes:true` `no:false ` | | taxRate | String | Token tax rate for buying: Applicable to tokens with configurable tax mechanisms (e.g., SafeMoon, SPL2022 tokens). Returns 0 for regular tokens without tax. The value ranges from 0 to 1, where 0.01 represents 1%. | | priceImpactPercent | String | Percentage = (Received value – Paid value) / Paid value. The swap amount will affect the depth of the liquidity pool, causing a value difference. This percentage can be positive if the received value exceeds the paid value. | | ***tx*** | ***Object*** | ***contract data model*** | | signatureData | ***Array*** | If this parameter is returned, it indicates that the transaction requires additional signing data. Developers should use this parameter as one of the inputs for the transaction signature and ensure it is correctly applied during the signing process.
When you specify the `tips` request parameter, this parameter value represents the calldata of the jito tips transfer. Use it to broadcast transactions, refer to [this API](./onchain-gateway-api-broadcast-transaction) | | from | String | User's wallet address (e.g.,`0x3f6a3f57569358a512ccc0e513f171516b0fd42a`) | | gas | String | estimated amount of the gas limit, increase this value by 50% (e.g.,`1173250`).
To get accurate data, please take a look at [gas-limit](./onchain-gateway-api-gas-limit) API | | gasPrice | String | Gas price in wei (e.g.,`58270000000`) | | maxPriorityFeePerGas | String | EIP-1559: Recommended priority cost of gas per unit (e.g.,`500000000`) | | to | String | The contract address of OKX DEX router (e.g.,`0x3b3ae790Df4F312e745D270119c6052904FB6790`) | | value | String | The amount of native tokens (in wei) that will be sent to the contract address (e.g.,`0`) | | maxSpendAmount | String | The maximum amount of a token to spend when the price reaches the upper limit of slippage (applies to the exactOut mode) | | minReceiveAmount | String | The minimum amount of a token to buy when the price reaches the upper limit of slippage (e.g.,`900645839798`) | | data | String | Call data | | slippagePercent | String | The value of current transaction slippage |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/aggregator/swap?chainIndex=1&amount=100000000000&fromTokenAddress=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48&toTokenAddress=0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599&approveAmount=10000000&approveTransaction=true&slippagePercent=0.1&userWalletAddress=0x77660f108043c9e300b4e30a35a61dd19f5ae28a' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "routerResult": { "chainIndex": "1", "contextSlot": 24331258, "dexRouterList": [ { "dexProtocol": { "dexName": "Fluid", "percent": "62" }, "fromToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "tokenSymbol": "USDC", "tokenUnitPrice": "0.99965" }, "fromTokenIndex": "0", "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7", "tokenSymbol": "USDT", "tokenUnitPrice": "0.99861" }, "toTokenIndex": "1" }, { "dexProtocol": { "dexName": "DODO V2", "percent": "5" }, "fromToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "tokenSymbol": "USDC", "tokenUnitPrice": "0.99965" }, "fromTokenIndex": "0", "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7", "tokenSymbol": "USDT", "tokenUnitPrice": "0.99861" }, "toTokenIndex": "1" }, { "dexProtocol": { "dexName": "Uniswap V4", "percent": "8" }, "fromToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "tokenSymbol": "USDC", "tokenUnitPrice": "0.99965" }, "fromTokenIndex": "0", "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7", "tokenSymbol": "USDT", "tokenUnitPrice": "0.99861" }, "toTokenIndex": "1" }, { "dexProtocol": { "dexName": "Maverick V2", "percent": "24" }, "fromToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "tokenSymbol": "USDC", "tokenUnitPrice": "0.99965" }, "fromTokenIndex": "0", "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7", "tokenSymbol": "USDT", "tokenUnitPrice": "0.99861" }, "toTokenIndex": "1" }, { "dexProtocol": { "dexName": "CurveNG", "percent": "1" }, "fromToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "tokenSymbol": "USDC", "tokenUnitPrice": "0.99965" }, "fromTokenIndex": "0", "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7", "tokenSymbol": "USDT", "tokenUnitPrice": "0.99861" }, "toTokenIndex": "1" }, { "dexProtocol": { "dexName": "Native", "percent": "100" }, "fromToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7", "tokenSymbol": "USDT", "tokenUnitPrice": "0.99861" }, "fromTokenIndex": "1", "toToken": { "decimal": "8", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", "tokenSymbol": "WBTC", "tokenUnitPrice": "88645.26492049586" }, "toTokenIndex": "2" } ], "estimateGasFee": "1248837", "fromToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "tokenSymbol": "USDC", "tokenUnitPrice": "0.99965" }, "fromTokenAmount": "100000000000", "priceImpactPercent": "0.07", "router": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48--0xdac17f958d2ee523a2206206994597c13d831ec7--0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", "swapMode": "exactIn", "toToken": { "decimal": "8", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", "tokenSymbol": "WBTC", "tokenUnitPrice": "88645.26492049586" }, "toTokenAmount": "90281915", "tradeFee": "1.352992935519650381" }, "tx": { "data": "0xf2c426960000000000000000000000000000000000000000000000000000000000033d06000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599000000000000000000000000000000000000000000000000000000174876e8000000000000000000000000000000000000000000000000000000000005603711000000000000000000000000000000000000000000000000000000006979aceb00000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000000000500000000000000000000000097a7f8be1364759266cc5a619772458cc126b61200000000000000000000000056bd269db96a089295d742351ba459fb0c279fe20000000000000000000000005745050e787f693ed21e4418d528f78ad9c374a60000000000000000000000004e3bcce28caf98a143fd8bd9e4875ccab3e7bbe0000000000000000000000000ecd7eef15713997528896cb5db7ec316db4c2101000000000000000000000000000000000000000000000000000000000000000500000000000000000000000097a7f8be1364759266cc5a619772458cc126b61200000000000000000000000004571c32a4e1c5f39bc3a238cb95b215058c432c0000000000000000000000005745050e787f693ed21e4418d528f78ad9c374a60000000000000000000000004e3bcce28caf98a143fd8bd9e4875ccab3e7bbe0000000000000000000000000ecd7eef15713997528896cb5db7ec316db4c21010000000000000000000000000000000000000000000000000000000000000005000000000000000000011838667701e51b4d1ca244f17c78f7ab8744b4c99f9b8000000000000000000101f404571c32a4e1c5f39bc3a238cb95b215058c432c000000000000000000010320000000000000000000000000000000000000000000000000000000000001096031373595f40ea48a7aab6cbcb0d377c6066e2dca0000000000000000000100644f493b7de8aac7d55f71853688b1f7c8f0243c85000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000160000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000000000010000000000000000000000001d27ad3613e84e201bc87929590f95e75454cdc000000000000000000000000000000000000000000000000000000000000000010000000000000000000000001d27ad3613e84e201bc87929590f95e75454cdc00000000000000000000000000000000000000000000000000000000000000001800000000000000001022710a540ec8c73322200d68e1b86c471a5c850854f220000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000003e00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005d1a34369686ae59ac97ae4e1df5635ffda9ee7c000000000000000000000000129b3d9a0a6e4beab88f5cb1e57995d72a6e24f10000000000000000000000001d27ad3613e84e201bc87929590f95e75454cdc0000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599000000000000000000000000000000000000000000000000000000174ef64fae0000000000000000000000000000000000000000000000000000000006b9fdaa0000000000000000000000000000000000000000000000000000000006b161840000000000000000000000000000000000000000000000000000000069799f170000000000000000000000000000000000000000000000002ae6d79d5b8581cf0000000000000000000000000000000000000000000000000000000069799ee50000000000000000000000000000000000000000000000000000000069799f030000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002db2544f5d245c4492b8e58de6d17ff15700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002800000000000000000000000006044eef7179034319e2c8636ea885b37cbfa9aba000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000041f4a08483b0d36c2b107ddf05bc9596e63d1daf996633dae4bdc9d48bbebf5aec31c126225e0d705efafb952425103bf4ae5725c92f5289a88f31f3803a884fe31b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000416a640cb7bcd355ee971adbbb30efdbb640b612a8c418da8dee981562f9ff66d4063d9f119ca4f95e26a634fb485d46dba89e4d0f7fdafbd45545eb9813b43f2b1c0000000000000000000000000000000000000000000000000000000000000077777777111180000000000000000000000000000000000000000000056197bb777777771111000000000064fa00a9ed787f3793db668bff3e6e6e7db0f92a1b", "from": "0x77660f108043c9e300b4e30a35a61dd19f5ae28a", "gas": "1248837", "gasPrice": "557703374", "maxPriorityFeePerGas": "500000000", "maxSpendAmount": "", "minReceiveAmount": "90191633", "signatureData": [ "{\"approveContract\":\"0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f\",\"approveTxCalldata\":\"0x095ea7b300000000000000000000000040aa958dd87fc8305b97f2ba922cddca374bcd7f0000000000000000000000000000000000000000000000000000000000989680\"}" ], "slippagePercent": "0.1", "to": "0x5E1f62Dac767b0491e3CE72469C217365D5B48cC", "value": "0" } } ], "msg": "" } ```
- [Get Transaction Status](https://web3.okx.com/onchainos/dev-docs/trade/dex-swap-history.md) {/* api-page */} # Get Transaction Status Get the final transaction status of a single-chain swap using `txhash`. ### Request URL GET `https://web3.okx.com/api/v6/dex/aggregator/history` ## Request Parameters | Parameter | Type | Required | Description | |--------------------|--------|----------|----------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). | | txHash | String | Yes | Transaction hash for a swap initiated via OKX DEX API | | isFromMyProject | Boolean| No | Set `true` to check if the transaction is under the current API Key. Set `false` or omit to query any OKX DEX API transaction. |
## Response Parameters | Parameter | Type | Description | |---------------------|---------|-----------------------------------------------------------------------------| | chainIndex | String | Unique identifier for the chain. | | txHash | String | Transaction hash. | | height | String | Block height where the transaction occurred. | | txTime | String | Transaction time in Unix timestamp (milliseconds). | | status | String | Transaction status: `pending` (In Progress), `success` (Success), `fail` (Failure). | | txType | String | Transaction action: `Approve`, `Wrap`, `Unwrap`, `Swap`. | | fromAddress | String | Sender's address. | | dexRouter | String | Interaction address. | | toAddress | String | Receiver's address. | | fromTokenDetails | Array | Details of the token being swapped. | | >symbol | String | Symbol of the token being swapped. | | >amount | String | Swap amount in the smallest unit (e.g., wei for Ethereum). | | >tokenAddress | String | Contract address of the token being swapped (e.g., `0xEeeeeEeeeEeEee...`). | | toTokenDetails | Array | Details of the token received in the swap. | | >symbol | String | Symbol of the token received. | | >amount | String | Amount received in the smallest unit. | | >tokenAddress | String | Contract address of the received token (e.g., `0xa0b86991c6218b36...`). | | referalAmount | String | Referral fee amount. | | errorMsg | String | Error message. | | gasLimit | String | Gas limit for the transaction. | | gasUsed | String | Gas used in the transaction, in the smallest unit (e.g., wei). | | gasPrice | String | Gas price in the smallest unit (e.g., wei). | | txFee | String | Transaction fee, response in the native token amount.Applied in Solana and Sui chain |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/aggregator/history?chainIndex=784&txHash=5GePcvqEakoUtArW8PHULDSQds95vcgeiTznvbnb8hCV' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": { "chainIndex": "784", "dexRouter": "0x51159f25f262ae01e87532b673de3b38df8f0ecc2dc0581f1033df6b84b84955", "errorMsg": "", "fromAddress": "0x4b9df646075d8621e2578f14818427e4c708709744ea3b827136056f85f88da7", "fromTokenDetails": { "amount": "892919000000.000", "symbol": "HIPPO", "tokenAddress": "0x8993129d72e733985f7f1a00396cbd055bad6f817fee36576ce483c8bbb8b87b::sudeng::SUDENG" }, "gasLimit": "", "gasPrice": "", "gasUsed": "", "height": "99502953", "referralAmount": "892919000", "status": "success", "toAddress": "0x4b9df646075d8621e2578f14818427e4c708709744ea3b827136056f85f88da7", "toTokenDetails": { "amount": "1532443840.00000000", "symbol": "SUI", "tokenAddress": "0x2::sui::SUI" }, "txFee": "7976416", "txHash": "5GePcvqEakoUtArW8PHULDSQds95vcgeiTznvbnb8hCV", "txTime": "1736390263909", "txType": "swap" }, "msg": "" } ```
- [Adding Fees ](https://web3.okx.com/onchainos/dev-docs/trade/dex-api-addfee.md) # Adding Fees The OKX Wallet API supports configuring referral fees and fee-receiving addresses for token swaps You can extend the implementation to include fee parameters in your swap quotes and charge up to 3% per swap from your users for most supported networks; while for Solana you can charge up to 10% per swap. The OKX DEX API introduces a few API tiers to better support our integration partners. For details, please visit the [API fee](../home/api-fee) page. ```json // Extended quoteParams with fee support const quoteParams = { chainIndex: SOLANA_CHAIN_ID, amount: rawAmount, fromTokenAddress, toTokenAddress, slippagePercent: "0.5", // 0.5% slippagePercent userWalletAddress: userAddress, // Fee-related parameters fromTokenReferrerWalletAddress: "Your_REFERRER_WALLET_ADDRESS", // Optional: fee receiving address based on fromToken toTokenReferrerWalletAddress: "Your_REFERRER_WALLET_ADDRESS", // Optional: fee receiving address based on toToken feePercent: "1.5", // Optional: referrer fee percentage (max 9 decimal points) } as Record; ``` Important Fee Configuration Notes for feePercent parameter: - Min percentage > 0. Max percentage: 10 for Solana, 3 for all other chains - Maximum 9 decimal points, E.g. 1.3269018736% is the actual input, but the final calculation will only adopt 1.326901873% - For Solana, the fee receiving address must have some SOL deposited for activation - Each transaction can only choose referrer fee from either the fromToken or the toToken Example Usage with Fees: ```json // .. Previous code implementation // Get swap quote const quoteParams = { chainIndex: SOLANA_CHAIN_ID, amount: rawAmount, fromTokenAddress, toTokenAddress, slippagePercent: "0.5", // 0.5% slippagePercent userWalletAddress: userAddress, // Additional Fee params fromTokenReferrerWalletAddress: "fee-recipient-wallet-address", feePercent: "1", // The wallet addresses to receive the referrer fee (Each transaction can only choose referrer fee from either the fromToken or the toToken) // toTokenReferrerWalletAddress: "Fee receiving address, // fromTokenReferrerWalletAddress: "Fee receiving address", } as Record; const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/aggregator/swap"; const queryString = "?" + new URLSearchParams(quoteParams).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); const response = await fetch( `https://web3.okx.com${requestPath}${queryString}`, { method: "GET", headers } ); const data = await response.json(); // .. Continue code implementation ``` Command Line Usage with Fees: ```json # Example: Swap .01 SOL to USDC with 1.5% referrer fee npx ts-node swap.ts .01 11111111111111111111111111111111 EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v --referrer YOUR_FEE_RECEIVING_ADDRESS --fee 1.5 ``` Fee Calculation Example: For a trade of 100 USDC with a 1.5% fee: - Fee amount: 1.5 USDC (1.5% of 100 USDC) - Actual swap amount: 98.5 USDC - The fee (1.5 USDC) will be sent to the fee receiving address - [Market Maker Integration](https://web3.okx.com/onchainos/dev-docs/trade/dex-api-market-maker.md) # Market Maker Integration ## Overview OKX DEX’s RFQ system is built on-chain and designed for professional market makers to offer efficient, competitive pricing across supported chains. By leveraging off-chain quoting with on-chain settlement, we aim to deliver the best execution for traders in DeFi. Market makers integrate with OKX DEX to continuously provide pricing data, which is then processed by our smart order router to help users achieve optimal trades. ## Market Making on OKX DEX To operate as a market maker on OKX DEX, you must connect via our dedicated API suite and fulfill the following requirements: - Able to stream live price levels once every 1 seconds - Maintain a RFQ response time below 500 ms - Return signature for the taker execution ## Order Execution Modes OKX DEX only supports taker-executed orders. Users receive a firm and executable quote from the market maker. The taker signs and submits the transaction directly. Taker-executed orders contain the following characteristics: - The maker is not required to provide a gas fee estimation - The quote and signature are submitted together - The taker is responsible for the execution ## Price Levels Makers are required to stream price levels to OKX DEX servers at least once every 1 seconds for each token pair. Any price level older than 1 seconds is considered a stale quote and will be ignored. - Quotes must be non-cumulative and level-by-level - Quotes must a cumulative value of over 200 USD. Otherwise, they will be ignored by the system - OKX DEX will request price levels every second on each chain, so quotes must be updated frequently to ensure responsiveness and accuracy ## Aggregation and Smart Routing OKX DEX aggregates liquidity across multiple makers, AMM pools and routes orders based on optimal price and fillability. Our router dynamically splits orders across sources to minimize cost and maximize execution quality. - Unified order book across all makers - Partial fills may be requested based on your streamed depth ## Approvals OKX DEX enables asset transfers through user and market maker token allowances. We support two approval methods: approving via Permit2 or approving the OKX DEX settlement contract directly. Market makers must ensure they have granted sufficient approvals to the OKX DEX settlement contract or permit2 contract to cover the size of the levels they stream and the quotes they provide. ## Signing OKX DEX on EVM supports 2 signature schemes: - EIP-712 - EIP-1271

OKX DEX on Solana currently only supports Base58-encoded signatures.

## Transaction expiry time We enforce a fixed transaction expiry timing: 36 seconds for Ethereum and 32 seconds for EVM L2. This simplifies integration by removing the need for market makers to specify custom expiry times in quote requests, providing consistent behavior across all quotes and transactions, and establishing clear timeout boundaries at different stages of the flow. ## Time Decaying The contract supports a time-based slippage mechanism: if the user does not submit the transaction within a specified time, the price will slip by a defined number of bps per second, with a maximum slippage cap in place. ## Performance Requirements 1. You must maintain a rate of 200 RPS in firm-order, and 50 RPS in pricing 2. For the /pricing endpoint, market makers must update price quotes for each token pair within 1 seconds. We will ping your endpoint every second. If the 1-second window is exceeded, the quote for that token pair on the corresponding chain will be considered invalid. 3. The firm-order response time is 200 ms, and the maximum response time is 500 ms. Any responses above this will be dropped and marked as a failed response. 4. You must keep a successful response rate of over 90%, with at least 90% of orders successfully executed on-chain. ## Settlement Contract Address ```js const contractAddress = { ETH: '0x5035D128ef482276Aa3bCce4307ffF8961ba30F9' ARB: '0xcdC09a6B5211bb51F18A1Af7691B6725bB024434' Base: '0x4EFBd630205DD9B987c3BcbEe257600abC1e3C11' BSC: '0xdD30339C4b2f7bac319Ef4Fa5c6963cc9F470B2d' }; ``` ## Permit2 Contract Address ```js const contractAddress = { ETH: '0x000000000022D473030F116dDEE9F6B43aC78BA3' ARB: '0x000000000022D473030F116dDEE9F6B43aC78BA3' Base: '0x000000000022D473030F116dDEE9F6B43aC78BA3' BSC: '0x000000000022D473030F116dDEE9F6B43aC78BA3' }; ``` ## RFQ API Schema To facilitate the integration into OKX DEX RFQ module, you will need to provide a endpoint for us to return the pricing and firm-order endpoints with the corresponding request and response format. | Endpoint | Method | URL | Description| |--------------|--------|--------------------------------------------------------------------|------------| | Base URL | - | | Example URL that we will register into our API. | | pricing | GET | | The pricing endpoint get prices from market makers. Your levels will be used to determine if there is a path for a user order | | firm-order | POST | | Whenever a trader makes an quote request, the OKX DEX servers determine the best way to route that RFQ among the existing Market Makers. The winning Market Maker(s) receive messages and return the order and the signature. | ## API Key We would require an API key to access your endpoints. Please provide it to us during the registration process. The API Key will be passed to the endpoint as a header X-API-KEY. ## DEX EVM PMM Contract Please refer to: https://github.com/okxlabs/Web3-DEX-EVM-PMM ## Other Please provide your project LOGO and official web URL to OKX team - [Pricing](https://web3.okx.com/onchainos/dev-docs/trade/dex-api-market-maker-pricing.md) {/* api-page */} # Pricing OKX DEX will request relevant data using the parameters below and requires the following token and pricing information to obtain complete quote data: - Market makers must provide independent (non-cumulative) pricing - Pricing consists of from/to token amounts and prices - Includes: trading pair info, each price level, and depth Example: A taker wants to swap 1.26 WETH to USDT. The market maker would buy 0.2635658632112683 WETH at the price of 4257.065884207436. The remaining 0.9964341368 WETH would need to be fulfilled by other PMMs or AMMs. Another taker wants to swap 2000 USDT to WETH. The market maker would buy 1277.8023761262712 USDT at the price of 0.00023477808901049835 and buy 722.1976238737 USDT at a price of 0.00023474489972208067. ## Request Parameters | Parameter | Type | Required | Description| |--------------|--------|---------------------------------------------------------------|-----| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). |
## Response Parameters | Parameter | Type | Description | |-------------------- |-------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | chainIndex | String | Unique identifier for the chain. e.g., 1: Ethereum. See more here. | | levelData | Object | Leveldata are a list of how much quantity is available at what price, quotes must be non-cumulative, level-by-level | | >takerTokenAddress | String | The contract address of the token being sold by the taker and purchased by the maker (e.g., 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2) | | >makerTokenAddress | String | The contract address of the token being sold by the maker and purchased by the taker (e.g., 0xa892e1fef8b31acc44ce78e7db0a2dc610f92d00) | | >levels | String | levels are used to distinguish depth, where the first value is the quantity and the second value is the takerTokenRate, representing the taker/maker token exchange rate. Note: We do not require a minimum liquidity. |
## Request Example ```shell curl --location --request GET 'https://your-api-endpoint.com/OKXDEX/rfq/pricing?chainIndex=501' \ --header 'X-API-KEY: 37c541a1-****-****-****-10fe7a038418' \ ``` ## Response Example ```json { "code": "0", "msg": "", "data": { "chainIndex": "1", "levelData": [ { "takerTokenAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // WETH "makerTokenAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7", // USDT "levels": [ [ "0.2635658632112683", // Maker is willing to buy 0.2635658632112683 ETH "4257.065884207436" // takerTokenRate 1 WETH = 4257.065884207436 USDT ] ] }, { "takerTokenAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7", // USDT "makerTokenAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // WETH "levels": [ [ "1277.8023761262712", // Maker is willing to buy 1277.8023761262712 USDT "0.00023477808901049835"//takerTokenRate 1 USDT = 0.00023477808901049835 WETH ], [ "961.3366422965815", "0.00023474489972208067" ] ] } ] } } ```
- [Firm order](https://web3.okx.com/onchainos/dev-docs/trade/dex-api-market-maker-firm-order.md) {/* api-page */} # Firm order OKX DEX will request relevant data using the parameters below. ## Request Parameters | Parameter | Type | Required | Description| |--------------|--------|---------------------------------------------------------------|-----| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). | | takerAsset | String | Yes | Address of takerToken | | makerAsset | String | Yes | Address of makerToken | | takerAmount | String | Yes | Trade quantity of takerToken | | takerAddress | String | Yes | Address of Taker | | rfqId | Long | Yes | A unique identifier assigned to each quote request. | | expiryDuration | Integer | Yes | This parameter sets the validity duration of a quote or request, indicating the time interval from when the quote/request is generated until it expires. | | callData | String | No | The transaction needs to be signed, this requirement applies to Solana only. | beneficiaryAddress | String | No | Address of taker | | orderId | String | No | | | confidenceT | Long | No | Slippage start time (in seconds) | | confidenceRate | Long | No | Slippage per second, 1e6 | | confidenceCap | Long | No | Maximum slippage cap ,1e6 |
## Response Parameters | Parameter | Type | Required | Description | |--------------|--------|---------------------------------------------------------------|------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). | | pmmProtocol | String | Yes | settlement contract address | | makerAmount | String | Yes | Trade quantity of makerToken | | makerAddress | String | Yes | Address of order signer | | takerAsset | String | Yes | Address of takerToken | | makerAsset | String | Yes | Address of makerToken | | takerAmount | String | Yes | Trade quantity of takerToken | | takerAddress | String | Yes | Address of Taker | | rfqId | Long | Yes | A unique identifier assigned to each quote request. | | expiry | Timestamp | Yes | Expiration time. | | signature | String | Yes | The signature of market maker. | | callData | String | No | The signed transaction and the modified calldata.(required for solana) | | signatureScheme | String | No | EIP-712 or EIP-1271(required for EVM) | | usePermit2 | Boolean | No | Use Permit2 to approve, default is false.(required for EVM) | | permit2Signature | String | No | Optional inline Permit2 signature (65 bytes if present) | | permit2Witness | String | No | Packed witness hash when using Permit2 witnesses | | permit2WitnessType | String | No | Canonical witness type string for Permit2 | | confidenceT | Long | No | Request timestamp plus offset | | confidenceRate | Long | No | Slippage per second, 1e6 | | confidenceCap | Long | No | Maximum slippage cap ,1e6 |
## Request Example ```json `firm-order` Solana Example { "chainIndex" : "501", "takerAsset": "11111111111111111111111111111111", // Address of takerToken "makerAsset": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", // Address of makerToken "takerAmount": "6000000000000000", // Quantity of takerToken "takerAddress": "taker address", // Address of order taker "rfqId": 12345678, // uniqueId for the rfq "expiryDuration": 60, "callData": "d1KVBN6xw6sF1YzS5gDGGEp64jSmoB54umQyZeuHU8Mgctmok5vVvekq8DNUoPHDnb7Ydr42CyiQHAgkr8TnGFjk1AVr7yYF5MadmGPuLLRrn7KgMd7VHXccReChopuK8iJ2Co7CNmKULx75VtcZj7UMN2qeSQAPeMeAS2deNny3qiKnHXDYKFZRDyeZWnQrRPeSiithSiqc2fLb3XsN7S82Ho2M2D2Y5VbZnGZrJ7XVuPmTQrA5VXwGZpEYZg9QsqR6biy811YFHhvHTMTzMVbUhG988xyJSdxmVRkXBwbvLM2WCfr1Dppewg9pej9sqTG3zKx4NYSW27H9n5fV6SjgLReZCsX1RosN6Wk9ZpkUUHoWDfiGBCQWNdfaMD1mk8eFYXcgReCG2JDwQw8VRoVMhpUAf31Xyt7Ec2e9ug2X6XpXCctk4Adh9UMEJRqs7agEEzZwx638Cm99WfnDh7scDLBMYp4UaAkSmDVvnT8UpQoehrSxJefdzawFXhxVifkfPxi1VNKc4uinyHc4UWdhn9FFp37qJq2WsiACbRwEBmV8SQrZ77AL7MwcUPD8RqyR57Pxezk8KpH9PgEj7g6yRQjUzowDmesP5U9uVPSywUtgKDbtWVJXq4SgQUuSXY5YGWwxkQ6HYkPe6ga7ntziGfBQFbb7t9z1MDw6KAZcP7YPwGC9biEjgQxMyEaCBWzXDHWSvpYdrcLX4HRRLp8cWA3QBPcTZ6JFLFnRHLtn9fBwhz9G8v2544VzdNoVCj3pMsS9UZapDSnzbTFi2xKcyNQtDnRnnumUdz7pS4XtGz8V4tnfNozWCRC4TRg77vcCk81r8dPGrXKZQa2vusp7EvjtUyinmEuEhJvbwuvmRc1YsbrqibrRD2r6XEWFKLFE5adWz8gSZWwTj6ZWZDZtBw2QqVd1cSkuR1tEEaDs91nNGcgRitXeTJTuRNpGJWhcgNotEmK3NWTSmJZCiL7qaZeoatnYcVd6X3axxnyr2Dz4SwQePnVi5wVwJPtNiaWZ1V9kqpNwjTfuuk1aRyaWT55LGL71wSBWBgVuNxUYu9jTQ6cpyXxQiHYMHdhEcpdxYPzwe4gEx2EbPVSgL5mazUJHJoTwwhj9CFSsaXeiMaH2QsBw1TZVvLJboMw7Sa7eeAF6S9Q4CYyh4YSyjL6oLMmutz1a3X4xw3HkJHeEn3M2syP7GVP1xHreS9sso92MWHo3v7PyNgUwm3HyzgMNjXd" "beneficiaryAddress":"Es2vMFrzaCECmJfrF4H2FYD4KCoNkY11McCe9CenwUYB" // Address of taker } `firm-order` EVM Example { "chainIndex" : "1", "takerAsset": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // Address of takerToken "makerAsset": "0xdac17f958d2ee523a2206206994597c13d831ec7", // Address of makerToken "takerAmount": "6000000000000000", // Quantity of takerToken "takerAddress": "taker address", // Address of order taker "rfqId": 12345678, // uniqueId for the rfq "expiryDuration": 60 "beneficiaryAddress":"0xf921fb05ed9db87889f413d7fefb2cd4af03beb6" // Address of taker "orderId": 1002142110, // "confidenceT": 30, // Slippage start time (in seconds) "confidenceRate": 75, // Slippage per second, 1e6 "confidenceCap": 1200, // Maximum slippage cap ,1e6 } ``` ## Response Example ```json `firm-order` Solana Example { "code": "0", "msg": "", "data": { "chainIndex" : "501", "rfqId" : 12345678, "expiry": 172120120102, "makerAsset": "11111111111111111111111111111111", //Address of makerToken "takerAsset": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", //Address of takerToken "makerAddress": "DmTcmrZ7Dz8asHuuvk2G419JMzqdx58brUBidAegaevp", //Address of order signer "takerAddress": "3owrzVrYU5bpWH6LpTRiG5BQ8F4szDtFXavrBWXRohgW", //Address of trading user "makerAmount": "100000000", //Trade quantity of makerToken. TakerAmount * takerTokenRate "takerAmount": "6000000000000000", //Trade quantity of takerToken "signature": "c64bf62b7619edda019fe491da256b9fbe892fbfeac91f9d1fce168478ad53053dde038584f063fe21e267fcb4e758bcf420036cd2838fe5cbd993ec6d3dde561b", "callData": "d1KVBN6xw6sF1YzS5gDGGEp64jSmoB54umQyZeuHU8Mgctmok5vVvekq8DNUoPHDnb7Ydr42CyiQHAgkr8TnGFjk1AVr7yYF5MadmGPuLLRrn7KgMd7VHXccReChopuK8iJ2Co7CNmKULx75VtcZj7UMN2qeSQAPeMeAS2deNny3qiKnHXDYKFZRDyeZWnQrRPeSiithSiqc2fLb3XsN7S82Ho2M2D2Y5VbZnGZrJ7XVuPmTQrA5VXwGZpEYZg9QsqR6biy811YFHhvHTMTzMVbUhG988xyJSdxmVRkXBwbvLM2WCfr1Dppewg9pej9sqTG3zKx4NYSW27H9n5fV6SjgLReZCsX1RosN6Wk9ZpkUUHoWDfiGBCQWNdfaMD1mk8eFYXcgReCG2JDwQw8VRoVMhpUAf31Xyt7Ec2e9ug2X6XpXCctk4Adh9UMEJRqs7agEEzZwx638Cm99WfnDh7scDLBMYp4UaAkSmDVvnT8UpQoehrSxJefdzawFXhxVifkfPxi1VNKc4uinyHc4UWdhn9FFp37qJq2WsiACbRwEBmV8SQrZ77AL7MwcUPD8RqyR57Pxezk8KpH9PgEj7g6yRQjUzowDmesP5U9uVPSywUtgKDbtWVJXq4SgQUuSXY5YGWwxkQ6HYkPe6ga7ntziGfBQFbb7t9z1MDw6KAZcP7YPwGC9biEjgQxMyEaCBWzXDHWSvpYdrcLX4HRRLp8cWA3QBPcTZ6JFLFnRHLtn9fBwhz9G8v2544VzdNoVCj3pMsS9UZapDSnzbTFi2xKcyNQtDnRnnumUdz7pS4XtGz8V4tnfNozWCRC4TRg77vcCk81r8dPGrXKZQa2vusp7EvjtUyinmEuEhJvbwuvmRc1YsbrqibrRD2r6XEWFKLFE5adWz8gSZWwTj6ZWZDZtBw2QqVd1cSkuR1tEEaDs91nNGcgRitXeTJTuRNpGJWhcgNotEmK3NWTSmJZCiL7qaZeoatnYcVd6X3axxnyr2Dz4SwQePnVi5wVwJPtNiaWZ1V9kqpNwjTfuuk1aRyaWT55LGL71wSBWBgVuNxUYu9jTQ6cpyXxQiHYMHdhEcpdxYPzwe4gEx2EbPVSgL5mazUJHJoTwwhj9CFSsaXeiMaH2QsBw1TZVvLJboMw7Sa7eeAF6S9Q4CYyh4YSyjL6oLMmutz1a3X4xw3HkJHeEn3M2syP7GVP1xHreS9sso92MWHo3v7PyNgUwm3HyzgMNjXd" } } `firm-order` EVM Example { "chainIndex" : "1", "rfqId" : 12345678, "expiry": 172120120102, "pmmProtocol": "0x0Bdf246b4AEF9Cfe4DD6eEf153A1b645aC4BcBb6", //settlement contract address "makerAsset": "0xdac17f958d2ee523a2206206994597c13d831ec7", //Address of makerToken "takerAsset": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", //Address of takerToken "makerAddress": "0xcfdfea67395c531249a9e1dc8d916c9158810509", //Address of order signer "takerAddress": "0xF36bC73f9783539E1DAC8Cf6d2bfd74e0663699C", //Address of trading user "makerAmount": "100000000", //Trade quantity of makerToken. TakerAmount * takerTokenRate "takerAmount": "6000000000000000", //Trade quantity of takerToken "signature": "0xc64bf62b7619edda019fe491da256b9fbe892fbfeac91f9d1fce168478ad53053dde038584f063fe21e267fcb4e758bcf420036cd2838fe5cbd993ec6d3dde561b", "sign_scheme": "EIP-712" //EIP-712 or 1271, "usePermit2": false "confidenceT": 1769767048, // Request timestamp plus offset "confidenceRate": 75, // Slippage per second, 1e6 "confidenceCap": 1200, // Maximum slippage cap ,1e6 } ```
- [EVM Signature](https://web3.okx.com/onchainos/dev-docs/trade/dex-api-market-maker-sdk.md) # EVM Signature ## EVM EIP-712 Signature Debug Tool https://okxlabs.github.io/DEX-Router-Tools-Suite/docs/ ## EVM Signature SDK ```javascript // signOrderRFQ.js import { Wallet, ethers } from "ethers"; /** * Sign an OrderRFQ-typed struct and return the signature string * * @param {string} privateKey - Signer's private key (EOA) * @param {string} verifyingContract - Address of the contract used for signature verification * @param {number} chainId - Current chain ID * @param {object} order - Order object containing fields like rfqId, expiration, etc. * @returns {Promise} - EIP-712 signature string */ export async function signOrderRFQ({ privateKey, verifyingContract, chainId, order }) { const wallet = new Wallet(privateKey); const domain = { name: "OnChain Labs PMM Protocol", version: "1.0", chainId, verifyingContract, }; // OrderRFQ typehash from Solidity - must match exactly const ORDER_RFQ_TYPEHASH = ethers.keccak256(ethers.toUtf8Bytes( "OrderRFQ(uint256 rfqId,uint256 expiry,address makerAsset,address takerAsset,address makerAddress,uint256 makerAmount,uint256 takerAmount,bool usePermit2,bytes permit2Signature,bytes32 permit2Witness,string permit2WitnessType)" )); // Domain separator calculation matching Solidity const EIP712_DOMAIN_TYPEHASH = ethers.keccak256(ethers.toUtf8Bytes( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" )); const domainSeparator = ethers.keccak256(ethers.AbiCoder.defaultAbiCoder().encode( ["bytes32", "bytes32", "bytes32", "uint256", "address"], [ EIP712_DOMAIN_TYPEHASH, ethers.keccak256(ethers.toUtf8Bytes(domain.name)), ethers.keccak256(ethers.toUtf8Bytes(domain.version)), domain.chainId, domain.verifyingContract ] )); // Struct hash calculation matching Solidity OrderRFQLib.hash() const structHash = ethers.keccak256(ethers.AbiCoder.defaultAbiCoder().encode( ["bytes32", "uint256", "uint256", "address", "address", "address", "uint256", "uint256", "bool", "bytes32", "bytes32", "bytes32"], [ ORDER_RFQ_TYPEHASH, order.rfqId, order.expiry, order.makerAsset, order.takerAsset, order.makerAddress, order.makerAmount, order.takerAmount, order.usePermit2, ethers.keccak256(order.permit2Signature), // Hashed like in Solidity order.permit2Witness, ethers.keccak256(ethers.toUtf8Bytes(order.permit2WitnessType)) // Hashed like in Solidity ] )); // Final digest calculation matching ECDSA.toTypedDataHash const digest = ethers.keccak256(ethers.concat([ "0x1901", domainSeparator, structHash ])); // Sign the digest directly (EIP-712 signature, no Ethereum message prefix) // Use signingKey.sign() to sign the raw digest without any prefixes const sig = wallet.signingKey.sign(digest); // Reconstruct signature as r + s + v to match Solidity abi.encodePacked(r, s, v) const rearrangedSignature = ethers.concat([sig.r, sig.s, ethers.toBeHex(sig.v, 1)]); return ethers.hexlify(rearrangedSignature); } export const EXAMPLE_WITNESS_TYPEHASH = ethers.keccak256(ethers.toUtf8Bytes("ExampleWitness(address user)")); export const WITNESS_TYPE_STRING = "ExampleWitness witness)ExampleWitness(address user)TokenPermissions(address token,uint256 amount)" export const TOKEN_PERMISSIONS_TYPEHASH = ethers.keccak256(ethers.toUtf8Bytes("TokenPermissions(address token,uint256 amount)")); /** * Calculate permit2 witness hash from witness data * * @param {object} witnessData - Witness data object (e.g., { user: address }) * @param {string} witnessTypehash - Keccak256 hash of the witness type string * @returns {string} - Witness hash as bytes32 */ export function calculateWitness(witnessData, witnessTypehash = EXAMPLE_WITNESS_TYPEHASH) { // For ExampleWitness struct: { user: address } const encodedWitness = ethers.AbiCoder.defaultAbiCoder().encode( ["bytes32", "address"], [witnessTypehash, witnessData.user] ); return ethers.keccak256(encodedWitness); } /** * Sign Permit2 with witness support * * @param {object} permit - Permit2 PermitTransferFrom object with { permitted: { token, amount }, nonce, deadline } * @param {string} spender - Spender address (usually the PMM contract) * @param {string} witness - Witness hash (bytes32) * @param {string} witnessTypeString - Full witness type string for EIP-712 * @param {string} privateKey - Signer's private key * @param {string} permit2DomainSeparator - Permit2 contract's domain separator * @returns {Promise} - Permit2 signature */ export async function signPermit2WithWitness({ permit, spender, witness, witnessTypeString, privateKey, permit2DomainSeparator }) { const wallet = new Wallet(privateKey); const TOKEN_PERMISSIONS_TYPEHASH = ethers.keccak256( ethers.toUtf8Bytes("TokenPermissions(address token,uint256 amount)") ); // Construct the full type hash for PermitWitnessTransferFrom const PERMIT_WITNESS_TRANSFER_FROM_TYPEHASH = ethers.keccak256( ethers.toUtf8Bytes( `PermitWitnessTransferFrom(TokenPermissions permitted,address spender,uint256 nonce,uint256 deadline,${witnessTypeString}` ) ); // Encode the TokenPermissions struct const tokenPermissionsHash = ethers.keccak256( ethers.AbiCoder.defaultAbiCoder().encode( ["bytes32", "address", "uint256"], [TOKEN_PERMISSIONS_TYPEHASH, permit.permitted.token, permit.permitted.amount] ) ); // Encode the main struct const structHash = ethers.keccak256( ethers.AbiCoder.defaultAbiCoder().encode( ["bytes32", "bytes32", "address", "uint256", "uint256", "bytes32"], [ PERMIT_WITNESS_TRANSFER_FROM_TYPEHASH, tokenPermissionsHash, spender, permit.nonce, permit.deadline, witness ] ) ); // Create the final digest const digest = ethers.keccak256( ethers.concat([ "0x1901", permit2DomainSeparator, structHash ]) ); // Sign the digest directly (EIP-712 signature, no Ethereum message prefix) // Use _signingKey().sign() to sign the raw digest without any prefixes const sig = wallet.signingKey.sign(digest); // Reconstruct signature as r + s + v to match Solidity abi.encodePacked(r, s, v) const rearrangedSignature = ethers.concat([sig.r, sig.s, ethers.toBeHex(sig.v, 1)]); return ethers.hexlify(rearrangedSignature); } ``` ## EVM Signing Example ```javascript import { signOrderRFQ, calculateWitness, WITNESS_TYPE_STRING, signPermit2WithWitness } from "./signOrderRFQ.js"; const currentTime = Math.floor(Date.now() / 1000); const expiry = currentTime + 90; const MAKER_ADDRESS = "YOUR_ADDRESS"; const privateKey = "YOUR_PRIVATE_KEY"; const VERIFYING_CONTRACT = "0x5C1c902e7E04DE98b49aCd3De68E12BEE2d7908D"; const PERMIT2_DOMAIN_SEPARATOR = "0x8a6e6e19bdfb3db3409910416b47c2f8fc28b49488d6555c7fceaa4479135bc3"; const MAKER_ASSET = "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"; const TAKER_ASSET = "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9"; const MAKER_AMOUNT = 400000000000000; const TAKER_AMOUNT = 1000; const chainId = 42161; const rfqId = 42; // Order 1: usePermit2: false const order1 = { privateKey: privateKey, verifyingContract: VERIFYING_CONTRACT, chainId: chainId, order: { rfqId: rfqId, expiry: expiry, makerAsset: MAKER_ASSET, takerAsset: TAKER_ASSET, makerAddress: MAKER_ADDRESS, makerAmount: MAKER_AMOUNT, takerAmount: TAKER_AMOUNT, usePermit2: false, permit2Signature: "0x", permit2Witness: "0x0000000000000000000000000000000000000000000000000000000000000000", permit2WitnessType: "" }, }; // Order 2: usePermit2: true, no witness const order2 = { privateKey: privateKey, verifyingContract: VERIFYING_CONTRACT, chainId: chainId, order: { rfqId: rfqId, expiry: expiry, makerAsset: MAKER_ASSET, takerAsset: TAKER_ASSET, makerAddress: MAKER_ADDRESS, makerAmount: MAKER_AMOUNT, takerAmount: TAKER_AMOUNT, usePermit2: true, permit2Signature: "0x", permit2Witness: "0x0000000000000000000000000000000000000000000000000000000000000000", permit2WitnessType: "" }, }; // Order 3: usePermit2: true, with witness const order3 = { privateKey: privateKey, verifyingContract: VERIFYING_CONTRACT, chainId: chainId, order: { rfqId: rfqId, expiry: expiry, makerAsset: MAKER_ASSET, takerAsset: TAKER_ASSET, makerAddress: MAKER_ADDRESS, makerAmount: MAKER_AMOUNT, takerAmount: TAKER_AMOUNT, usePermit2: true, permit2Signature: await signPermit2WithWitness({ permit: { permitted: { token: MAKER_ASSET, amount: MAKER_AMOUNT }, nonce: rfqId, deadline: expiry }, spender: VERIFYING_CONTRACT, witness: calculateWitness({ user: MAKER_ADDRESS }), witnessTypeString: WITNESS_TYPE_STRING, privateKey: privateKey, permit2DomainSeparator: PERMIT2_DOMAIN_SEPARATOR }), permit2Witness: calculateWitness({ user: MAKER_ADDRESS }), permit2WitnessType: WITNESS_TYPE_STRING }, }; console.log("Signature 1:", await signOrderRFQ(order1)); console.log("Signature 2:", await signOrderRFQ(order2)); console.log("Signature 3:", await signOrderRFQ(order3)); console.log("permit2Signature (Order 3):", order3.order.permit2Signature); ``` ## EVM testSignOrder ```javascript import "dotenv/config"; import { ethers } from "ethers"; import { calculateWitness, calculateWitnessConsideration, signOrderRFQ, signPermit2WithWitness, WITNESS_TYPE_STRING } from "./signOrderRFQ.js"; const currentTime = Math.floor(Date.now() / 1000); const expiry = currentTime + 1000*60 * 60 * 24 * 30; const privateKey = process.env.PK; const MAKER_ADDRESS = new ethers.Wallet(privateKey).address; const VERIFYING_CONTRACT = "0x1Ef032a3c471a99CC31578c8007F256D95E89896"; const PERMIT2_DOMAIN_SEPARATOR = "0x8a6e6e19bdfb3db3409910416b47c2f8fc28b49488d6555c7fceaa4479135bc3"; const MAKER_ASSET = "0xaf88d065e77c8cC2239327C5EDb3A432268e5831"; const TAKER_ASSET = "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9"; const MAKER_AMOUNT = 100; const TAKER_AMOUNT = 90; const chainId = 42161; const rfqId = Math.floor(Math.random() * 10000000000000); // Order 1: usePermit2: false const order1 = { privateKey: privateKey, verifyingContract: VERIFYING_CONTRACT, chainId: chainId, order: { rfqId: rfqId, expiry: expiry, makerAsset: MAKER_ASSET, takerAsset: TAKER_ASSET, makerAddress: MAKER_ADDRESS, makerAmount: MAKER_AMOUNT, takerAmount: TAKER_AMOUNT, usePermit2: false, permit2Signature: "0x", permit2Witness: "0x0000000000000000000000000000000000000000000000000000000000000000", permit2WitnessType: "" }, }; // Order 2: usePermit2: true, no witness const order2 = { privateKey: privateKey, verifyingContract: VERIFYING_CONTRACT, chainId: chainId, order: { rfqId: rfqId, expiry: expiry, makerAsset: MAKER_ASSET, takerAsset: TAKER_ASSET, makerAddress: MAKER_ADDRESS, makerAmount: MAKER_AMOUNT, takerAmount: TAKER_AMOUNT, usePermit2: true, permit2Signature: "0x", permit2Witness: "0x0000000000000000000000000000000000000000000000000000000000000000", permit2WitnessType: "" }, }; // Order 3: usePermit2: true, with witness const order3 = { privateKey: privateKey, verifyingContract: VERIFYING_CONTRACT, chainId: chainId, order: { rfqId: rfqId, expiry: expiry, makerAsset: MAKER_ASSET, takerAsset: TAKER_ASSET, makerAddress: MAKER_ADDRESS, makerAmount: MAKER_AMOUNT, takerAmount: TAKER_AMOUNT, usePermit2: true, permit2Signature: await signPermit2WithWitness({ permit: { permitted: { token: MAKER_ASSET, amount: MAKER_AMOUNT }, nonce: rfqId, deadline: expiry }, spender: VERIFYING_CONTRACT, witness: calculateWitness({ user: MAKER_ADDRESS }), witnessTypeString: WITNESS_TYPE_STRING, privateKey: privateKey, permit2DomainSeparator: PERMIT2_DOMAIN_SEPARATOR }), permit2Witness: calculateWitness({ user: MAKER_ADDRESS }), permit2WitnessType: WITNESS_TYPE_STRING }, }; const TAKER_ADDRESS = "0x1111111111111111111111111111111111111111"; const CONSIDERATION = { token: MAKER_ASSET, amount: MAKER_AMOUNT, counterparty: TAKER_ADDRESS }; const CONSIDERATION_TYPE_STRING_STUB = "Consideration witness)Consideration(address token,uint256 amount,address counterparty)TokenPermissions(address token,uint256 amount)"; // Order 4: usePermit2: true, with witness const order4 = { privateKey: privateKey, verifyingContract: VERIFYING_CONTRACT, chainId: chainId, order: { rfqId: rfqId, expiry: expiry, makerAsset: MAKER_ASSET, takerAsset: TAKER_ASSET, makerAddress: MAKER_ADDRESS, makerAmount: MAKER_AMOUNT, takerAmount: TAKER_AMOUNT, usePermit2: true, permit2Signature: await signPermit2WithWitness({ permit: { permitted: { token: MAKER_ASSET, amount: MAKER_AMOUNT }, nonce: rfqId, deadline: expiry }, spender: VERIFYING_CONTRACT, witness: calculateWitnessConsideration(CONSIDERATION), witnessTypeString: CONSIDERATION_TYPE_STRING_STUB, privateKey: privateKey, permit2DomainSeparator: PERMIT2_DOMAIN_SEPARATOR }), permit2Witness: calculateWitnessConsideration(CONSIDERATION), permit2WitnessType: CONSIDERATION_TYPE_STRING_STUB }, }; // console.log("Signature 1:", await signOrderRFQ(order1)); // console.log("Signature 2:", await signOrderRFQ(order2)); // console.log("Signature 3:", await signOrderRFQ(order3)); console.log("CONSIDERATION:", CONSIDERATION); console.log("order4:", order4); const order4Signature = await signOrderRFQ(order4); console.log("Signature 4:", order4Signature); // send tx to fill order (optional) // Requirements: // - export RPC_URL=https://arb1.arbitrum.io/rpc (or your node) // - export TAKER_PK=0x... // - export SEND_TX=1 const sendTx = async () => { const rpcUrl = process.env.RPC_URL || "https://arb1.arbitrum.io/rpc"; const takerPk = process.env.PK; if (!takerPk) throw new Error("missing env: TAKER_PK"); const provider = new ethers.JsonRpcProvider(rpcUrl, chainId); const taker = new ethers.Wallet(takerPk, provider); const pmmAbi = [ "function fillOrderRFQTo((uint256 rfqId,uint256 expiry,address makerAsset,address takerAsset,address makerAddress,uint256 makerAmount,uint256 takerAmount,bool usePermit2,bytes permit2Signature,bytes32 permit2Witness,string permit2WitnessType) order, bytes signature, uint256 flagsAndAmount, address target) returns (uint256,uint256,bytes32)", ]; const pmm = new ethers.Contract(VERIFYING_CONTRACT, pmmAbi, taker); const flagsAndAmount = BigInt(order4.order.takerAmount); const target = taker.address; const tx = await pmm.fillOrderRFQTo(order4.order, order4Signature, flagsAndAmount, target); console.log("fill tx:", tx.hash); await tx.wait(); } sendTx(); // console.log("permit2Signature (Order 3):", order3.order.permit2Signature); ``` - [Smart Contract](https://web3.okx.com/onchainos/dev-docs/trade/dex-smart-contract.md) # Smart Contract The contract addresses of OKX DEX router and ABI ## Contract Address The contract addresses of the DEX router and token approval may be subject to replacement due to contract upgrades. To ensure uninterrupted use of the API, we recommend using the contract addresses returned by the response parameters: `/approve-transaction` API and `/swap` API for approvals and transactions. ### DEX Router | Chain | DEX router address | |----------------|----------------------------------------------| | Ethereum | 0x28b1Dc1a5E3699A428BC51d234DFab7C9CB2a183 | | Solana | proVF4pMXVaYqmy4NjniPh4pqKNfMmsihgd4wdkCX3u | | SUI | 0x0705aa6aad0a6195d1da7f1b1b057d58684040459c375db056059b1747d5d1f0
extended: 0xfb62ac68863a8cf5066a04171ea173c49051049a460163304bd4a938f0a7ef3a extended: 0xab71c2c2c37f973e28b2d28847046615bf47acc85ffc3ba2eb3d9a6442b18422 SUI packge id 大小限制,部署 extended 合约,支持 Momentum、Scallop、Haedal、Alphafi 等流动性)| | Sonic | 0x79f7C6C6dc16Ed3154E85A8ef9c1Ef31CEFaEB19 | | Tron | TAGVH5t42MuofaAfUauPPRe4Qw3i8Z3QHM | | Ton | EQAgvOlWk7C0Pz3YgSaX-MA7UDDhE9n6eQgQRwJahOBm4VKr | | zkSync Era | 0x6f7c20464258c732577c87a9B467619e03e5C158 | | Optimism | 0xDd5E9B947c99Aa60bab00ca4631Dce63b49983E7 | | Polygon | 0xF6E1B4b201e220FC3741bd7a75675ffEA25c02AD | | BNB Chain | 0x62cceF0b4545166f721cAa9fEe13c1d3767E27dc | | Avalanche C | 0xa94Fcf9fc56a864f8DE51e6315aee5863AD63C91 | | Fantom | 0x25e7f77F33206d311A0130D4b5B881E5Db1181b1 | | Arbitrum | 0x7CF6b330b437E9fb432B1400DE17B03357Cf049A | | Linea | 0x2E1Dee213BA8d7af0934C49a23187BabEACa8764 | | Conflux eSpace | 0x95418635f012fFd10eAFcDaF4137e90371f06917 | | Base | 0xC8F6b8Ba0DC0f175B568B99440B0867F69A29265 | | Mantle | 0xcF76984119C7f6ae56fAfE680d39C08278b7eCF4 | | Scroll | 0x5e2F47bD7D4B357fCfd0Bb224Eb665773B1B9801 | | Manta | 0x69C236E021F5775B0D0328ded5EaC708E3B869DF | | Metis | 0x25e7f77F33206d311A0130D4b5B881E5Db1181b1 | | Blast | 0xcF76984119C7f6ae56fAfE680d39C08278b7eCF4 | | Zeta | 0xF5402CCC5fC3181B45D7571512999D3Eea0257B6 | | Polygon zkEvm | 0x6f7c20464258c732577c87a9B467619e03e5C158 | | Merlin | 0x6f7c20464258c732577c87a9B467619e03e5C158 | | X Layer | 0xbec6d0E341102732e4FD62EC50E2F0a9D1bd1D33 | | UniChain | 0x6733Eb2E75B1625F1Fe5f18aD2cB2BaBDA510d19 | | Cronos | 0x25e7f77F33206d311A0130D4b5B881E5Db1181b1 | | Plasma | 0x19D345f95A80cc136d898f41b490E023cFF78658 | | Monad | 0x7A7AD9aa93cd0A2D0255326E5Fb145CEc14997FF | DEX Router Addresses for OKX DEX used in signing exactOut transactions | Chain Name | DEX Router Contract Address | |----------------|--------------------------------------------------| | Ethereum | 0xa875Fb2204cE71679BE054d97f7fAFFeb6536D67 | | Base | 0x77449Ff075C0A385796Da0762BCB46fd5cc884c6 | | BNB Chain | 0x5cb43Bae4f36E2f9f858232B4Dce0dbE27bb85e3 | | Arbitrum | 0x9736d9a45115E33411390EbD54e5A5C3A6E25aA6 | ### Token Approval A list of smart contracts for ERC-20 token approval. Ton and Solana chains do not require authorization. | Chain | Approval contract address | |----------------|--------------------------------------------| | Ethereum | 0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f | | Tron | THRAE2VhGNAcvPKtT96AqyXtSQwhiU1XL8 | | Sonic | 0xd321ab5589d3e8fa5df985ccfef625022e2dd910 | | zkSync Era | 0xc67879F4065d3B9fe1C09EE990B891Aa8E3a4c2f | | Optimism | 0x68D6B739D2020067D1e2F713b999dA97E4d54812 | | Polygon | 0x3B86917369B83a6892f553609F3c2F439C184e31 | | BNB Chain | 0x2c34A2Fb1d0b4f55de51E1d0bDEfaDDce6b7cDD6 | | OKC | 0x70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58 | | Avalanche C | 0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f | | Fantom | 0x70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58 | | Arbitrum | 0x70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58 | | Linea | 0x57df6092665eb6058DE53939612413ff4B09114E | | Conflux eSpace | 0x68D6B739D2020067D1e2F713b999dA97E4d54812 | | Base | 0x57df6092665eb6058DE53939612413ff4B09114E | | Mantle | 0x57df6092665eb6058DE53939612413ff4B09114E | | Scroll | 0x57df6092665eb6058DE53939612413ff4B09114E | | Manta | 0x57df6092665eb6058DE53939612413ff4B09114E | | Metis | 0x57df6092665eb6058DE53939612413ff4B09114E | | Blast | 0x5fD2Dc91FF1dE7FF4AEB1CACeF8E9911bAAECa68 | | Zeta | 0x03B5ACdA01207824cc7Bc21783Ee5aa2B8d1D2fE | | Polygon zkEvm | 0x57df6092665eb6058DE53939612413ff4B09114E | | Merlin | 0x8b773D83bc66Be128c60e07E17C8901f7a64F000 | | X Layer | 0x8b773D83bc66Be128c60e07E17C8901f7a64F000 | | UniChain | 0x2e28281Cf3D58f475cebE27bec4B8a23dFC7782c | | Cronos | 0x70cbb871e8f30fc8ce23609e9e0ea87b6b222f58 | | Plasma | 0x9FD43F5E4c24543b2eBC807321E58e6D350d6a5A | | Monad | 0xf534A8a1CAD0543Cd6438f7534CA3486c01998d4 | ## Contract Application Binary Interface (ABI) Please refer to: https://github.com/okxlabs/DEX-Router-EVM-V1/tree/main/DexRouterabi https://github.com/okxlabs/Web3-DEX-EVM-PMM - [Error Codes](https://web3.okx.com/onchainos/dev-docs/trade/dex-error-code.md) # Error Codes ## Swap API | Code | HTTP status | Message | | ----- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 0 | 200 | Succeeded | | 50011 | 429 | Rate limit reached. Please refer to API documentation and throttle requests accordingly | | 50014 | 400 | Parameter param0 cannot be empty | | 50026 | 500 | System error. Try again later | | 50103 | 401 | Request header "OK-ACCESS-KEY" cannot be empty | | 50104 | 401 | Request header "OK-ACCESS-PASSPHRASE" cannot be empty | | 50105 | 401 | Request header "OK-ACCESS-PASSPHRASE" incorrect | | 50106 | 401 | Request header "OK-ACCESS-SIGN" cannot be empty | | 50107 | 401 | Request header "OK-ACCESS-TIMESTAMP" cannot be empty | | 50111 | 401 | Invalid OK-ACCESS-KEY | | 50112 | 401 | Invalid OK-ACCESS-TIMESTAMP | | 50113 | 401 | Invalid signature | | 51000 | 400 | Parameter param0 error | | 80000 | 200 | Repeated request | | 80001 | 200 | CallData exceeds the maximum limit. Try again in 5 minutes. | | 80002 | 200 | Requested token Object count has reached the limit. | | 80003 | 200 | Requested native token Object count has reached the limit. | | 80004 | 200 | Timeout when querying SUI Object. | | 80005 | 200 | Not enough Sui objects under the address for swapping | | 82000 | 200 | Insufficient liquidity | | 82001 | 500 | The commission service is not available during the upgrade | | 82003 | 200 | toTokenReferrerWalletAddress address is not valid | | 82102 | 200 | Less than the minimum quantity limit,the minimum amount is 0 | | 82103 | 200 | Exceeds than the maximum quantity limit,the maximum amount is 0 | | 82104 | 200 | This token is not supported | | 82105 | 200 | This chain is not supported | | 82112 | 200 | The value difference from this transaction’s quote route is higher than num, which may cause asset loss,The default value is 90%. It can be adjusted using the string age. | | 82116 | 200 | callData exceeds the maximum limit. Try again in 5 minutes. | | 82130 | 200 | The chain does not require authorized transactions and can be exchanged directly. | | 82004 | 200 | Commission split for swaps via Four.meme is not supported | | 82005 | 200 | Commission split for swaps via aspecta is not supported | ## RFQ API Market makers should return appropriate HTTP status codes along with error messages. | Code | HTTP status | Message | | ----- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | 0 | 200 | The request was successful, and the endpoint will return a quote. | | 404 | 404 | The endpoint will not return a quote for this request (e.g. the pair or the size are not supported). | | 400 | 400 | The request sent to the endpoint is malformed (e.g. missing an expected parameter). | | 401 | 401 | Authorization failed. For example the X-API-KEY is missing or incorrect. | | 50x | 50x | The endpoint is offline or unable to respond. If the status persist, the endpoint will be temporarily suspended and will not receive requests. | | 82000 | 200 | Liquidity too low for this quote | | 82001 | 200 | The quote does not exceed the minimum size of the maker | | 82002 | 200 | The maker is unavailable to handle the quote | | 82003 | 200 | The maker rejects to respond to this user | - [FAQ](https://web3.okx.com/onchainos/dev-docs/trade/dex-aggregation-faq.md) # FAQ ## What Is the Native Token Address for Each Chain? We have defined the native tokens for each chain. Please refer to the table below for details: | Chain Name | Native Token Address | |------------|----------------------------------------------------| | EVM | 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee | | Solana | 11111111111111111111111111111111 | | Sui | 0x2::sui::SUI | | Tron | T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb | | Ton | EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c | ## What Is “Transfer amount exceeds allowance”? This error message indicates that the amount you're trying to transfer exceeds the approved limit. Set your approval limit higher than the amount you wish to transfer to resolve this error. ## What Is “min return not reached”? This means that the expected minimum return was not met during trade execution. This usually happens when there is a significant slippage or high market volatility. If the expected minimum return is not met, the trade will not be executed.
You may increase slippage to raise the chances of the order going through as a higher slippage allows a greater price fluctuation at execution. However, please note that too high a slippage may lead to results that are worse than expected. ## Which Tokens Require an Approval Transaction? 1. EVM + Tron: Typically, non-native tokens (such as ERC-20/TRC-20 tokens on Ethereum or Tron) require an approval transaction. This ensures that you are allowing the smart contract to transfer these tokens from your account. 2. Other heterogeneous chains: On some other chains, such as Solana, approval transactions are not required for tokens. - [Introduction](https://web3.okx.com/onchainos/dev-docs/trade/onchain-gateway-api-introduction.md) # Introduction The Transaction API offers on-chain simulation and on-chain transaction broadcasting services, supporting both self-developed RPC nodes and external premium RPC nodes. By leveraging OKX Web3's advanced node management infrastructure and expertise, it enables intelligent transaction broadcasting, significantly reducing failure rates and accelerating confirmation speeds. Developers can seamlessly integrate the Transaction API with the Swap API to create a comprehensive DEX experience to their users, eliminating the need for additional external resources. **Key capabilities** 1. **High-availability hybrid node architecture** - Self-developed multi-chain node clusters for robust performance. - Intelligent integration of third-party premium node resources to build a redundant and resilient network. - Dynamic load balancing with real-time node health monitoring and sub-second failover for uninterrupted services. 2. **Intelligent multi-broadcasting engine** - Breakthrough capability to broadcast transactions across multiple node networks simultaneously. - Enhanced on-chain success rates through advanced distributed propagation algorithms. - Priority block packaging acceleration for major chains like ETH, BNB Chain, and Solana and more. - [API Reference](https://web3.okx.com/onchainos/dev-docs/trade/onchain-gateway-reference.md) # API Reference - [Get Supported Chains](https://web3.okx.com/onchainos/dev-docs/trade/onchain-gateway-api-chains.md) {/* api-page */} # Get Supported Chains Retrieve information on chains supported by Onchain gateway API ### Request URL GET `https://web3.okx.com/api/v6/dex/pre-transaction/supported/chain` ## Request Parameters None ## Response Parameters | Parameter | Type | Description | |-----------|--------|-------------------| | name | String | Chain name | | logoUrl | String | Chain logo URL | | shortName | String | Chain short name | | chainIndex| String | Chain unique identifier | ## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/pre-transaction/supported/chain' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "name": "Ethereum", "logoUrl": "http://www.eth.org/eth.png", "shortName": "ETH", "chainIndex": "1" } ], "msg": "" } ``` - [Get Gas Price](https://web3.okx.com/onchainos/dev-docs/trade/onchain-gateway-api-gas-price.md) {/* api-page */} # Get Gas Price Dynamically obtain estimated gas prices for various chains. ### Request URL GET `https://web3.okx.com/api/v6/dex/pre-transaction/gas-price` ## Request Parameters | Parameter | Type | Required | Description | |------------|--------|----------|-----------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). |
## Response Parameters ### EVM & Tron | Parameter | Type | Description | |------------------|---------|-----------------------------------| | normal | String | Medium gas price. For EVM, it is in wei. For Tron,it is in SUN | | min | String | Low gas price. For EVM, it is in wei. For Tron,it is in SUN | | max | String | High gas price. For EVM, it is in wei. For Tron,it is in SUN | | supporteip1559 | Boolean | Whether supports 1559 | | eip1559Protocol | Object | 1559 protocol | ### eip1559 Protocol | Parameter | Type | Description | |---------------------|--------|--------------------------------------| | eip1559Protocol | Object | Structure of 1559 protocol | | >suggestBaseFee | String | Suggested base fee = base fee * 1.25, in wei | | >baseFee | String | Base fee, in wei | | >proposePriorityFee | String | Medium priority fee, in wei | | >safePriorityFee | String | Low priority fee, in wei | | >fastPriorityFee | String | High priority fee, in wei | ### Solana | Parameter | Type | Description | |------------------|---------|-------------------| | priorityFee | String | Priority fee per compute unit. Only applicable to Solana | | >proposePriorityFee | String | Medium priority fee in microlamports.( it is also called Medium compute unit price ) 80th percentile| | >safePriorityFee | String | Low priority fee in microlamports.( it is also called Low compute unit price ) 60th percentile| | >fastPriorityFee | String | High priority fee in microlamports.( it is also called High compute unit price ) 95th percentile| | >extremePriorityFee | String | Extreme High priority fee in microlamports.( it is also called Extreme High compute unit price ) 99th percentile |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/pre-transaction/gas-price?chainIndex=1' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "normal" : "21289500000", // Medium gas price "min" : "15670000000", // Low gas price "max" : "29149000000", // High gas price "supportEip1559" : true, // Whether supports 1559 "eip1599Protocol": { "suggestBaseFee" : "15170000000", // Suggested base fee "baseFee" : "15170000000", // Base fee "proposePriorityFee" : "810000000", // Medium priority fee "safePriorityFee" : "500000000", // Low priority fee "fastPriorityFee" : "3360000000" // High priority fee }, "priorityFee":{} } ], "msg": "" } ```
- [Get Gas Limit](https://web3.okx.com/onchainos/dev-docs/trade/onchain-gateway-api-gas-limit.md) {/* api-page */} # Get Gas Limit Retrieve estimated Gas Limit consumption through pre-execution of transaction information. ### Request URL POST `https://web3.okx.com/api/v6/dex/pre-transaction/gas-limit` ## Request Parameters | Parameter | Type | Required | Description | |------------|--------|----------|-----------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). | | fromAddress| String | Yes | From address. For `transfer`,`Swap`, `Approve`, it is a wallet address | | toAddress | String | Yes | To address.
For `transfer`, it can be a token address or wallet address.
For `Swap`, it should be OKX DEX router address.
For `Approve`, it is a token address | | txAmount | String | No | Transaction amount. Default value: `0`.
1. For **Native token transactions** ( where the `fromToken` is native token. e.g., Ethereum), the txAmount can be set to the native token quantity, or retrieved from [/swap](./dex-swap) api(e.g., `txAmount = swapResponse.tx.value`).
2.For **non-native token transactions**, set `txAmount` to `0`.
The valle must use base unit of the native token, e.g., wei for ETH | | extJson | Object | No | Additional parameters for calldata and other information | extJson | Parameter | Type | Required | Description | |-----------|--------|----------|-------------| | inputData | String | No | Calldata |
## Response Parameters | Parameter | Type | Description | |-----------|--------|-------------------| | gasLimit | String | Estimated gas limit |
## Request Example ``` shell curl --location --request POST 'https://web3.okx.com/api/v6/dex/pre-transaction/gas-limit' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '{ "fromAddress": "0x383c8208b4711256753b70729ba0cf0cda55efad", "toAddress": "0x4ad041bbc6fa102394773c6d8f6d634320773af4", "txAmount": "31600000000000000", "chainIndex": "1", "extJson": { "inputData":"041bbc6fa102394773c6d8f6d634320773af4" } }' ``` ## Response Example ```json { "code": "0", "data": [ { "gasLimit": "652683" } ], "msg": "" } ```
- [Simulate Transactions](https://web3.okx.com/onchainos/dev-docs/trade/onchain-gateway-api-simulate-transaction.md) {/* api-page */} # Simulate Transactions Simulate a blockchain transaction before executing it to see the expected outcomes and potential risks.
Transaction simulate API is available to our whitelisted customers only. If you are interested, please contact us dexapi@okx.com. ### Request URL GET `https://web3.okx.com/api/v6/dex/pre-transaction/simulate` ## Request Parameters | Parameter | Type | Required | Description | |--------------|--------|----------|---------------------------------------------------------------------------------------| | fromAddress | String | Yes | Source address. For `Swap`, `Approve`, it is a wallet address | | toAddress | String | Yes | Destination address.
For `Swap`, it should be OKX DEX router address.
For `Approve`, it is a token address | | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum
See [Supported Chains](../home/supported-chain) for more.
It supports EVM、SOL、SUI, more chains will be supported soon. | | txAmount | String | No | Transaction amount. Default value: `0`.
1. For **Native token transactions** ( where the `fromToken` is native token. e.g., Ethereum), the txAmount can be set to the native token quantity, or retrieved from [/swap](./dex-swap) api(e.g., `txAmount = swapResponse.tx.value`).
2.For **non-native token transactions**, set `txAmount` to `0`.
The valle must use base unit of the native token, e.g., wei for ETH | | extJson | Object | Yes | Extended information object containing the following fields: | | > inputData | String | Yes | Call data for the transaction. The encoding rule require `base58`. | | priorityFee | String | No | Priority fee. Only applicable to Solana. | | gasPrice | String | No | Gas price for the transaction. |
## Response Parameters | Parameter | Type | Description | |--------------|--------|--------------------------------------------------------------------| | intention | String | Transaction purpose. Valid values: "Swap", "Token Approval" | | assetChange | Array | Details of asset changes resulting from the transaction | | > assetType | String | Asset type. Valid values: "NATIVE", "ERC20", "SPLTOKEN","SUITOKEN"| | > name | String | Asset name (e.g., "Ethereum") | | > symbol | String | Asset symbol (e.g., "ETH") | | > decimals | Number | Asset decimal precision | | > address | String | Asset contract address | | > imageUrl | String | URL to the asset's image | | > rawValue | String | Asset amount. Positive values indicate receiving assets, negative values indicate sending assets. | | gasUsed | String | Gas consumed by the transaction | | failReason | String | Human-friendly explanation if the transaction would fail | | risks | Array | Potential risks identified in the transaction | | > address | String | Address associated with the risk | | > addressType| String | Type of address. Valid values: "contract", "eoa" |
## Request Example ```shell curl --location --request POST 'https://web3.okx.com/api/v6/dex/pre-transaction/simulate' \ --header 'OK-ACCESS-KEY: your-access-key' \ --header 'OK-ACCESS-SIGN: your-access-sign' \ --header 'OK-ACCESS-PASSPHRASE: your-passphrase' \ --header 'OK-ACCESS-TIMESTAMP: 2025-05-19T10:00:00.000Z' \ --header 'Content-Type: application/json' \ --data-raw '{ "fromAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "toAddress": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", "chainIndex": "1", "txAmount": "0", "extJson": { "inputData": "0x38ed1739000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000000000000000000000000000000000000042ab52c000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000742d35cc6634c0532925a3b844bc454e4438f44e0000000000000000000000000000000000000000000000000000000064794b4b0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" }, "gasPrice": "12000000000" }' ``` ## Response Example ```json { "code": "0", "data": [ { "intention": "SWAP", "assetChange": [ { "assetType": "NATIVE", "name": "Ether", "symbol": "ETH", "decimals": 18, "address": "", "imageUrl": "", "rawValue": "-1000000000000000" }, { "assetType": "ERC20", "name": "USD Coin", "symbol": "USDC", "decimals": 6, "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "imageUrl": "", "rawValue": "1000000000000000" } ], "gasUsed": "180000", "failReason": "", "risks": [] } ], "msg": "success" } ```
- [Broadcast Transactions](https://web3.okx.com/onchainos/dev-docs/trade/onchain-gateway-api-broadcast-transaction.md) {/* api-page */} # Broadcast Transactions Broadcast transactions to the specified blockchain.
Your end-user's transaction can only be covered by the MEV protection feature if you actually utilise OKX Build's API services for that particular transaction. MEV protection is currently an experimental feature provided by third-parties and OKX Build does not guarantee the effectiveness and quality of such MEV protection. ### Request URL POST `https://web3.okx.com/api/v6/dex/pre-transaction/broadcast-transaction` ## Request Parameters | Parameter | Type | Required | Description | |------------ |-------- |----------|------------------------------------------------------------------------| | signedTx | String | Yes | The transaction string after being signed | | chainIndex | String | Yes | Unique identifier for the chain.
e.g., ETH=1.
See more [here](../home/supported-chain). | | address | String | Yes | Address. | | extraData | String | No | Additional parameters for calldata and other information | | > enableMevProtection | Boolean | No | Enable MEV protection. Not enabled by default. Valid values: `false`:not enabled, `true`:enabled
It supports only `ETH`、`BSC`、`SOL`、`BASE`, more chains will be supported soon. | | > jitoSignedTx | String | No | The transaction string after being signed that will send to Jito. The encoding rule require `base58`, applicable to `SOL`. For SOL, `signedTx` and `jitoSignedTx` must be passed at the same time |
## Response Parameters | Parameter | Type | Description | |-----------|--------|--------------------| | orderId | String | Unique transaction identifier | | txHash | String | Transaction Hash.
It supports only `ETH`、`BSC`、`SOL`、`BASE`, more chains will be supported soon. |
## Request Example ``` shell curl --location --request POST 'https://web3.okx.com/api/v6/dex/pre-transaction/broadcast-transaction' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '{ "signedTx":"0x08b47112567534ad041bbc6fa102394773c6d8f6d634320773af4da55efa", "address": "0x383c8208b4711256753b70729ba0cf0cda55efad", "chainIndex": "1", "extraData":"{\"enableMevProtection\":true,\"jitoSignedTx\":\"0x123456\"}" }' ``` ## Response Example ```json { "code": "0", "data": [ { "orderId": "0x383c8208b4711256753b70729ba0cf0cda55efad", "txHash": "0xd394f356a16b618ed839c66c935c9cccc5dde0af832ff9b468677eea38759db5" } ], "msg": "" } ```
- [Get Transaction Orders](https://web3.okx.com/onchainos/dev-docs/trade/onchain-gateway-api-orders.md) {/* api-page */} # Get Transaction Orders Get the list of orders sent from transaction broadcasting API. This supports querying transactions sorted in descending order by time. ### Request URL GET `https://web3.okx.com/api/v6/dex/post-transaction/orders` ## Request Parameters | Parameter | Type | Required | Description | |------------ |-------- |----------|----------------------------------------------------| | address | String | Yes | Address | | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). | | txStatus | String | No | Transaction status:
`1`: Pending
`2`: Success
`3`: Failed | | orderId | String | No | Unique identifier for the transaction order | | cursor | String | No | Cursor | | limit | String | No | Number of records returned, default is the most recent 20, maximum is 100 |
## Response Parameters | Parameter | Type | Description | |------------ |-------- |-----------------------------------------------------| | chainIndex | String | Unique identifier for the chain | | address | String | Address | | orderId | String | Order ID | | txStatus | String | Transaction status:
`1`: Pending
`2`: Success
`3`: Failed | | failReason | String | The reason for failed transaction | | txHash | String | Transaction hash |
## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/post-transaction/orders?address=0x238193be9e80e68eace3588b45d8cf4a7eae0fa3&chainIndex=1' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ``` json { "code": "0", "msg": "success", "data": [ { "cursor": "1", "orders":[ { "chainIndex": "1", "orderId": "016cf21d020be6c2f071dad9bbd8ec5cb9342fa8", "address": "0x238193be9e80e68eace3588b45d8cf4a7eae0fa3", "txHash": "0xb240e65dd9156b4a450be72f6c9fe41be6f72397025bb465b21a96ee9871a589", "failReason": "", "txstatus": "2" }, { "chainIndex": "1", "orderId": "592051a92a744627022955be929ecb5c9e777705", "address": "0x238193be9e80e68eace3588b45d8cf4a7eae0fa3", "txHash": "0xc401ffcd2a2b4b1db42ce68dfde8e63c0a1e9653484efb2873dbf5d0cbeb227a", "txstatus": "1", "failReason": "", } ] } ] } ```
- [Error Codes](https://web3.okx.com/onchainos/dev-docs/trade/onchain-gateway-error-code.md) # Error Codes | Code | HTTP status | Message | |-------|-------------|-----------------------------------------------------------------------------------------| | 50001 | 200 | Service temporarily unavailable. Try again later | | 81001 | 200 | Incorrect parameter | | 81108 | 200 | Wallet type does not match the required type | | 81104 | 200 | Chain not support | | 81152 | 200 | Coin not exist | | 81451 | 200 | node return failed | - [Use Widget](https://web3.okx.com/onchainos/dev-docs/trade/dex-widget.md) # Use Widget

Integrate the powerful OKX Widget into your product! With this widget, you can create an effective trading interface within 30 minutes.

## Install ```javaScript yarn add @okxweb3/dex-widget // or npm install @okxweb3/dex-widget // or pnpm add @okxweb3/dex-widget ``` ## Quickstart

Here is an example which shows how to use @okxweb3/dex-widget in a React project. You can find more examples through this [link](https://github.com/okx/dex-widget/tree/develop/packages/widget-configurator/src/react-cra).
Demo:https://okx.github.io/dex-widget/

```javaScript import React, { useRef, useEffect } from 'react'; import ReactDOM from 'react-dom/client'; import { createOkxSwapWidget } from '@okxweb3/dex-widget'; function App() { const widgetRef = useRef(); useEffect(() => { const params = { width: 375, providerType: 'EVM', }; const provider = window.ethereum; const listeners = [ { event: 'ON_CONNECT_WALLET', handler: () => { provider.enable(); }, }, ]; const instance = createOkxSwapWidget(widgetRef.current, { params, provider, listeners, }); return () => { instance.destroy(); }; }, []); return
; } const root = ReactDOM.createRoot(document.getElementById('root')); root.render( ); ``` ## Wallet Provider

You should pass the wallet provider information from your application if you want to connect a wallet. Then add the ON_CONNECT_WALLET event to seamlessly use the widget as part of your application.

- If it’s on Ethereum or other EVM networks, the provider must comply with EIP-1193 to implement the interface. - If it’s on Solana, the provider must pass the wallet provider information from your application. ```typeScript import { createOkxSwapWidget, ProviderType } from '@okxweb3/dex-widget'; const widgetEthInstance = createOkxSwapWidget( document.getElementById('widget'), { params: { providerType: ProviderType.EVM, }, provider: window.ethereum, // e.g. window.okexchain } ); const widgetSolanaInstance = createOkxSwapWidget( document.getElementById('widget'), { params: { providerType: ProviderType.SOLANA, }, provider: window.solana, // window.okexchain.solana } ); ```

You can check out this [link](https://github.com/okx/dex-widget/blob/faf69c76b90268f2352507c9a90fb37bb80fdbc7/example/widget-demo/src/main.tsx#L22)。 for an example of using the Rainbow kit to connect to a wallet.

## Params

The following sheet contains the descriptions of the params.

| Parameter | Type | Default | Description | | -------------- | --------------- | ------- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `width` | `number` | 450 | The width of the widget in css values (px). If the width is not set, the display style for the width will be: 450px when the screen width > 767px. 100% when the screen width < 768px. 375px when the screen width < 375px. | | `theme` | `THEME` | light | The swap widget provides a default light theme and a dark theme as options. You can change the theme of the widget by following the example below. | | `lang` | `string` | en_us | The widget language is adjustable. Check the Multilanguage section for more details. | | `tradeType` | `TradeType` | auto | The type of transaction. It can be “swap”, “bridge”, or “auto”.Note: “Auto” includes “swap” and “bridge”. | | `chainIds` | `Array` | [] | The ID of the blockchain on which the single-chain swap will take place. Check the ChainId config section for all the networks that you can choose from. | | `tokenPair` | `ITokenPair` | {} | The default token pair you have set for Swap, can be found in the default tokenPair configuration section for more details. | | `bridgeTokenPair` | `ITokenPair` | {} | The default token pair you have set for Bridge, can be found in the default tokenPair configuration section for more details. | | `providerType` | `ProviderType` | ' ' | ProviderType represents the type of the provider and corresponds to it one-to-one. For example, if the provider is Solana, then the providerType would be SOLANA. | | `defaultTab` | `TradeTab ` | 'swap' | Default open mode can be set to single-chain or cross-chain. Supported from version 1.3.16 and above. | | `walletName` | `string` | ' ' | Name of the connected wallet. This parameter helps the DEX widget continuously improve its products and services to provide a better user experience. Supported from version 1.3.16 and above. | ## Type Description ```typeScript interface ITokenPair { fromChain: string | number; toChain: string | number; fromToken?: string; toToken?: string; } enum ProviderType { EVM = 'EVM', SOLANA = 'SOLANA', WALLET_CONNECT = 'WALLET_CONNECT', } enum TradeType { SWAP = 'swap', BRIDGE = 'bridge', AUTO = 'auto', } enum THEME { LIGHT = 'light', DARK = 'dark', } ``` ## Multilanguage | lang | Description | | -------- | ----------------------- | | `en_us` | English,Default | | `zh_cn` | 简体中文 | | `zh_tw` | 繁體中文 | | `fr_fr` | Français (Afrique) | | `id_id` | Bahasa Indonesia | | `ru_ru` | Русский | | `tr_tr` | Türkçe | | `vi_vn` | Tiếng Việt | | `de_de` | Deutsch | | `it_it` | Italiano | | `pl_pl` | Polski | | `pt_pt` | Português (Portugal) | | `es_es` | Español (España) | | `pt_br` | Português (Brasil) | | `es_419` | Español (Latinoamérica) | | `cs_cz` | Čeština | | `ro_ro` | Română | | `uk_ua` | Українська | | `ar_eh` | العربية | | `nl_nl` | Nederlands | ## ChainId Config | Network | ChainId | Native token contract | | ----------- | ------- | ------------------------------------------ | | Ethereum | 1 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | zkSync Era | 324 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Optimism | 10 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Polygon | 137 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Avalanche C | 43114 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Arbitrum | 42161 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Linea | 59144 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Base | 8453 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Mantle | 5000 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Scroll | 534352 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | X Layer | 196 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Blast | 81457 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | BNB Chain | 56 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Solana | 501 | 11111111111111111111111111111111 | ## Default tokenPair Config

`tokenPair`: If tokenPair not configured, the default network for single-chain swaps is set to Ethereum, with ETH as `fromToken` and USDC as `toToken`.

`bridgeTokenPair`: If bridgeTokenPair not configured, the default bridge transaction is set to one from Ethereum to BNB Chain, with ETH as `fromToken` and BNB as `toToken`.

```javaScript import React, { useEffect, useRef } from 'react'; import { OkxSwapWidgetParams, ProviderType, TradeType, } from '@okxweb3/dex-widget'; const provider = window.ethereum; export function EvmWidget() { const widgetRef = useRef(); const params = { chainIds: ['1', '10'], lang: 'zh_cn', providerType: ProviderType.EVM, theme: 'dark', tradeType: TradeType.AUTO, tokenPair: { fromChain: 1, //ETH toChain: 1, // ETH fromToken: '0xdac17f958d2ee523a2206206994597c13d831ec7', // USDT toToken: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // ETH }, bridgeTokenPair: { fromChain: 1, //ETH toChain: 56, // BNB fromToken: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // ETH toToken: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // BNB }, }; const initialConfig = { params, provider, listeners: [ { event: 'ON_CONNECT_WALLET', handler: (token, preToken) => { provider.enable(); }, }, ], }; useEffect(() => { const widgetHandler = createOkxSwapWidget(widgetRef.current, initialConfig); return () => { widgetHandler?.destroy(); }; }, []); return
; } ``` | Parameter | Type | Description | | --------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | fromChain | String | The ID of the source network that the fromToken belongs to (e.g., 1: Ethereum. Check ChainId config for a full list of the supported networks and the corresponding chain IDs). | | fromToken | String | The contract address of the token to be sold. E.g., ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE. If the fromToken is a blockchain’s native token, check the chain ID to get the contract address. | | toChain | String | The ID of the destination network that the toToken belongs to (e.g., 1: Ethereum. Check ChainId config for a full list of the supported networks and the corresponding chain IDs). | | toToken | String | "The contract address of a token to be bought. E.g., USDC: 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48. If the toToken is a blockchain’s native token, check the chain ID to get the contract address." | ### updateProvider

The widget supports EVM and Solana. When switching from EVM to Solana, remember to update the corresponding widget’s provider, and vice versa.
If you don’t pass in provider information for the first rendering and want the widget to respond to a wallet connection, you need to call updateProvider. Updating the provider can also include the `walletName` parameter to identify the plugin wallet connected by the user.

```javaScript // 3. Update the provider if the user connects a different wallet, EVM => SOLANA const walletName = 'phantom'; widgetHandler.updateProvider(window.solana, ProviderType.SOLANA, walletName); // SOLANA => EVM // widgetHandler.updateProvider(window.ethereum, ProviderType.EVM); ``` ### updateListeners

You can update the events that the widget listens to.

```javaScript // 4. Modify event listeners to handle new types of events widgetHandler.updateListeners([ { event: OkxEvents.ON_FROM_CHAIN_CHANGE, handler: (payload) => { // }, }, ]); ``` - Listeners mainly listen to the interfaces exposed externally by the widget, enabling customized processing through various events. The updateListeners function is used to modify custom processing after switching chains. - By adding event listeners, you can capture and handle data passed out from the iframe. This data usually represents events or state changes happening within the iframe and is passed to the external page through events. - The received data can be processed and manipulated flexibly according to your needs. This allows you to implement different logic or update UI elements based on the type or content of the data passed. - With the updateListeners method, you can add handlers for different types of events, such as OkxEvents.ON_TOKEN_CHANGE. When the event is triggered, the handler will receive the relevant payload data for further processing. ### destroy

Call this method when removing the widget module.

```javascript const widgetHandler = createOkxSwapWidget(container, initialConfig); widgetHandler.destory(); ``` #### Note: - Whenever you refresh or update, make sure to call the destroy method to remove previously connected events in order to prevent duplicate requests. ## Event Listeners

Widget provides event listeners for ON_CONNECT_WALLET and ON_FROM_CHAIN_CHANGE.

- `ON_CONNECT_WALLET`: This event is triggered when the widget is not connected to a wallet and the connect wallet button is clicked. - `ON_FROM_CHAIN_CHANGE`: This event is triggered when fromChain changes. - `ON_SUBMIT_TX`: This event is triggered after the transaction is completed and returns the `txHash` and `chainId`. Supported from version 1.3.16 and above.

Here’s how to use them:

```typeScript import {createOkxSwapWidget, OkxSwapWidgetParams, OkxEventListeners, OkxEvents} from '@okxweb3/dex-widget' const params: OkxSwapWidgetParams = { // ... } const listeners: OkxEventListeners = [ { event: OkxEvents.ON_CONNECT_WALLET, handler: () => { // open connect wallet method, eg openConnectModal of the rainbow kit. window.ethereum.enable() } }, { event: OkxEvents.ON_FROM_CHAIN_CHANGE, handler: (token) => { // } }, { event: OkxEvents.ON_SUBMIT_TX, handler: (res) => { console.log(`Transaction submitted successfully, txHash: ${res.data.txHash}`); } }, ] const { updateListeners } = createOkxSwapWidget(container, { params, listeners, provider }) ``` - [API Fee](https://web3.okx.com/onchainos/dev-docs/trade/api-fee.md) # API Fee Our API provides integration partners with various API tiers and flexible methodology to add fees to each transaction, designed to support various stages of development and commercialization. As our integration partner, you can access the API with a few different tiers to meet your specific needs. With the DEX API module, you can earn revenue by setting your own partner fee scheme to charge your users per swap. In detail, integration partners can configure partner fee and fee-receiving address for each token swap. You can charge your users up to 3% per swap for most supported chains; while for Solana, you can charge up to 10% per swap. All tiers of the API are subject to the [User agreement](https://web3.okx.com/help/okx-web3-build-user-agreement). ## Trial API Tier Our API offers a Trial tier that includes access to selected API functions. To start using the trial plan, you need to create an account on the [Developer Portal](./developer-portal) and verify your email and phone number. This plan provides a default rate limit of 1 request per second (RPS) and can be increased to 5 RPS upon review and approval. The trial tier is valid for 60 days upon the API key creation. For the trial tier, when the DEX API module secures a better price than quoted infrequently, the additional value named positive slippage is kept as our infrastructure fee. The positive slippage is capped at 10% of the trade amount. ## Start-up API Tier To continue using the API after the 60-day trial period, you can upgrade your developer account to the Start-up tier on the [Developer Portal](./developer-portal). Once upgraded to the Start-up tier, you immediately have access to additional product features, much higher RPS, standard technical and growth support. For start-up tier partners charging partner fee in token swaps, a standard revenue-sharing agreement is entered to retain 20% of your revenue as our infrastructure fee. In such cases, the positive slippage (if happened) is returned to your users by default; however, you can apply to have access to the feature to keep a portion of the positive slippage as your revenue. If you do not configure partner fees in token swaps to make revenue, we will keep the positive slippage (if happened) as our infrastructure fee, capped at 10% of the trade value. ## Enterprise API Tier For high-volume partners who need a much higher RPS, customized fee structure, dedicated technical and growth support, access to additional product features or customized features, you can upgrade to the Enterprise tier by contacting our BD team and signing a contract with us. Furthermore, Enterprise partners have access to the feature to keep the positive slippage as your revenue or provide the positive slippage entirely to your users. ## Need Help? If you need to increase your rate limit, upgrade to the Start-up tier or Enterprise tier, or have product-related queries, please join our [discord](https://discord.com/invite/okxdexapi), or contact our BD team directly at dexapi@okx.com ## API Tiers Summary | | Trial Tier | Start-up Tier | Enterprise Tier | |--------------------- |-------------------------------------------------------------------------------------------------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | API fee | Positive slippage only | 20% rev-share, or positive slippage if no partner fee is configured | Customized fee structure | | Features & Benefits | • RPS 1-5
• Access to standard API endpoints
• Valid for 60 days
| • RPS 2-50
• Access to most advanced API endpoints
• Access to positive slippage feature to retain as extra revenue (upon approval)
• Receive standard tech and growth support
| • Customised RPS
• Access to all advanced API endpoints, including positive slippage feature to retain as extra revenue
• Request customized feature development (upon approval)
• Receive dedicated tech and growth support
| *RPS adjustment is correlated to trading volume
*Positive slippage refers to a situation where a trade is executed at a more favorable price than initially quoted, which is relatively rare. For selected API tiers, the additional value generated by positive slippage will be retained as an API fee, capped at no more than 10% of the total traded amount.
*Start-up customers with monthly trading volume exceeding $10M need to contact our BD to upgrade to Enterprise tier for customized support
- [Smart Contract Safety](https://web3.okx.com/onchainos/dev-docs/trade/smart-contract-safety.md) # Smart Contract Safety ## Bug Bounty Program Security is our paramount priority. To learn about the security programs at OKX Web3, please visit our [website](https://web3.okx.com/security). We also have bug bounty programs to reward ethical hackers and our community to report bugs or security vulnerabilities to our product.
Submit a bug report: https://hackerone.com/okg ## Open Source Smart Contract We have open-sourced our smart contract codes on github, inviting community oversight. - Solana Chain Contract Repository https://github.com/okxlabs/DEX-Router-Solana-V1 - EVM Chain Contract Repository https://github.com/okxlabs/DEX-Router-EVM-V1 ## Join Community Discussions Join our [Discord community](https://discord.gg/okxdexapi) to share your experience with our DEX router and help other developers troubleshoot their integration issues. Our [Discord](https://discord.gg/okxdexapi) is the main hub for announcements, community interactions, technical discussion and 24/7 technical support. - [Market API](https://web3.okx.com/onchainos/dev-docs/market/market-api-introduction.md) # Market API Our Market API is a suite of high-performance Restful JSON endpoints and real-time websocket channels to provide comprehensive multi-market and onchain data for cryptocurrency tokens, trades, transactions, accounts and more, pulling information from hundreds of decentralized exchanges (DEX) and centralized exchanges (CEX) across different blockchain ecosystems. Developers can utilize the Market API and the Trade API to build complete DEX experience with insightful market and portfolio dashboards, allowing users to monitor token performance across different exchange types in real-time, analyze portfolio changes and identify trading opportunities. - [Build with AI](https://web3.okx.com/onchainos/dev-docs/market/market-ai-tools-introduction.md) # Build with AI Onchain OS Market give agents and developers a unified data layer for real-time on-chain intelligence, token prices, trading activity, candlestick charts, token discovery, wallet balances, and transaction history , all from a single integration. Use it as the research and monitoring layer that runs alongside trade execution, or independently for portfolio dashboards and opportunity detection. ## Why Onchain OS Market for AI - **Dual-source price aggregation**. Market Price data is aggregated in real time from both on-chain DEX activity and centralized exchange feeds, giving a more complete picture of a token's true market price than any single-venue source. For agents that need a manipulation-resistant reference , stop-loss thresholds, risk parameters, multi-step trade validation, the Index Price API computes a stable composite price from multiple independent third-party sources (CEX, DEX, oracles), specifically designed to resist single-venue distortion. - **Token intelligence from discovery to depth**. The Token API is a full information stack: search by name, symbol, or contract address; retrieve basic metadata (decimals, contract); pull live trading metrics (24h volume, market cap, circulating supply, holders, liquidity); surface trending tokens by price change, volume, or market cap; and inspect the top 20 holder addresses for concentration analysis. An Agent can go from a user's natural language question ("what's trending on Ethereum today?") to a structured, actionable answer without leaving the tool. - **Complete portfolio visibility in one call**. The Balance API queries token balances and total USD portfolio value across all supported chains simultaneously , no need to iterate per chain. This is designed for agents that manage multi-chain portfolios or need to verify sufficient balance before executing a swap. - **Candlestick history for analysis and backtesting**. The Market Price API provides OHLCV data from minute-level to daily candles, with a historical endpoint that extends the lookback window for trend analysis, pattern detection, and strategy backtesting. - **Agent-optimized interface Skill and MCP Server**. OKX Market provides two integration paths depending on how your Agent is deployed. The Skill teaches your Agent how to call the OKX Web3 Market API through structured instructions and code generation. The MCP Server exposes the same capabilities as directly callable tools via the Model Context Protocol. ## Quickstart Add the Skill files to the Agent’s `skill` directory. The Agent will automatically load the intent router, chain-specific execution playbooks, signing modes, and error-handling logic. ```shell npx skills add okx/onchainos-skills ``` For more details, please refer to the [GitHub repository](https://github.com/okx/onchainos-skills). For Claude Desktop, Cursor, and other MCP-compatible clients, add the following configuration: **for General Claude code** ```shell claude mcp add onchainos-mcp https://web3.okx.com/api/v1/onchainos-mcp -t http -H"OK-ACCESS-KEY: d573a84c-8e79-4a35-b0c6-427e9ad2478d" ``` **for Claude Desktop Installation** 1. Go to the `Settings` page and locate the `Connector` menu. 2. Scroll to the bottom, find `Add custom connector`, and enter the URL: https://web3.okx.com/api/v1/onchainos-mcp You can also try a local installation. For detailed instructions, please consult your Claude client. **for Claude code MCP settings** ```shell claude mcp add-json onchainos-mcp '{ "type": "http", "url": "https://web3.okx.com/api/v1/onchainos-mcp", "headers": { "OK-ACCESS-KEY": "d573a84c-8e79-4a35-b0c6-427e9ad2478d" } }' ``` One MCP server covers both Market and Trade capabilities. Restart your client after updating the config. - [Skills](https://web3.okx.com/onchainos/dev-docs/market/market-ai-tools-skills.md) # Skills Beyond simply "retrieving documentation," Skills encapsulate domain knowledge and engineering workflows into stable capabilities. They enable the Agent not only to answer "how to write the docs," but also to handle "which endpoint to choose, what the next step is, and how to deal with errors." ## Why Onchain OS Market Skills for AI - Covers the full Market data lifecycle , price lookup, token discovery, candlestick retrieval, balance queries, and trade history. - Provides an Intent Router: maps user questions ("what's ETH's price?", "who holds the most USDT?", "show me SOL's 4h chart") to the correct API family and the appropriate first action. - Plug-and-play for AI agents: Structured capability modules that directly encapsulate the OKX DEX API for AI Agents. Each Skill corresponds to a specific capability (e.g., filtering trending tokens by price change, trading volume, or market cap; retrieving real-time trading metrics; analyzing address concentration) and defines clear input/output schemas, enabling seamless integration into any Agent architecture. ## Quickstart ```shell npx skills add okx/onchainos-skills ``` For more details, please refer to the [GitHub repository](https://github.com/okx/onchainos-skills). ## Example interactions Once the Skills is uploaded to agents, an Agent can respond to natural-language queries like: ```shell What is the current price of OKB? # Call index-current-price ``` ```shell Show me OKB’s 4-hour candlesticks for the past week. # Call market-candlesticks ``` ```shell What is the hottest token on the X-layer chain right now? # Call market-token-ranking ``` ```shell Which address holds the most USDT on X-layer? # Call market-token-holder ``` ```shell What is the total asset value of wallet 0xd8dA...? # Call balance-total-value ``` - [MCP Server](https://web3.okx.com/onchainos/dev-docs/market/market-ai-tools-mcp-server.md) # MCP Server MCP (Model Context Protocol) connects AI tools with developer resources. After adding the OKX DEX MCP Server, the Agent can query live token prices, retrieve candlestick charts, search for tokens, inspect holder distributions, and check wallet balances all through standardized, directly callable tool interfaces, within a single conversation or editor session, without any additional integration code. For Claude Desktop, Cursor, and other MCP-compatible clients, add the following configuration: One MCP server covers both Market and Trade capabilities. Restart your client after updating the config. ## What the MCP Server exposes - **Price Tools:** `dex-okx-index-current-price`, `dex-okx-index-historical-price`, `dex-okx-market-price`, `dex-okx-market-price-chains` — real-time and historical index/DEX prices across 20+ chains. - **Candlestick Tools:** `dex-okx-market-candlesticks`, `dex-okx-market-candlesticks-history` — OHLCV data from 1-minute to daily intervals, with support for extended lookback windows. - **Token Intelligence Tools:** `dex-okx-market-token-search`, `dex-okx-market-token-price-info`, `dex-okx-market-token-ranking`, `dex-okx-market-token-holder` — token discovery, metadata, real-time metrics, and holder concentration analysis. - **Trade Data Tool:** `dex-okx-market-trades` — latest on-chain trade records for any token. - **Balance Tools:** `dex-okx-balance-chains`, `dex-okx-balance-total-token-balances`, `dex-okx-balance-specific-token-balance`, `dex-okx-balance-total-value` — multi-chain wallet balances and USD portfolio valuation. ## Quickstart **for General Claude code** ```shell claude mcp add onchainos-mcp https://web3.okx.com/api/v1/onchainos-mcp -t http -H"OK-ACCESS-KEY: d573a84c-8e79-4a35-b0c6-427e9ad2478d" ``` **for Claude Desktop Installation** 1. Go to the `Settings` page and locate the `Connector` menu. 2. Scroll to the bottom, find `Add custom connector`, and enter the URL: https://web3.okx.com/api/v1/onchainos-mcp You can also try a local installation. For detailed instructions, please consult your Claude client. **for Claude code MCP setting** ```shell claude mcp add-json onchainos-mcp '{ "type": "http", "url": "https://web3.okx.com/api/v1/onchainos-mcp", "headers": { "OK-ACCESS-KEY": "d573a84c-8e79-4a35-b0c6-427e9ad2478d" } }' ``` ## Example interactions Once the MCP Server is active, an Agent can respond to natural-language queries like: ```shell What is the current price of OKB? # Call index-current-price ``` ```shell Show me OKB’s 4-hour candlesticks for the past week. # Call market-candlesticks ``` ```shell What is the hottest token on the X-layer chain right now? # Call market-token-ranking ``` ```shell Which address holds the most USDT on X-layer? # Call market-token-holder ``` ```shell What is the total asset value of wallet 0xd8dA...? # Call balance-total-value ``` - [llms.txt](https://web3.okx.com/onchainos/dev-docs/market/market-ai-tools-llm.md) # llms.txt ## Onchain OS Market llms.txt Structure `llms.txt` is a proposed standard designed to help AI language models efficiently understand and navigate documentation or websites. It enables Agents to quickly grasp the structure of documentation and locate relevant pages. Based on minimal context, it can precisely identify the appropriate module within shorter response times, reduce hallucinations, and lower token consumption—serving as a low-cost navigation layer. A typical `llms.txt` file includes: - Site title (H1) - Sections organized by module (H2) - A link to each page + a one-sentence description (used for routing and retrieval) In addition to `llms.txt`, we also provide `llms-full.txt`. Unlike a directory-style index, it aggregates the full site documentation in Markdown format (including more granular descriptions and examples) for deeper indexing and search. Please visit [OnchainOS.llms.txt](https://web3.okx.com/llms.txt) to view the detailed structure of `llms.txt`. ## Onchain OS Market llms-full.txt Structure Suitable for: - AI tools that require full-context access (deep indexing / advanced search / offline knowledge base construction) - Developers who want a comprehensive view of all pages and resources at once - Building custom AI workflows (e.g., full indexing first, then chunk-based retrieval as needed) Please visit [OnchainOS.llms-full.txt](https://web3.okx.com/llms-full.txt) to view the detailed structure of `llms-full.txt`. - [API Reference](https://web3.okx.com/onchainos/dev-docs/market/market-price-reference.md) # API Reference - [Get supported chains](https://web3.okx.com/onchainos/dev-docs/market/market-price-chains.md) {/* api-page */} # Get supported chains Retrieve information on chains supported by Market Price API. ### Request URL GET `https://web3.okx.com/api/v6/dex/market/supported/chain` ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | No | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). |
## Response Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Unique identifier for the chain | | chainName | String | Chain name (e.g.,`Optimism`) | | chainLogoUrl | String | Chain icon | | chainSymbol | String | Chain symbol (e.g., ETH). |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/supported/chain?chainIndex=1' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code":"0", "data":[ { "chainIndex":"1", "chainName":"Ethereum", "chainSymbol":"ETH" }, ], "msg":"" } ```
- [Get Price](https://web3.okx.com/onchainos/dev-docs/market/market-price.md) {/* api-page */} # Get Price Retrieve the latest price of a token. ### Request URL POST `https://web3.okx.com/api/v6/dex/market/price` ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). | | tokenContractAddress | String | Yes | Token contract address,for EVM please pass all-lowercase addresses (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) |
## Response Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | chainIndex | String| Unique identifier for the chain | | tokenContractAddress | String | Token contract address | | time | String | Timestamp of the price, Unix timestamp format in milliseconds | | price | String | Latest token price |
## Request Example ```shell curl --location --request POST 'https://web3.okx.com/api/v6/dex/market/price' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '[ { "chainIndex": "66", "tokenContractAddress":"0x382bb369d343125bfb2117af9c149795c6c65c50" } ]' ``` ## Response Example ```json { "code":"0", "data":[ { "chainIndex": "1", "tokenContractAddress": "0x382bb369d343125bfb2117af9c149795c6c65c50", "time": "1716892020000", "price": "26.458143090226812" } ], "msg":"" } ```
- [Get Candlesticks](https://web3.okx.com/onchainos/dev-docs/market/market-candlesticks.md) {/* api-page */} # Get Candlesticks Retrieve the candlestick charts. This endpoint can retrieve the latest 1,440 data entries. Charts are returned in groups based on the requested bar. ### Request URL GET `https://web3.okx.com/api/v6/dex/market/candles` ## Request Parameters | Parameter | Type | Required | Description | | -------------------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). | | tokenContractAddress | String | Yes | Token contract address,for EVM please pass all-lowercase addresses (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | after | String | No | Pagination of data to return records earlier than the requested ts. | | before | String | No | Pagination of data to return records newer than the requested ts. The latest data will be returned when using before individually | | bar | String | No | Bar size, the default is 1m
e.g. [1s/1m/3m/5m/15m/30m/1H/2H/4H]
Hong Kong time opening price k-line:[6H/12H/1D/1W/1M/3M]
UTC time opening price k-line:[/6Hutc/12Hutc/1Dutc/1Wutc/1Mutc/3Mutc] | | limit | String | No | Number of results per request. The maximum is 299. The default is 100. |
## Response Parameters | Parameter | Type | Description | | --------- | ------ | ---------------------------------------------------------------------------------------------------- | | ts | String | Opening time of the candlestick, Unix timestamp format in milliseconds, e.g. 1597026383085 | | o | String | Open price | | h | String | Highest price | | l | String | Lowest price | | c | String | Close price | | vol | String | Trading volume, with a unit of base currency. | | volUsd | String | Trading volume, with a unit of usd. | | confirm | String | The state of candlesticks.
`0` represents that it is uncompleted, `1` represents that it is completed. | The first candlestick data may be incomplete, and should not be polled repeatedly. The data returned will be arranged in an array like this: [ts,o,h,l,c,vol,volUsd,confirm]. Use the closing price of the last candle as the opening price of the following candle.
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/candles?chainIndex=66&tokenContractAddress=0x382bb369d343125bfb2117af9c149795c6c65c50' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ [ "1597026383085", "3.721", "3.743", "3.677", "3.708", "22698348.04828491", "226348.0482", "0" ], [ "1597026383085", "3.731", "3.799", "3.494", "3.72", "67632347.24399722", "6767.2439", "1" ] ], "msg": "" } ```
- [Get Candlesticks History](https://web3.okx.com/onchainos/dev-docs/market/market-candlesticks-history.md) {/* api-page */} # Get Candlesticks History Retrieve historical candlestick charts. Historical candlestick data does not include unfinished candlesticks ### Request URL GET `https://web3.okx.com/api/v6/dex/market/historical-candles` ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). | | tokenContractAddress | String | Yes | Token contract address ,for EVM please pass all-lowercase addresses(e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | after | String | No | Pagination of data to return records earlier than the requested ts. | | before | String | No | Pagination of data to return records newer than the requested ts. The latest data will be returned when using before individually | | bar | String | No | Bar size, the default is 1m
e.g. [1s/1m/3m/5m/15m/30m/1H/2H/4H]
Hong Kong time opening price k-line:[6H/12H/1D/1W/1M/3M]
UTC time opening price k-line:[/6Hutc/12Hutc/1Dutc/1Wutc/1Mutc/3Mutc] | | limit | String | No | Number of results per request. The maximum is 299. The default is 100. |
## Response Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | ts | String | Opening time of the candlestick, Unix timestamp format in milliseconds, e.g. 1597026383085 | | o | String | Open price | | h | String | Highest price | | l | String | Lowest price | | c | String | Close price | | vol | String | Trading volume, with a unit of base currency. | | volUsd | String | Trading volume, with a unit of usd. | | confirm | String | The state of candlesticks.
`0` represents that it is uncompleted, `1` represents that it is completed. | The first candlestick data may be incomplete, and should not be polled repeatedly. The data returned will be arranged in an array like this: [ts,o,h,l,c,vol,volUsd,confirm]. Use the closing price of the last candle as the opening price of the following candle.
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/historical-candles?chainIndex=66&tokenContractAddress=0x382bb369d343125bfb2117af9c149795c6c65c50' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code":"0", "data":[ [ "1597026383085", "3.721", "3.743", "3.677", "3.708", "22698348.04828491", "226348.0482", "0" ], [ "1597026383085", "3.731", "3.799", "3.494", "3.72", "67632347.24399722", "6767.2439", "1" ] ], "msg":"" } ```
- [Error Codes](https://web3.okx.com/onchainos/dev-docs/market/market-price-error-code.md) # Error Codes | Code | HTTP status | Message | |-------|-------------|-----------------------------------------------------------------------------------------| | 0 | 200 | Succeeded | | 50011 | 429 | Rate limit reached. Please refer to API documentation and throttle requests accordingly | | 50014 | 400 | Parameter \{param0\} cannot be empty | | 50026 | 500 | System error. Try again later | | 50103 | 401 | Request header "OK-ACCESS-KEY" cannot be empty | | 50104 | 401 | Request header "OK-ACCESS-PASSPHRASE" cannot be empty| | 50105 | 401 | Request header "OK-ACCESS-PASSPHRASE" incorrect | | 50106 | 401 | Request header "OK-ACCESS-SIGN" cannot be empty | | 50107 | 401 | Request header "OK-ACCESS-TIMESTAMP" cannot be empty | | 50111 | 401 | Invalid OK-ACCESS-KEY | | 50112 | 401 | Invalid OK-ACCESS-TIMESTAMP | | 50113 | 401 | Invalid signature | | 51000 | 400 | Parameter \{param0\} error | - [Websocket](https://web3.okx.com/onchainos/dev-docs/market/websocket.md) # Websocket WebSocket is a new HTML5 protocol that achieves full-duplex data transmission between the client and server, allowing data to be transferred effectively in both directions. A connection between the client and server can be established with just one handshake. The server will then be able to push data to the client according to preset rules. Its advantages include: - The WebSocket request header size for data transmission between client and server is only 2 bytes. - Either the client or server can initiate data transmission. - There's no need to repeatedly create and delete TCP connections, saving resources on bandwidth and server. ## Connect **Connection limit**: 3 requests per second (based on API KEY)
When subscribing to a private channel, use the address of the private service **Request limit** The total number of 'subscribe'/'unsubscribe'/'login' requests per connection is limited to 480 times per hour. If there’s a network problem, the system will automatically disable the connection. The connection will break automatically if the subscription is not established or data has not been pushed for more than 30 seconds. To keep the connection stable: 1. Set a timer of N seconds whenever a response message is received, where N is less than 30. 2. If the timer is triggered, which means that no new message is received within N seconds, send the String 'ping'. 3. Expect a 'pong' as a response. If the response message is not received within N seconds, please raise an error or reconnect. ## Notification WebSocket has introduced a new message type (event = notice). Client will receive the information in the following scenarios: - Websocket disconnect for service upgrade 30 seconds prior to the upgrade of the WebSocket service, the notification message will be sent to users indicating that the connection will soon be disconnected. Users are encouraged to establish a new connection to prevent any disruptions caused by disconnection. Response Example ```json { "event": "notice", "code": "64008", "msg": "The connection will soon be closed for a service upgrade. Please reconnect.", "connId": "a4d3ae55" } ``` - [Login](https://web3.okx.com/onchainos/dev-docs/market/websocket-login.md) {/* api-page */} # Login ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | op | String | Yes | Operation, `login` | | args | Array | Yes | List of subscribed channels | | > apiKey | String | Yes | API Key | | > passphrase | String | Yes | API Key password | | > timestamp | String | Yes | Unix Epoch time, the unit is seconds | | > sign | String | Yes | Signature string | ## Response Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | event | String | Operation.`login` or `error` | | code | String | Error code | | msg | String | Error message | | connId | String | WebSocket connection ID |

**apiKey**: Unique identification for invoking API. Requires users to apply one manually in the [developer portal](https://web3.okx.com/zh-hans/build/dev-portal).
**passphrase**: API Key password
**timestamp**: the Unix Epoch time, the unit is seconds, e.g. 1704876947
**sign**: signature string, the signature algorithm is as follows: First concatenate timestamp, method, requestPath, strings, then use HMAC SHA256 method to encrypt the concatenated string with SecretKey, and then perform Base64 encoding.
**secretKey**: The security key generated when the user applies for API Key, e.g. : 22582BD0CFF14C41EDBF1AB98506286D
**Example of timestamp**: const timestamp = '' + Date.now() / 1,000
**Among sign example**: sign=CryptoJS.enc.Base64.stringify(CryptoJS.HmacSHA256(timestamp +'GET'+'/users/self/verify', secretKey))
**method**: always 'GET'.
**requestPath**: always '/users/self/verify'

The request will expire 30 seconds after the timestamp. If your server time differs from the API server time, we recommend using the REST API to query the API server time and then set the timestamp.
## Request Example ```json { "op": "login", "args": [{ "apiKey": "985d5b66-57ce-40fb-b714-afc0b9787083", "passphrase": "123456", "timestamp": "1538054050", "sign": "7L+zFQ+CEgGu5rzCj4+BdV2/uUHGqddA9pI6ztsRRPs=" }] } ``` ## Response Example Successful Response Example ```json { "event": "login", "code": "0", "msg": "", "connId": "a4d3ae55" } ``` Failure Response Example ```json { "event": "error", "code": "60009", "msg": "Login failed.", "connId": "a4d3ae55" } ```
- [Subscribe](https://web3.okx.com/onchainos/dev-docs/market/websocket-subscribe.md) {/* api-page */} # Subscribe

Users can choose to subscribe to one or more channels, with the total length of all channels not exceeding 64 KB. Price channels and trading channels require authentication before subscription. K-line (candlestick) channels do not require authentication. Below is an example of request parameters. Each channel has different parameter requirements, so please subscribe according to the specific requirements of each channel.

## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | op | String | Yes | Operation, `subscribe` | | args | Array | Yes | List of subscribed channels | | > channel | String | Yes | Channel name | | > chainIndex | String | Yes | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](../home/supported-chain)) | | > timestamp | String | Yes | Unix Epoch time, the unit is seconds | | > tokenContractAddress | String | Yes | Token contract address,for EVM please pass all-lowercase addresses (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | ## Response Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | event | String | Operation.`subscribe` or `error` | | arg | String | Subscribed channel | | > channel | String | Channel name | | > chainIndex | String | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](../home/supported-chain)) | | > tokenContractAddress | String | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | code | String | Error code | | msg | String | Error message | | connId | String | WebSocket connection ID | Request format description ```json {"op": "subscribe","args": ["SubscriptionTopic"]} ```
## Request Example ```json { "op": "subscribe", "args": [{ "channel": "price", "chainIndex": "1", "tokenContractAddress": "0x382bb369d343125bfb2117af9c149795c6c65c50" }] } ``` ## Response Example ```json { "event": "subscribe", "arg": { "channel": "price", "chainIndex": "1" "tokenContractAddress":"0x382bb369d343125bfb2117af9c149795c6c65c50" }, "connId": "accb8e21" } ```
- [Unsubscribe](https://web3.okx.com/onchainos/dev-docs/market/websocket-unsubscribe.md) {/* api-page */} # Unsubscribe Unsubscribe from one or more channels. ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | op | String | Yes | Operation, `unsubscribe` | | args | Array | Yes | List of subscribed channels | | > channel | String | Yes | Channel name | | > chainIndex | String | Yes | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](../home/supported-chain)) | | > timestamp | String | Yes | Unix Epoch time, the unit is seconds | | > tokenContractAddress | String | Yes | Token contract address,for EVM please pass all-lowercase addresses (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | ## Response Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | event | String | Operation.`unsubscribe` or `error` | | arg | String | Subscribed channel | | > channel | String | Channel name | | > chainIndex | String | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](../home/supported-chain)) | | > tokenContractAddress | String | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | code | String | Error code | | msg | String | Error message | | connId | String | WebSocket connection ID | Request format description ```json { "op": "unsubscribe", "args": ["SubscriptionTopic"] } ``` ## Request Example ```json { "op": "unsubscribe", "args": [{ "channel": "price", "chainIndex": "1", "tokenContractAddress": "0x382bb369d343125bfb2117af9c149795c6c65c50" }] } ``` ## Response Example ```json { "event": "unsubscribe", "arg": { "channel": "price", "chainIndex": "1", "tokenContractAddress":"0x382bb369d343125bfb2117af9c149795c6c65c50" }, "connId": "d0b44253" } ``` - [Websocket Channels](https://web3.okx.com/onchainos/dev-docs/market/websocket-channels.md) # Websocket Channels - [Price Channel](https://web3.okx.com/onchainos/dev-docs/market/websocket-price-channel.md) {/* api-page */} # Price Channel Retrieve the latest price data of a token. The fastest push frequency updates in real time. A push will only occur if there is a trade and the price is not filtered out by the candlestick (K-line) price filter.
**Request URL** wss://wsdex.okx.com/ws/v6/dex ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | op | String | Yes | Operation, `subscribe` `unsubscribe` | | args | Array | Yes | List of subscribed channels | | channel | String | Yes | Channel name,`price` | | chainIndex | String | Yes | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](../home/supported-chain)) | | tokenContractAddress | String | Yes | Token contract address,for EVM please pass all-lowercase addresses (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | ## Response Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | event | String | Event, `subscribe` `unsubscribe` `error` | | arg | Object | Token contract address | | channel | String | Channel name | | chainIndex| String | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](../home/supported-chain)) | | tokenContractAddress| String | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | code | String | Error code | | msg | String | Error message | ## Push Data Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | arg | Object | Successfully subscribed channel | | > channel | String | Channel name | | > chainIndex | String | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](../home/supported-chain)) | | > tokenContractAddress| String | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | data | Array | Subscribed data | | > time | String | Timestamp of the price, Unix timestamp format in milliseconds | | > price | String | Latest token price |
## Request Example ```json { "op": "subscribe", "args": [ { "channel": "price", "chainIndex": "1", "tokenContractAddress":"0x382bb369d343125bfb2117af9c149795c6c65c50" } ] } ``` ## Response Example Successful response example ```json { "event": "subscribe", "arg": { "channel": "price", "chainIndex": "1" "tokenContractAddress":"0x382bb369d343125bfb2117af9c149795c6c65c50" }, "connId": "a4d3ae55" } ``` Failure response example ```json { "event": "error", "code": "60012", "msg": "Invalid request: {\"op\": \"subscribe\", \"argss\":[{ \"channel\" : \"price\", \"chainIndex\" : \"1\", \"tokenContractAddress\" : \"0x382bb369d343125bfb2117af9c149795c6c65c50\"}]}", "connId": "a4d3ae55" } ``` Push data example ```json { "arg": { "channel": "price", "chainIndex": "1" "tokenContractAddress":"0x382bb369d343125bfb2117af9c149795c6c65c50" }, "data": [ { "time": "1716892020000", "price": "26.458143090226812", } ] } ```
- [Liquidity channel](https://web3.okx.com/onchainos/dev-docs/market/websocket-price-info-channel.md) {/* api-page */} # Liquidity channel Returns token liquidity-related data with a maximum push frequency of once per second. **Request URL** wss://wsdex.okx.com/ws/v6/dex ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | op | String | Yes | Operation, `subscribe` `unsubscribe` | | args | Array | Yes | List of subscribed channels | | channel | String | Yes | Channel name,`price` | | chainIndex | String | Yes | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](../home/supported-chain)) | | tokenContractAddress | String | Yes | Token contract address,for EVM please pass all-lowercase addresses (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | ## Response Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | event | String | Event, `subscribe` `unsubscribe` `error` | | arg | Object | Token contract address | | channel | String | Channel name | | chainIndex| String | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](../home/supported-chain)) | | tokenContractAddress| String | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | code | String | Error code | | msg | String | Error message | ## Push Data Parameters | Parameter | Type | Description | |------------------------ |-------- |--------------------------------------------------------------------------- | | arg | Object | Successfully subscribed channel | | > channel | String | Channel name | | > chainIndex | String | Unique identifier for the chain. (e.g., 1 for Ethereum. See ChainIndex) | | > tokenContractAddress | String | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | data | Array | Subscribed data | | > time | String | Timestamp of the price, Unix timestamp format in milliseconds | | > price | String | Latest token price | | > marketCap | String | Token marketcap | | > priceChange5M | String | 5 min price change | | > priceChange1H | String | 1 hour price change | | > priceChange4H | String | 4 hour price change | | > priceChange24H | String | 24 hour price change | | > volume5M | String | 5 min volume | | > volume1H | String | 1 hour volume | | > volume4H | String | 4 hour volume | | > volume24H | String | 24 hour volume | | > txs5M | String | 代币 5 分钟内交易笔数 | | >txs1H | String | 代币 1 小时内交易笔数 | | >txs4H | String | 代币 4 小时内交易笔数 | | >txs24H | String | 代币 24 小时内交易笔数 | | >maxPrice | String | 代币 24h 最高价格 | | >tradeNum | String | 24h 代币交易数量 | | >minPrice | String | 代币 24h 最低价格 | | >circSupply | String | 代币流通供应量 | | >liquidity | String | 代币资金池中的流动性 | | >holders | String | 代币持仓地址数 | ## Request Example ```json { "op": "subscribe", "args": [ { "channel": "price-info", "chainIndex": "1", "tokenContractAddress":"0x382bb369d343125bfb2117af9c149795c6c65c50" } ] } ``` ## Response Example Successful response example ```json { "event": "subscribe", "arg": { "channel": "price-info", "chainIndex": "501" "tokenContractAddress":"eL5fUxj2J4CiQsmW85k5FG9DvuQjjUoBHoQBi2Kpump" }, "connId": "a4d3ae55" } ``` Failure response example ```json { "event": "error", "code": "60012", "msg": "Invalid request: {\"op\": \"subscribe\", \"argss\":[{ \"channel\" : \"price-info\", \"chainIndex\" : \"501\", \"tokenContractAddress\" : \"eL5fUxj2J4CiQsmW85k5FG9DvuQjjUoBHoQBi2Kpump\"}]}", "connId": "a4d3ae55" } ``` Push data example ```json { "arg": { "channel": "price-info", "chainIndex": "501" "tokenContractAddress":"0x382bb369d343125bfb2117af9c149795c6c65c50" }, "data": [ { "chainIndex": "501", "circSupply": "999973312.2632950000", "holders": "37241", "liquidity": "3923952.461979153265333544895656917", "marketCap": "19960307.19257757296691203", "maxPrice": "0.1656024888921609", "minPrice": "0.02292722724150618", "price": "0.019960839902217294", "priceChange1H": "9.12", "priceChange24H": "374.25", "priceChange4H": "68.26", "priceChange5M": "6.91", "time": "1758702741738", "tokenContractAddress": "eL5fUxj2J4CiQsmW85k5FG9DvuQjjUoBHoQBi2Kpump", "tradeNum": "2460429287.120492", "txs1H": "15142", "txs24H": "276164", "txs4H": "38998", "txs5M": "1196", "volume1H": "12864939.572057", "volume24H": "169512096.311189", "volume4H": "29069166.04389", "volume5M": "893224.505265" } ] } ``` - [Candlesticks Channel](https://web3.okx.com/onchainos/dev-docs/market/websocket-candlesticks-channel.md) {/* api-page */} # Candlesticks Channel Retrieve the candlesticks data of a token. The fastest push frequency is 1 push per second.
**Request URL** wss://wsdex.okx.com/ws/v6/dex ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | op | String | Yes | Operation, `subscribe` `unsubscribe` | | args | Array | Yes | List of subscribed channels | | channel | String | Yes | Channel name. `dex-token-candle1s` `dex-token-candle1m` `dex-token-candle3m` `dex-token-candle5m` `dex-token-candle15m` `dex-token-candle30m` `dex-token-candle1H` `dex-token-candle2H` `dex-token-candle4H` `dex-token-candle6H` `dex-token-candle12H` `dex-token-candle1M` `dex-token-candle3M` `dex-token-candle1W` `dex-token-candle1D` `dex-token-candle2D` `dex-token-candle3D` `dex-token-candle5D` `dex-token-candle6Hutc` `dex-token-candle12Hutc` `dex-token-candle1Dutc` `dex-token-candle2Dutc` `dex-token-candle3Dutc` `dex-token-candle5Dutc` `dex-token-candle1Wutc` `dex-token-candle1Mutc` `dex-token-candle3Mutc` | | chainIndex | String | Yes | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](../home/supported-chain)) | | tokenContractAddress | String | Yes | Token contract address,for EVM please pass all-lowercase addresses (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | ## Response Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | event | String | Event, `subscribe` `unsubscribe` `error` | | arg | Object | Token contract address | | channel | String | Channel name | | chainIndex| String | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](../home/supported-chain)) | | tokenContractAddress| String | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | code | String | Error code | | msg | String | Error message | ## Push Data Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | arg | Object | Successfully subscribed channel | | > channel | String | Channel name | | > chainIndex | String | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](../home/supported-chain)) | | > tokenContractAddress| String | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | data | Array | Subscribed data | | > ts | String | Opening time of the candlestick, Unix timestamp format in milliseconds, e.g. 1597026383085 | | > o | String | Open price | | > h | String | highest price | | > l | String | Lowest price | | > c | String | Close price | | > vol | String | Trading volume, with a unit of base currency | | > volUsd | String | Trading volume, with a unit of usd. | | > confirm | String | The state of candlesticks.
`0`: represents that it is uncompleted `1`: represents that it is completed. |
## Request Example ```json { "op": "subscribe", "args": [ { "channel": "dex-token-candle1s", "chainIndex": "1", "tokenContractAddress":"0x382bb369d343125bfb2117af9c149795c6c65c50" } ] } ``` ## Response Example Successful response example ```json { "event": "subscribe", "arg": { "channel": "dex-token-candle1s", "chainIndex": "1" "tokenContractAddress":"0x382bb369d343125bfb2117af9c149795c6c65c50" }, "connId": "a4d3ae55" } ``` Failure response example ```json { "event": "error", "code": "60012", "msg": "Invalid request: {\"op\": \"subscribe\", \"argss\":[{ \"channel\" : \"dex-token-candle1s\", \"chainIndex\" : \"1\", \"tokenContractAddress\" : \"0x382bb369d343125bfb2117af9c149795c6c65c50\"}]}", "connId": "a4d3ae55" } ``` Push data example ```json { "arg": { "channel": "dex-token-candle1s", "chainIndex": "1" "tokenContractAddress":"0x382bb369d343125bfb2117af9c149795c6c65c50" }, "data": [ [ "1597026383085", "8533.02", "8553.74", "8527.17", "8548.26", "529.5858061", "226348.0482", "0" ] ] } ```
- [Token Update Channel](https://web3.okx.com/onchainos/dev-docs/market/websocket-token-channel.md) {/* api-page */} # Token Update Channel Real-time push of incremental market metric updates for Meme tokens. Data is pushed whenever metrics change.
**URL Path**
wss://wsdex.okx.com/ws/v6/dex ## Request Parameters | Parameter | Type | Required | Description | |--------------------------|--------|----------|-------------------------------------------------------------------------------------------------| | op | String | Yes | Operation: `subscribe` `unsubscribe` | | args | Array | Yes | List of channels to subscribe | | channel | String | Yes | Channel name: `dex-market-memepump-update-metrics-openapi` | | chainIndex | String | Yes | Unique identifier for the chain. Pass the chain ID (e.g., 501 for Solana). Single-chain only. | ## Response Parameters | Parameter | Type | Description | |-----------|--------|-----------------------------------------------------------| | event | String | Event type: `subscribe` `unsubscribe` `error` | | arg | Object | Subscribed channel | | channel | String | Channel name | | code | String | Error code (only returned when event=error) | | msg | String | Error message (only returned when event=error) | | connId | String | WebSocket connection ID | ## Push Data Parameters | Parameter | Type | Description | |------------------------------------|---------|---------------------------------------------------------------------------------------| | arg | Object | Successfully subscribed channel info | | > channel | String | Channel name | | > chainIndex | String | Unique identifier for the chain | | data | Array | Batched real-time token metric updates (each batch contains multiple token objects) | | > chainIndex | String | Chain ID (e.g., 501=Solana) | | > protocolId | String | Protocol source ID (e.g., 1=PUMP_FUN) | | > quoteTokenAddress | String | Quote token contract address | | > tokenContractAddress | String | Token contract address | | > symbol | String | Token symbol | | > name | String | Token name | | > logoUrl | String | Token logo URL | | > createdTimestamp | String | Token creation time (Unix timestamp in milliseconds) | | > market | Object | Market data (incremental update) | | >> marketCapUsd | String | Market cap (USD) | | >> volumeUsd1h | String | 1-hour trading volume (USD) | | >> txCount1h | String | 1-hour total transaction count | | >> buyTxCount1h | String | 1-hour buy transaction count | | >> sellTxCount1h | String | 1-hour sell transaction count | | > bondingPercent | String | Bonding curve progress (%) | | > mayhemModeTimeRemaining | String | Remaining time for Pump.fun Mayhem Mode; empty if token is not in this mode | | > tags | Object | Tag / audit data | | >> top10HoldingsPercent | String | Top 10 holders percentage (%) | | >> devHoldingsPercent | String | Dev holdings percentage (%) | | >> insidersPercent | String | Insiders percentage (%) | | >> bundlersPercent | String | Bundlers percentage (%) | | >> snipersPercent | String | Snipers percentage (%) | | >> freshWalletsPercent | String | Fresh wallets percentage (%) | | >> suspectedPhishingWalletPercent | String | Suspected phishing wallet percentage (%) | | >> totalHolders | String | Total number of token holder addresses | | > social | Object | Social media information | | >> x | String | X (Twitter) link | | >> telegram | String | Telegram link | | >> website | String | Website link | | >> dexScreenerPaid | Boolean | DEX Screener paid | | >> communityTakeover | Boolean | Community takeover (CTO) | | >> liveOnPumpFun | Boolean | Live on Pump.fun | | > bagsFeeClaimed | Boolean | Whether bags fee has been claimed |
## Request Example ```json { "op": "subscribe", "args": [ { "channel": "dex-market-memepump-update-metrics-openapi", "chainIndex": "501" } ] } ``` ## Response Example Successful response example ```json { "event": "subscribe", "arg": { "channel": "dex-market-memepump-update-metrics-openapi", "chainIndex": "501" }, "connId": "a4d3ae55" } ``` Failure response example ```json { "event": "error", "code": "60012", "msg": "Invalid request: {\"op\": \"subscribe\", \"argss\":[{ \"channel\": \"dex-market-memepump-update-metrics-openapi\", \"chainIndex\": \"501\"}]}", "connId": "a4d3ae55" } ``` Push data example ```json { "arg": { "channel": "dex-market-memepump-update-metrics-openapi", "chainIndex": "501" }, "data": [ [ { "bagsFeeClaimed": false, "bondingPercent": "0.02", "chainIndex": "501", "createdTimestamp": "1773129702000", "creatorAddress": "5DZ1ghesLRDzioYoDoyFejgxRwFBxgs9P85kv6d8Zd7X", "logoUrl": "https://static.coinall.ltd/cdn/web3/currency/token/default-logo/token_custom_logo_default_P/type=default_350_0", "market": { "buyTxCount1h": "1", "marketCapUsd": "2457.472431547000000000", "sellTxCount1h": "0", "txCount1h": "1", "volumeUsd1h": "4.011085498679725011505911" }, "name": "$PRISM", "protocolId": "136137", "quoteTokenAddress": "So11111111111111111111111111111111111111112", "social": { "communityTakeover": false, "dexScreenerPaid": false, "liveOnPumpFun": false }, "symbol": "PSM", "tags": { "bundlersPercent": "0", "devHoldingsPercent": "0.0458", "freshWalletsPercent": "0", "insidersPercent": "0", "snipersPercent": "0.0458", "suspectedPhishingWalletPercent": "0", "top10HoldingsPercent": "0.16320", "totalHolders": "1" }, "tokenAddress": "SXEdooR2e1RHpYdarMqFPrkhTBARn6NhT88nXjVrD2X" } ] ] } ```
- [Trades Channel](https://web3.okx.com/onchainos/dev-docs/market/websocket-trades-channel.md) {/* api-page */} # Trades Channel Retrieve the recent trades data. Data will be pushed whenever there is a trades.
**Request URL** wss://wsdex.okx.com/ws/v6/dex ## Request Parameters | Parameter | Type | Required | Description | | -------------------- | ------ | -------- | ------------------------------------------------------------------------------------------------ | | op | String | Yes | Operation, `subscribe` `unsubscribe` | | args | Array | Yes | List of subscribed channels | | channel | String | Yes | Channel name,`trades` | | chainIndex | String | Yes | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](../home/supported-chain)) | | tokenContractAddress | String | Yes | Token contract address,for EVM please pass all-lowercase addresses (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | ## Response Parameters | Parameter | Type | Description | | -------------------- | ------ | ------------------------------------------------------------------------------------------------ | | event | String | Event, `subscribe` `unsubscribe` `error` | | arg | Object | Token contract address | | channel | String | Channel name | | chainIndex | String | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](../home/supported-chain)) | | tokenContractAddress | String | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | code | String | Error code | | msg | String | Error message | ## Push Data Parameters | Parameter | Type | Description | | ----------------------- | ------ | ------------------------------------------------------------------------------------------------ | | arg | Object | Successfully subscribed channel | | > channel | String | Channel name | | > chainIndex | String | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](../home/supported-chain)) | | > tokenContractAddress | String | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | data | Array | Subscribed data | | > id | String | Unique trade id | | > txHashUrl | String | On-chain txhash of the transaction | | > userAddress | String | Authorizer of the transaction | | > dexName | String | Name of the dex where the trade occured | | > poolLogoUrl | String | Pool logo url | | > type | String | Trade Type buy sell | | > amountExchanged | String | Amount exchanged in this pair | | >> amount | String | Token exchanged amount in this trade | | >> tokenSymbol | String | Token symbol | | >> tokenContractAddress | String | Token contract address | | > price | String | Latest token price | | > volume | String | USD value of this trade | | > time | String | Timestamp of the trade, Unix timestamp format in milliseconds | | > isFiltered | String | If the trade is filtered for price and k-line calculation.
`0`: not filtered `1`: filtered |
## Request Example ```json { "op": "subscribe", "args": [ { "channel": "trades", "chainIndex": "501", "tokenContractAddress": "HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC" } ] } ``` ## Response Example Successful response example ```json { "event": "subscribe", "arg": { "channel": "trades", "chainIndex": "501", "tokenContractAddress": "HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC" }, "connId": "a4d3ae55" } ``` Failure response example ```json { "event": "error", "code": "60012", "msg": "Invalid request: {\"op\": \"subscribe\", \"argss\":[{ \"channel\" : \"trades\", \"chainIndex\" : \"501\", \"tokenContractAddress\" : \"HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC\"}]}", "connId": "a4d3ae55" } ``` Push data example ```json { "arg": { "channel": "trades", "chainIndex": "501" "tokenContractAddress":"HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC" }, "data":[ { "id":"1739439633000!@#120!@#14731892839", "chainIndex": "501", "tokenContractAddress": "HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC", "txHashUrl": "https://solscan.io/tx/zgDzoiVG4XuDgQcoEg9vhpRyfyk5thNUQuTeTCeF289Qec5iraeCrUzPLyiE2UCviox2ebbTcsagGvzYF7M5uqs", "userAddress": "2kCm1RHGJjeCKL4SA3ZJCLyXqUD7nEJ7GMtVaP7c6jQ8", "dexName": "Orca Whirlpools", "poolLogoUrl": "https://static.okx.com/cdn/wallet/logo/dex_orcaswap.png", "type": "sell", "changedTokenInfo": [ { "amount":"100.396595878", "tokenSymbol":"ai16z", "tokenContractAddress": "HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC" }, { "amount":"2.482831", "tokenSymbol":"SOL", "tokenContractAddress": "So11111111111111111111111111111111111111112" } ] "price": "26.458143090226812", "volume": "519.788163", "time": "1739439633000", "isFiltered": "0" } ] } ```
- [Signal Channel](https://web3.okx.com/onchainos/dev-docs/market/websocket-signal-channel.md) {/* api-page */} # Signal Channel Real-time push of on-chain trading signals from Smart Money / KOL / Whale wallets. Subscribe after login; data is pushed whenever a new signal is triggered.
**URL Path**
wss://wsdex.okx.com/ws/v6/dex ## Request Parameters | Parameter | Type | Required | Description | |-------------|--------|----------|----------------------------------------------------------------------------------------------------------| | op | String | Yes | Operation: `subscribe` `unsubscribe` | | args | Array | Yes | List of channels to subscribe | | channel | String | Yes | Channel name `dex-market-new-signal-openapi` | | chainIndex | String | Yes | Unique identifier for the chain. Pass the chain ID (e.g., 1 for Ethereum). Single-chain only. | ## Response Parameters | Parameter | Type | Description | |------------------------------|--------|---------------------------------------------------------------------------------------------------------------------| | event | String | Event type: `subscribe` `unsubscribe` `error` | | arg | Object | Subscribed channel | | channel | String | Channel name | | signal | Object | Signal list | | > timestamp | String | Timestamp when the signal was triggered | | > chainIndex | String | Unique identifier for the chain | | > token | Object | Token information | | >> tokenAddress | String | Token contract address | | >> symbol | String | Token symbol | | >> name | String | Token name | | >> logo | String | Token logo URL | | >> marketCapUsd | String | Market cap (USD) | | >> holders | String | Number of holder addresses | | >> top10HolderPercent | String | Top 10 holder percentage | | > price | String | Token price (USD) at signal trigger time | | > walletType | String | Wallet type code. Enum: `1` = Smart Money, `2` = KOL / Influencer, `3` = Whales. Multiple values separated by commas | | > triggerWalletCount | String | Number of wallet addresses that triggered the signal | | > triggerWalletAddress | String | List of wallet addresses, comma-separated | | > amountUsd | String | Trade amount (USD) | | > soldRatioPercent | String | Sell-off ratio percentage | | code | String | Error code (only returned when event=error) | | msg | String | Error message (only returned when event=error) | ## Push Data Parameters | Parameter | Type | Description | |------------------------------|--------|---------------------------------------------------------------------------------------------------------------------| | arg | Object | Successfully subscribed channel info | | > channel | String | Channel name | | > timestamp | String | Timestamp when the signal was triggered | | > chainIndex | String | Unique identifier for the chain | | > token | Object | Token information | | >> tokenAddress | String | Token contract address | | >> symbol | String | Token symbol | | >> name | String | Token name | | >> logo | String | Token logo URL | | >> marketCapUsd | String | Market cap (USD) | | >> holders | String | Number of holder addresses | | >> top10HolderPercentage | String | Top 10 holder percentage | | > price | String | Token price (USD) at signal trigger time | | > walletType | String | Wallet type code. Enum: `1` = Smart Money, `2` = KOL / Influencer, `3` = Whales. Multiple values separated by commas | | > triggerWalletCount | String | Number of wallet addresses that triggered the signal | | > triggerWalletAddress | String | List of wallet addresses, comma-separated | | > amountUsd | String | Trade amount (USD) | | > soldRatioPercentage | String | Sell-off ratio percentage |
## Request Example ```json { "op": "subscribe", "args": [ { "channel": "dex-market-new-signal-openapi", "chainIndex": "1" } ] } ``` ## Response Example Successful response example ```json { "event": "subscribe", "arg": { "channel": "dex-market-new-signal-openapi", "chainIndex": "1" }, "connId": "a4d3ae55" } ``` Failure response example ```json { "event": "error", "code": "60012", "msg": "Invalid request: {\"op\": \"subscribe\", \"argss\":[{ \"channel\" , \"chainIndex\" : \"1\", \"tokenContractAddress\" : \"0x382bb369d343125bfb2117af9c149795c6c65c50\"}]}", "connId": "a4d3ae55" } ``` Push data example ```json { "arg": { "channel": "dex-market-new-signal-openapi", "chainIndex": "1", "timestamp": "1739439633000", "token": { "tokenAddress": "0x382bb369d343125bfb2117af9c149795c6c65c50", "symbol": "ORBS", "name": "Orbs", "logo": "https://static.okx.com/cdn/wallet/logo/ORBS.png", "marketCapUsd": "89234567.12", "holders": "23456", "top10HolderPercentage": "35.6" }, "price": "0.0421", "walletType": "1,2", "triggerWalletCount": "5", "triggerWalletAddress": "0xabc...111,0xdef...222", "amountUsd": "128000.00", "soldRatioPercentage": "0" } } ```
- [Memepump Channel](https://web3.okx.com/onchainos/dev-docs/market/websocket-memepump-channel.md) {/* api-page */} # Memepump Channel Real-time push of newly launched Meme token data. Data is pushed whenever a new token is released.
**URL Path**
wss://wsdex.okx.com/ws/v6/dex ## Request Parameters | Parameter | Type | Required | Description | |--------------------------|--------|----------|-------------------------------------------------------------------------------------------------| | op | String | Yes | Operation: `subscribe` `unsubscribe` | | args | Array | Yes | List of channels to subscribe | | channel | String | Yes | Channel name: `dex-market-memepump-new-token-openapi` | | chainIndex | String | Yes | Unique identifier for the chain. Pass the chain ID (e.g., 501 for Solana). Single-chain only. | ## Response Parameters | Parameter | Type | Description | |-----------|--------|-----------------------------------------------------------| | event | String | Event type: `subscribe` `unsubscribe` `error` | | arg | Object | Subscribed channel | | channel | String | Channel name | | code | String | Error code (only returned when event=error) | | msg | String | Error message (only returned when event=error) | | connId | String | WebSocket connection ID | ## Push Data Parameters | Parameter | Type | Description | |------------------------------------|---------|--------------------------------------------------------------------------| | arg | Object | Successfully subscribed channel info | | > channel | String | Channel name | | > chainIndex | String | Unique identifier for the chain | | data | Array | List of newly launched tokens | | > chainIndex | String | Chain ID (e.g., 501=Solana) | | > protocolId | String | Protocol source ID (e.g., 1=PUMP_FUN) | | > quoteTokenAddress | String | Quote token contract address | | > tokenContractAddress | String | Token contract address | | > symbol | String | Token symbol | | > name | String | Token name | | > logoUrl | String | Token logo URL | | > createdTimestamp | String | Token creation time (Unix timestamp in milliseconds) | | > market | Object | Market data | | >> marketCapUsd | String | Market cap (USD) | | >> volumeUsd1h | String | 1-hour trading volume (USD) | | >> txCount1h | String | 1-hour total transaction count | | >> buyTxCount1h | String | 1-hour buy transaction count | | >> sellTxCount1h | String | 1-hour sell transaction count | | > bondingPercent | String | Bonding curve progress (%) | | > tags | Object | Tag / audit data | | >> top10HoldingsPercent | String | Top 10 holders percentage (%) | | >> devHoldingsPercent | String | Dev holdings percentage (%) | | >> insidersPercent | String | Insiders percentage (%) | | >> bundlersPercent | String | Bundlers percentage (%) | | >> snipersPercent | String | Snipers percentage (%) | | >> freshWalletsPercent | String | Fresh wallets percentage (%) | | >> suspectedPhishingWalletPercent | String | Suspected phishing wallet percentage (%) | | >> totalHolders | String | Total number of token holder addresses | | > social | Object | Social media information | | >> x | String | X (Twitter) link | | >> telegram | String | Telegram link | | >> website | String | Website link | | >> dexScreenerPaid | Boolean | DEX Screener paid | | >> communityTakeover | Boolean | Community takeover (CTO) | | >> liveOnPumpFun | Boolean | Live on Pump.fun | | > bagsFeeClaimed | Boolean | Whether bags fee has been claimed |
## Request Example ```json { "op": "subscribe", "args": [ { "channel": "dex-market-memepump-new-token-openapi", "chainIndex": "501" } ] } ``` ## Response Example Successful response example ```json { "event": "subscribe", "arg": { "channel": "dex-market-memepump-new-token-openapi", "chainIndex": "501" }, "connId": "a4d3ae55" } ``` Failure response example ```json { "event": "error", "code": "60012", "msg": "Invalid request: {\"op\": \"subscribe\", \"argss\":[{ \"channel\": \"dex-market-memepump-new-token-openapi\", \"chainIndex\": \"501\"}]}", "connId": "a4d3ae55" } ``` Push data example ```json { "arg": { "channel": "dex-market-memepump-new-token-openapi", "chainIndex": "501" }, "data": [ { "bagsFeeClaimed": false, "bondingPercent": "0", "chainIndex": "501", "createdTimestamp": "1773111278502", "creatorAddress": "CfCpn9LFW6HDsUcNUbX65HfxNmouhTNCb6RD9FmF8sy9", "logoUrl": "https://static.oklink.com/cdn/web3/currency/token/default-logo/token_custom_logo_default_S/type=default_350_0", "market": {}, "name": "Siberian Husky Scarlett", "protocolId": "136460", "social": { "communityTakeover": false, "dexScreenerPaid": false, "liveOnPumpFun": false }, "symbol": "Scarlett", "tags": {}, "tokenAddress": "5E2yC3KVFhm2kvUXFMWJCKP7pLtkScBP8CnZ9rtjpump" } ] } ```
- [Address Tracker Trades Channel](https://web3.okx.com/onchainos/dev-docs/market/websocket-address-activity-channel.md) {/* api-page */} # Address Tracker Trades Channel Real-time push of on-chain transaction activity from tracked wallet addresses. Subscribe after login; data is pushed whenever a new transaction occurs.
**URL Path**
wss://wsdex.okx.com/ws/v6/dex ## Request Parameters | Parameter | Type | Required | Description | |-------------|--------|----------|---------------------------------------------------------------| | op | String | Yes | Operation: `subscribe` `unsubscribe` | | args | Array | Yes | List of subscription parameters | | > channel | String | Yes | Channel name: `address-tracker-activity` | | > walletAddress | String | Yes | The wallet addresses you want to track, One connection can support up to 200 addresses; for 1,000 addresses, simply establish 5 connections. | ## Response Parameters | Parameter | Type | Description | |-------------|--------|--------------------------------------------------------------------| | event | String | Event type: `subscribe` `unsubscribe` `error` | | arg | Object | Successfully subscribed channel parameters | | > channel | String | Channel name | | code | String | Error code (only returned when event=error) | | msg | String | Error message (only returned when event=error) | | connId | String | WebSocket connection ID | ## Push Data Parameters | Parameter | Type | Description | |------------------------|--------|-------------------------------------------------------------------------------------------------| | arg | Object | Channel info that triggered the push | | > channel | String | Channel name | | data | Array | List of pushed trade activity | | > txHash | String | Transaction hash | | > walletAddress | String | Trading wallet address | | > quoteTokenSymbol | String | Quote token symbol (native chain token) | | > quoteTokenAmount | String | Quote token trade amount | | > tokenSymbol | String | Traded token symbol | | > tokenContractAddress | String | Traded token contract address | | > chainIndex | String | Chain identifier of the traded token | | > tokenPrice | String | Trade price of the token (USD) | | > marketCap | String | Market cap of the token at the trade price (USD) | | > realizedPnlUsd | String | Realized PnL for the token (USD) | | > tradeType | String | Trade type: `1` buy `2` sell | | > tradeTime | String | Trade time (Unix timestamp in milliseconds) | | > trackerType | Array | Tracker wallet type: `1` Smart Money `2` KOL |
## Request Example ```json { "channel": "address-tracker-activity", "walletAddress": "DHfshpzoC9Q7rz32j5juq2do3Bo8bA1KLmkNiRYaA8tf" }, { "channel": "address-tracker-activity", "walletAddress": "0x1234567890abcdef1234567890abcdef12345678" }, { "channel": "address-tracker-activity", "walletAddress": "0x1234567890abcdef1234567890abcdef12345678" } ``` ## Response Example Successful response example ```json { "event": "subscribe", "arg": { "channel": "address-tracker-activity" }, "connId": "a4d3ae55" } ``` Failure response example ```json { "event": "error", "code": "60012", "msg": "Invalid request: {\"op\": \"subscribe\", \"argss\":[{ \"channel\" , \"chainIndex\" : \"1\", \"tokenContractAddress\" : \"0x382bb369d343125bfb2117af9c149795c6c65c50\"}]}", "connId": "a4d3ae55" } ``` Push data example ```json { "arg": { "channel": "address-tracker-activity" }, "data": [ { "baseTokenChainIndex": "501", "baseTokenContractAddress": "FmxDdxpFmmuN4DeXoHFzuEyrH8RfRsej6oxg4MaUpump", "baseTokenSymbol": "XAIC", "marketCap": "3229.75150297000000000000000000000000000", "quoteTokenAmount": "1.576294", "quoteTokenSymbol": "SOLANA", "realizedPnlUsd": "-0.481221442431056693018746", "trackerType": [1], "tradePrice": "0.00000322975150297", "tradeTime": 1773628806000, "tradeType": "2", "walletAddress": "DHfshpzoC9Q7rz32j5juq2do3Bo8bA1KLmkNiRYaA8tf" } ] } ```
- [KOL & Smart Money Tracker Trades Channel](https://web3.okx.com/onchainos/dev-docs/market/websocket-kol-smartmoney-activity-channel.md) {/* api-page */} # KOL & Smart Money Tracker Trades Channel Real-time push of on-chain transaction activity from tracked KOL / Smart Money addresses. Subscribe after login; data is pushed whenever a new transaction occurs.
**URL Path**
wss://wsdex.okx.com/ws/v6/dex ## Request Parameters | Parameter | Type | Required | Description | |-------------|--------|----------|---------------------------------------------------------------| | op | String | Yes | Operation: `subscribe` `unsubscribe` | | args | Array | Yes | List of subscription parameters | | > channel | String | Yes | Channel name: `kol_smartmoney-tracker-activity` | ## Response Parameters | Parameter | Type | Description | |-------------|--------|--------------------------------------------------------------------| | event | String | Event type: `subscribe` `unsubscribe` `error` | | arg | Object | Successfully subscribed channel parameters | | > channel | String | Channel name | | code | String | Error code (only returned when event=error) | | msg | String | Error message (only returned when event=error) | | connId | String | WebSocket connection ID | ## Push Data Parameters | Parameter | Type | Description | |------------------------|--------|-------------------------------------------------------------------------------------------------| | arg | Object | Channel info that triggered the push | | > channel | String | Channel name | | data | Array | List of pushed trade activity | | > txHash | String | Transaction hash | | > walletAddress | String | Trading wallet address | | > quoteTokenSymbol | String | Quote token symbol (native chain token) | | > quoteTokenAmount | String | Quote token trade amount | | > tokenSymbol | String | Traded token symbol | | > tokenContractAddress | String | Traded token contract address | | > chainIndex | String | Chain identifier of the traded token | | > tokenPrice | String | Trade price of the token (USD) | | > marketCap | String | Market cap of the token at the trade price (USD) | | > realizedPnlUsd | String | Realized PnL for the token (USD) | | > tradeType | String | Trade type: `1` buy `2` sell | | > tradeTime | String | Trade time (Unix timestamp in milliseconds) | | > trackerType | Array | Tracker wallet type: `1` Smart Money `2` KOL |
## Request Example ```json { "op": "subscribe", "args": [ { "channel": "kol_smartmoney-tracker-activity" } ] } ``` ## Response Example Successful response example ```json { "event": "subscribe", "arg": { "channel": "kol_smartmoney-tracker-activity" }, "connId": "a4d3ae55" } ``` Failure response example ```json { "event": "error", "code": "60012", "msg": "Invalid request: {\"op\": \"subscribe\", \"argss\":[{ \"channel\" , \"chainIndex\" : \"1\", \"tokenContractAddress\" : \"0x382bb369d343125bfb2117af9c149795c6c65c50\"}]}", "connId": "a4d3ae55" } ``` Push data example ```json { "arg": { "channel": "kol_smartmoney-tracker-activity" }, "data": [ { "baseTokenChainIndex": "501", "baseTokenContractAddress": "FmxDdxpFmmuN4DeXoHFzuEyrH8RfRsej6oxg4MaUpump", "baseTokenSymbol": "XAIC", "marketCap": "3229.75150297000000000000000000000000000", "quoteTokenAmount": "1.576294", "quoteTokenSymbol": "SOLANA", "realizedPnlUsd": "-0.481221442431056693018746", "trackerType": [1], "tradePrice": "0.00000322975150297", "tradeTime": 1773628806000, "tradeType": "2", "walletAddress": "DHfshpzoC9Q7rz32j5juq2do3Bo8bA1KLmkNiRYaA8tf" } ] } ```
- [Error Codes](https://web3.okx.com/onchainos/dev-docs/market/websocket-error-code.md) # Error Codes | Code | Message | |-------|------------------------------------------------------------------------------------------------------------| | 60004 | Invalid timestamp | | 60005 | Invalid apiKey | | 60006 | Timestamp request expired | | 60007 | Invalid sign | | 60008 | The current WebSocket endpoint does not support subscribing to {0} channels. Please check the WebSocket URL | | 60009 | Login failure | | 60011 | Please log in | | 60012 | Invalid request | | 60013 | Invalid args | | 60014 | Requests too frequent | | 60018 | Wrong URL or {0} doesn't exist. Please use the correct URL, channel and parameters referring to API document. | | 60019 | Invalid op: \{op\} | | 60020 | APIKey subscription amount exceeds the limit {0}. | | 60021 | This operation does not support multiple accounts login. | | 60022 | Bulk login partially succeeded | | 60023 | Bulk login requests too frequent | | 60024 | Wrong passphrase | | 60025 | token subscription amount exceeds the limit {0} | | 60026 | Batch login by APIKey and token simultaneously is not supported. | | 60027 | Parameter {0} can not be empty. | | 60028 | The current operation is not supported by this URL. Please use the correct WebSocket URL for the operation. | | 60029 | Only users who are in the whitelist are allowed to subscribe to this channel. | | 60030 | The WebSocket endpoint does not allow multiple or repeated logins. | | 60031 | API key doesn't exist. | | 63999 | Login failed due to internal error. Please try again later. | - [API Reference](https://web3.okx.com/onchainos/dev-docs/market/index-price-reference.md) # API Reference - [Get Supported Chains](https://web3.okx.com/onchainos/dev-docs/market/index-price-chains.md) {/* api-page */} # Get Supported Chains Retrieve information on chains supported by Index price API ### Request URL GET `https://web3.okx.com/api/v6/dex/balance/supported/chain` ## Request Parameters None ## Response Parameters | Parameter | Type | Description | |-----------|--------|-------------------| | name | String | Chain name | | logoUrl | String | Chain logo URL | | shortName | String | Chain short name | | chainIndex| String | Chain unique identifier | ## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/balance/supported/chain' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "name": "Ethereum", "logoUrl": "http://www.eth.org/eth.png", "shortName": "ETH", "chainIndex": "1" } ], "msg": "" } ``` - [Get Token Index Price](https://web3.okx.com/onchainos/dev-docs/market/index-price.md) {/* api-page */} # Get Token Index Price The index price refers to a currency price calculated from the prices of multiple third-party data sources. Batch query for index token prices, maximum 100 token prices can be queried per request.
Request Parameters should be passed in the form of an array. ### Request URL POST `https://web3.okx.com/api/v6/dex/index/current-price` ## Request Parameters | Parameter | Type | Required | Description | |--------------|--------|----------|-------------| | chainIndex | String | Yes | Unique identifier of the blockchain | | tokenContractAddress | String | Yes | Token address.
`1`: Pass an empty string `""` to query the native token of the corresponding chain.
`2`: Pass the specific token contract address to query the corresponding token. |
## Response Parameters | Parameter | Type | Description | |--------------|--------|-------------------------------| | price | String | Token price | | time | String | Timestamp of the price, Unix timestamp in milliseconds | | chainIndex | String | Unique identifier of the blockchain | | tokenContractAddress | String | Token address.|
## Request Example ``` shell curl --location --request POST 'https://web3.okx.com/api/v6/dex/index/current-price' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '[ { "chainIndex": "1", "tokenContractAddress":"0xc18360217d8f7ab5e7c516566761ea12ce7f9d72" }, ]' ``` ## Response Example ``` json { "code": 0, "msg": "success", "data": [ { "chainIndex": "1", "tokenContractAddress": "0xc18360217d8f7ab5e7c516566761ea12ce7f9d72" "time": "1716892020000", "price": "26.458143090226812", } ] } ```
- [Get Historical Index Price](https://web3.okx.com/onchainos/dev-docs/market/historical-index-price.md) {/* api-page */} # Get Historical Index Price Query historical prices for a specific token. ### Request URL GET `https://web3.okx.com/api/v6/dex/index/historical-price` ## Request Parameters | Parameter | Type | Required | Description | |--------------|--------|----------|----------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier of the blockchain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). | | tokenContractAddress | String | No | Token address.
`1`: Pass an empty string `""` to query the native token of the corresponding chain.
`2`: Pass the specific token contract address to query the corresponding token. | | limit | String | No | Number of entries per query, default is 50, maximum is 200 | | cursor | String | No | Cursor position, defaults to the first entry | | begin | String | No | Start time to query historical prices after. Unix timestamp in milliseconds | | end | String | No | End time to query historical prices before. If neither begin nor end is provided, query historical prices before the current time. Unix timestamp in milliseconds | | period | String | No | Time interval unit:
`1m`: 1 minute
`5m`: 5 minutes
`30m`: 30 minutes
`1h`: 1 hour
`1d`: 1 day (default) |
## Response Parameters | Parameter | Type | Description | |-----------|--------|----------------------| | prices | Array | List of historical prices | | >time | String | Timestamp of the minute (whole minute) | | >price | String | Cryptocurrency price (precision 18 decimal places) |
## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v5/wallet/token/historical-price?chainIndex=1&limit=5&begin=1700040600000&period=5m' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "msg": "success", "data": [ { "cursor": "31", "prices": [ { "time": "1700040600000", "price": "1994.430000000000000000" }, { "time": "1700040300000", "price": "1994.190000000000000000" }, { "time": "1700040000000", "price": "1992.090000000000000000" }, { "time": "1700039700000", "price": "1992.190000000000000000" }, { "time": "1700039400000", "price": "1990.190000000000000000" } ] } ] } ```
- [Error Codes](https://web3.okx.com/onchainos/dev-docs/market/index-price-error-code.md) # Error Codes | Code | HTTP status | Message | |-------|-------------|-----------------------------------------------------------------------------------------| | 81001 | 200 | Incorrect parameter | - [API Reference](https://web3.okx.com/onchainos/dev-docs/market/market-token-reference.md) # API Reference - [Token Search](https://web3.okx.com/onchainos/dev-docs/market/market-token-search.md) {/* api-page */} # Token Search Search tokens by token name, symbol or token contract address. For token name or symbol search, return maximum 100 results by relevance.For token contract address, return the exact match result. ### Request URL GET `https://web3.okx.com/api/v6/dex/market/token/search` ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chains | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). | | search | String | Yes | Search for token keywords, token address or token symbol | | cursor | String | No | Pagination cursor, pass the cursor value returned from the previous request | | limit | String | No | Number of records per page, max 100 |
## Response Parameters | Parameter | Type | Description | |---------------------- |--------- |--------------------------------------------------------------------------------------------- | | chainIndex | String | Unique identifier of the chain. (Such as 1: Ethereum, for more see the list of [chainIndex](../home/supported-chain) ) | | cursor | String | Pagination cursor | | tokenName | String | Token name | | tokenSymbol | String | Token identification | | tokenLogoUrl | String | Token icon url | | tokenContractAddress | String | Token contract address | | decimal | String | Token precision | | explorerUrl | String | Token Browser link | | change | String | 24H price change ratio | | holders | String | Number of holders | | liquidity | String | Token liquidity (24h) | | marketCap | String | Token market cap | | price | String | Price | | tagList | Object | Label | | >communityRecognized | Boolean | True means it's listed in the Top 10 CEX or is community verifed |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/token/search?chains=1,10&search=weth' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "chainIndex": "501", "change": "6.59", "decimal": "8", "explorerUrl": "https://web3.okx.com/explorer/solana/token/XsDoVfqeBukxuZHWhdvWHBhgEHjGNst4MLodqsJHzoB", "holders": "22447", "liquidity": "3492546.00711048141155477039737838", "marketCap": "51095303.595316825571569398", "price": "381.228119807066217995", "tagList": { "communityRecognized": true }, "tokenContractAddress": "XsDoVfqeBukxuZHWhdvWHBhgEHjGNst4MLodqsJHzoB", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-XsDoVfqeBukxuZHWhdvWHBhgEHjGNst4MLodqsJHzoB-900/type=default_90_0?v=1771926275192", "tokenName": "Tesla xStock", "tokenSymbol": "TSLAx", "cursor": "0" }, { "chainIndex": "501", "change": "6.19", "decimal": "9", "explorerUrl": "https://web3.okx.com/explorer/solana/token/KeGv7bsfR4MheC1CkmnAVceoApjrkvBhHYjWb67ondo", "holders": "133", "liquidity": "", "marketCap": "7747.288131154003818", "price": "380.833333", "tagList": { "communityRecognized": true }, "tokenContractAddress": "KeGv7bsfR4MheC1CkmnAVceoApjrkvBhHYjWb67ondo", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-KeGv7bsfR4MheC1CkmnAVceoApjrkvBhHYjWb67ondo-900/type=default_90_0?v=1774296033373", "tokenName": "Tesla (Ondo Tokenized)", "tokenSymbol": "TSLAon", "cursor": "1" } ], "msg": "" } ```
- [Token Basic Information](https://web3.okx.com/onchainos/dev-docs/market/market-token-basic-info.md) {/* api-page */} # Token Basic Information Retrieve the basic token information of the specified token contract address ### Request URL POST `https://web3.okx.com/api/v6/dex/market/token/basic-info` ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). | | tokenContractAddress | String | Yes | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) |
## Response Parameters | Parameter | Type | Description | |---------------------- |--------- |-------------------------------------------------------------------------------------------- | | chainIndex | String | Unique identifier of the chain. (Such as 1: Ethereum, for more see the list of [chainIndex](../home/supported-chain) ) | | tokenName | String | Token name | | tokenSymbol | String | Token identification | | tokenLogoUrl | String | Token icon url | | decimal | String | Token precision | | tagList | Object | Label | | >communityRecognized | Boolean | True means it's listed in the Top 10 CEX or is community verifed |
## Request Example ```shell curl --location --request POST 'https://web3.okx.com/api/v6/dex/market/token/basic-info' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '[ { "chainIndex": "501", "tokenContractAddress": "5mbK36SZ7J19An8jFochhQS4of8g6BwUjbeCSxBSoWdp" }, { "chainIndex": "501", "tokenContractAddress": "eL5fUxj2J4CiQsmW85k5FG9DvuQjjUoBHoQBi2Kpump" } ]' ``` ## Response Example ```json { "code": "0", "data": [ { "chainIndex": "501", "decimal": "6", "tagList": { "communityRecognized": true }, "tokenContractAddress": "5mbK36SZ7J19An8jFochhQS4of8g6BwUjbeCSxBSoWdp", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/small/501-5mbK36SZ7J19An8jFochhQS4of8g6BwUjbeCSxBSoWdp-106?v=1749146943562", "tokenName": "michi", "tokenSymbol": "$michi" }, { "chainIndex": "501", "decimal": "6", "tagList": { "communityRecognized": true }, "tokenContractAddress": "eL5fUxj2J4CiQsmW85k5FG9DvuQjjUoBHoQBi2Kpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-eL5fUxj2J4CiQsmW85k5FG9DvuQjjUoBHoQBi2Kpump-108/type=default_90_0?v=1755815305433", "tokenName": "Unicorn Fart Dust", "tokenSymbol": "UFD" } ], "msg": "" } ```
- [Token Liquidity Pool Information](https://web3.okx.com/onchainos/dev-docs/market/market-token-top-liquidity.md) {/* api-page */} # Token Liquidity Pool Information Support viewing pool information of the top 5 liquidity ### Request Path GET `https://web3.okx.com/api/v6/dex/market/token/top-liquidity` ## Request Parameters | Parameter | Type | Required | Description | |---|---|---|---| | chainIndex | String | Yes | Unique identifier of the chain. For example: `1`: Ethereum. | | tokenContractAddress | String | Yes | Token contract address (e.g. 0x382bb369d343125bfb2117af9c149795c6c65c50) | ## Response Parameters | Field | Type | Description | |---|---|---| | pool | String | Funding pool, e.g. Punch/SOL | | protocolName | String | Agreement name | | liquidityUsd | String | Liquidity value | | liquidityAmount | Array | Quantity of liquidity | | >tokenAmount | String | Token amount in liquidity pool | | >tokenSymbol | String | Token name in liquidity pool | | liquidityProviderFeePercent | String | Liquidity provider fee percentage | | poolAddress | String | Pool address | | poolCreator | String | Pool creator | ## Request Example ```shell curl --location 'https://web3pre.okex.org/api/v6/dex/market/token/liquidity?chainIndex=8453&tokenContractAddress=0x1f16e03c1a5908818f47f6ee7bb16690b40d0671' \ --header 'Cookie: locale=en-US' ``` ## Response Example ```json { "code": "0", "data": [ { "liquidityAmount": [ { "tokenAmount": "4347613.0508917095", "tokenSymbol": "RECALL" }, { "tokenAmount": "142351.302373", "tokenSymbol": "USDC" } ], "liquidityProviderFeePercent": "0.06%", "liquidityUsd": "344879.7538226645330963352547001735", "pool": "RECALL/USDC", "poolAddress": "0x5e3791f68ebceac82788f3becab154c15141a2f4", "poolCreator": "0xee4bbf067ce361b75e8f31fd2fe726caba757a67", "protocolName": "Aerodrome" }, { "liquidityAmount": [ { "tokenAmount": "1627239.5672854523", "tokenSymbol": "RECALL" }, { "tokenAmount": "25.183845099309004", "tokenSymbol": "WETH" } ], "liquidityProviderFeePercent": "0.30%", "liquidityUsd": "126390.2349541208658853815306505521", "pool": "RECALL/WETH", "poolAddress": "0x6ee714d6d8df7662bca805f58cc1d5a8886d78eb", "poolCreator": "0xee4bbf067ce361b75e8f31fd2fe726caba757a67", "protocolName": "Aerodrome" } ], "msg": "" } ``` - [Token Trading Information](https://web3.okx.com/onchainos/dev-docs/market/market-token-price-info.md) {/* api-page */} # Token Trading Information Return token trading information including price, volume, trading info, supply, holders, liquidity etc at specific timestamp, support max 100 multiple tokens query. ### Request URL POST `https://web3.okx.com/api/v6/dex/market/price-info` ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). | | tokenContractAddress | String | Yes | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) |
## Response Parameters | Parameter | Type | Description | |---------------------- |-------- |-------------------------------------------------------------------------------------------- | | chainIndex | String | Unique identifier of the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain) | | tokenContractAddress | String | Token contract address (e.g. 0x382bb369d343125bfb2117af9c149795c6c65c50) | | time | String | Price timestamp, using Unix Millisecond timestamp format | | price | String | Latest token price | | marketCap | String | Token market cap | | priceChange5M | String | Price changes within 5 minutes, in percentage increase or decrease | | priceChange1H | String | Price changes within one hour, expressed as a percentage increase or decrease | | priceChange4H | String | Price changes within 4 hours, expressed as a percentage increase or decrease | | priceChange24H | String | Price changes within 24 hours, expressed as a percentage increase or decrease | | volume5M | String | Trading volume within 5 minutes | | volume1H | String | Trading volume within 1 hour | | volume4H | String | Trading volume within 4 hours | | volume24H | String | Trading volume within 24 hours | | txs5M | String | Token transactions within 5 minutes | | txs1H | String | Token transactions within 1 hour | | txs4H | String | Token transactions within 4 hours | | txs24H | String | Number of token transactions within 24 hours | | maxPrice | String | Token 24h highest price | | tradeNum | String | 24H token trading quantity | | minPrice | String | Token 24h lowest price | | circSupply | String | Token circulation supply | | liquidity | String | Liquidity in the token pool | | holders | String | Number of token holding addresses |
## Request Example ```shell curl --location --request POST 'https://web3.okx.com/api/v6/dex/market/price-info' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '[ { "chainIndex": "501", "tokenContractAddress": "5mbK36SZ7J19An8jFochhQS4of8g6BwUjbeCSxBSoWdp" }, { "chainIndex": "501", "tokenContractAddress": "eL5fUxj2J4CiQsmW85k5FG9DvuQjjUoBHoQBi2Kpump" } ]' ``` ## Response Example ```json { "code": "0", "data": [ { "chainIndex": "501", "circSupply": "555761678.7348550000", "holders": "46998", "liquidity": "2909733.283759244562509712218832656", "marketCap": "12252728.212049527112081409", "maxPrice": "0.023000175796511334", "minPrice": "0.021290716539724027", "price": "0.022046730965585534", "priceChange1H": "-1.24", "priceChange24H": "-1.8", "priceChange4H": "-2.64", "priceChange5M": "0.22", "time": "1756816961600", "tokenContractAddress": "5mbK36SZ7J19An8jFochhQS4of8g6BwUjbeCSxBSoWdp", "tradeNum": "9577269.994247", "txs1H": "27664", "txs24H": "127879", "txs4H": "108489", "txs5M": "2265", "volume1H": "7376.6139697593500223", "volume24H": "213047.96235814982022456", "volume4H": "33943.03136454470008366", "volume5M": "544.69701090069000181" }, { "chainIndex": "501", "circSupply": "999973538.9201610000", "holders": "37302", "liquidity": "2946946.965800864848335614721052390", "marketCap": "25792746.281014184438384254", "maxPrice": "0.026539875867707924", "minPrice": "0.02427728431412691", "price": "0.025793428802993062", "priceChange1H": "-1.13", "priceChange24H": "3.4", "priceChange4H": "-2.07", "priceChange5M": "0.52", "time": "1756816961600", "tokenContractAddress": "eL5fUxj2J4CiQsmW85k5FG9DvuQjjUoBHoQBi2Kpump", "tradeNum": "10046562.105494", "txs1H": "166", "txs24H": "2888", "txs4H": "322", "txs5M": "29", "volume1H": "10343.0564689259900202", "volume24H": "253496.67765782958052983", "volume4H": "21530.5160926891601342", "volume5M": "3278.85450250897" } ], "msg": "" } ```
- [Token Advanced Information](https://web3.okx.com/onchainos/dev-docs/market/market-token-advanced-info.md) {/* api-page */} # Token Advanced Information Obtain advanced information about the specified token contract address ### Request Path GET `https://web3.okx.com/api/v6/dex/market/token/advanced-info` ## Request Parameters | Parameter | Type | Required | Description | |---|---|---|---| | chainIndex | String | Yes | Unique identifier of the chain. For example: `1`: Ethereum. | | tokenContractAddress | String | Yes | Token contract address (e.g. 0x382bb369d343125bfb2117af9c149795c6c65c50) | ## Response Parameters | Field | Type | Description | |---|---|---| | totalFee | String | Total fees include priority fees and tip fees | | lpBurnedPercent | String | Liquidity pool burned percentage | | isInternal | Boolean | Whether it is an internal token | | protocolId | String | Protocol ID | | progress | String | Internal token launch progress | | tokenTags | Array | Token tags: can be empty, or return one or more of the following | | >honeypot | String | Honeypot | | >dexBoost | String | Boost activity | | >lowLiquidity | String | Low liquidity | | >communityRecognized | String | Community recognized | | >devHoldingStatusSell | String | Developers sold | | >devHoldingStatusSellAll | String | Developers sold all | | >devHoldingStatusBuy | String | Developers buy more | | >initialHighLiquidity | String | High initial liquidity | | >smartMoneyBuy | String | Smart money buy | | >devAddLiquidity | String | Developers add liquidity | | >devBurnToken | String | Developers burn tokens | | >volumeChangeRateHoldersPlunge | String | Trading volume plummeted | | >holdersChangeRateHoldersSurge | String | The number of holding addresses has increased sharply | | >dexScreenerTokenCommunityTakeOver | String | Community takeover | | >dexScreenerPaid | String | Paid on DEX Screener | | createTime | String | Token creation time | | creatorAddress | String | Creator address | | devRugPullTokenCount | String | The number of Rug Pull tokens created by the developer | | devCreateTokenCount | String | Total number of tokens created by developers | | devLaunchedTokenCount | String | Developer created tokens in the number of migrated | | riskControlLevel | String | Risk control level: `0`=undefined, `1`=low, `2`=medium, `3`=medium high, `4`=high, `5`=high (manual configuration) | | top10HoldPercent | String | Position percent of Top 10 Holders | | devHoldingPercent | String | Developer position percent | | bundleHoldingPercent | String | Bundle position percent | | suspiciousHoldingPercent | String | Suspicious address position percent | | sniperHoldingPercent | String | Sniper position percent | | snipersClearAddressCount | String | Number of Sniper Clearance Addresses | | snipersTotal | String | Total number of snipers | ## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/token/advanced-info?chainIndex=501&tokenContractAddress=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": { "bundleHoldingPercent": "", "chainIndex": "501", "createTime": "1729231507000", "creatorAddress": "HyYNVYmnFmi87NsQqWzLJhUTPBKQUfgfhdbBa554nMFF", "devCreateTokenCount": "480", "devHoldingPercent": "", "devLaunchedTokenCount": "", "devRugPullTokenCount": "26", "isInternal": false, "lpBurnedPercent": "74.3609957824270349103361582217", "progress": "", "protocolId": "120596", "riskControlLevel": "1", "sniperHoldingPercent": "", "snipersClearAddressCount": "", "snipersTotal": "", "suspiciousHoldingPercent": "", "tokenContractAddress": "9BB6NFEcjBCtnNLFko2FqVQBq8HHM13kCyYcdQbgpump", "tokenTags": [ "dexBoost", "communityRecognized", "devHoldingStatusSellAll", "smartMoneyBuy" ], "top10HoldPercent": "13.6832", "totalFee": "2180.105145301" }, "msg": "" } ``` - [Get Tokens Trades Activity](https://web3.okx.com/onchainos/dev-docs/market/market-trades.md) {/* api-page */} # Get Tokens Trades Activity Retrieve the recent transactions of a token. ### Request URL GET `https://web3.okx.com/api/v6/dex/market/trades` ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). | | tokenContractAddress | String | Yes | Token contract address,for EVM please pass all-lowercase addresses (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | after | String | No | Pagination of data to return records earlier than the requested id. | | limit | String | No | Number of results per request. The maximum is 500 and default is 100. | | tagFilter | String | No | Default: do not enter
Enter 1: Return the holding address labeled KOL.
Enter 2: Return the token address labeled Developer
Enter 3: Return the holding address labeled Smart Money
Enter 4: Return the holding address labeled as Whale
Enter 5: Return the holding address labeled New Wallet
Enter 6: Return the holding address labeled Suspicious
Enter 7: Return the holding address labeled Sniper
Enter 8: Return the holding address labeled as Suspected phishing.
Enter 9: Return the holding address labeled Bundle | | walletAddressFilter | String | No | Query history for multiple addresses. Enter multiple addresses, separated by commas, up to 10 |
## Response Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | id | String | Unique trade id | | chainIndex | String | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](../home/supported-chain)) | | tokenContractAddress | String | Token contract address | | txHashUrl | String | On-chain txhash of the transactions | | userAddress | String | Authorizer of the transaction | | dexName | String | Name of the dex where the trade occured | | poolLogoUrl | String | Pool logo url | | type | String | trade Type. `buy` `sell` | | changedTokenInfo | String | exchanged info | | > amount | String | token exchanged amount in this trade | | > tokenSymbol | String | Token symbol | | > tokenContractAddress | String | Token contract address | | price | String | Latest token price | | volume | String | USD value of this trade | | time | String | Timestamp of the price, Unix timestamp format in milliseconds | | isFiltered | String | If the trade is filtered for price and k-line calculation.
`0`: not filtered `1`: filtered" |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/trades?chainIndex=501&tokenContractAddress=HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code":"0", "data":[ { "id":"1739439633000!@#120!@#14731892839", "chainIndex": "501", "tokenContractAddress": "HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC", "txHashUrl": "https://solscan.io/tx/zgDzoiVG4XuDgQcoEg9vhpRyfyk5thNUQuTeTCeF289Qec5iraeCrUzPLyiE2UCviox2ebbTcsagGvzYF7M5uqs", "userAddress": "2kCm1RHGJjeCKL4SA3ZJCLyXqUD7nEJ7GMtVaP7c6jQ8", "dexName": "Orca Whirlpools", "poolLogoUrl": "https://static.okx.com/cdn/wallet/logo/dex_orcaswap.png", "type": "sell", "changedTokenInfo": [ { "amount":"100.396595878", "tokenSymbol":"ai16z", "tokenContractAddress": "HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC" }, { "amount":"2.482831", "tokenSymbol":"SOL", "tokenContractAddress": "So11111111111111111111111111111111111111112" } ] "price": "26.458143090226812", "volume": "519.788163", "time": "1739439633000", "isFiltered": "0" } ], "msg":"", } ```
- [Hot Tokens](https://web3.okx.com/onchainos/dev-docs/market/market-token-hot-token.md) {/* api-page */} # Hot Tokens Returns a list of tokens ranked by token score and social media mentions based on different time ranges. It can be sorted in descending order according to the specified data, and can also be filtered based on the specified data. Up to 100 results are returned. ### Request Path GET `https://web3.okx.com/api/v6/dex/market/token/hot-token` ## Request Parameters | Parameter | Type | Required | Description | |---|---|---|---| | rankingType | String | Yes | Default use trending, does not support multiple selection
4: Trending, sorting by token score
5: Xmentioned, sorting by number of mentions on Twitter
Note: Only 4 and 5, no 1, 2, 3. | | chainIndex | String | No | Default is all networks, it does not support multiple selection chain. Example: 1, Filter out the tokens of the Ethereum chain | | rankBy | String | No | Trending lists are sorted backwards by "12" by default; The Xmentioned list is sorted by default in reverse order according to "11". Sort in reverse order according to more parameters, single choice
Enter 1: token price \| Enter 2: price changes percent \| Enter 3: transactions \| Enter 4: unique traders \| Enter 5: volume(in USD) \| Enter 6: marketcap \| Enter 7: liquidity value \| Enter 8: token creation time \| Enter 9: OKX in-app search frequency \| Enter 10: number of holder \| Enter 11: mentions on social media \| Enter 12: social media scores \| Enter 14: net inflow \| Enter 15: token score | | rankingTimeFrame | String | No | Default is 1h, single choice
1: 5 minutes \| 2: 1 hour \| 3: 4 hours \| 4: 24 hours | | riskFilter | Boolean | No | Hide risk tokens, default is true. Example: true, false | | protocolId | String | No | Filter tokens by protocol ID. No protocol is selected by default, multiple options can be selected, separated by commas (For example, 120596 can filter out tokens Pump.fun protocols) | | priceChangePercentMin | String | No | Minimum price change percent | | priceChangePercentMax | String | No | Maximum price change percent | | tradeAmountMin | String | No | Minimum volume | | tradeAmountMax | String | No | Maximum volume | | volumeMin | String | No | Minimum turnover | | volumeMax | String | No | Maximum turnover | | txsMin | String | No | Minimum number of transactions | | txsMax | String | No | Maximum number of transactions | | uniqueTraderMin | String | No | Minimum number of unique trader | | uniqueTraderMax | String | No | Maximum number of unique trader | | marketCapMin | String | No | Minimum Marketcap | | marketCapMax | String | No | Maximum Marketcap | | liquidityMin | String | No | Minimum liquidity | | liquidityMax | String | No | Maximum liquidity | | stableTokenFilter | Boolean | No | Whether to filter stablecoins, the default is true. Example: true, false | | holdersMin | String | No | Minimum number of holders | | holdersMax | String | No | Maximum number of holders | | top10HoldPercentMin | String | No | Top 10 minimum holding percent | | top10HoldPercentMax | String | No | Top 10 maximum holding percent | | devHoldPercentMin | String | No | Minimum developer holding percent | | devHoldPercentMax | String | No | Maximum developer holding percent | | suspiciousHoldPercentMin | String | No | Minimum suspicious holding percent | | suspiciousHoldPercentMax | String | No | Maximum suspicious holding percent | | bundleHoldPercentMin | String | No | Minimum binding holding percent | | bundleHoldPercentMax | String | No | Maximum binding holding percent | | mentionedCountMin | String | No | Minimum number of mentions | | mentionedCountMax | String | No | Maximum number of mentions | | socialScoreMin | String | No | Minimum social score | | socialScoreMax | String | No | Maximum social score | | isLpBurnt | Boolean | No | Whether LP is burned, the default is true. Example: true, false | | isMint | Boolean | No | Whether it can be mint, the default is true. Example: true, false | | isFreeze | Boolean | No | Whether to freeze, default is true. Example: true, false | | inflowUsdMin | String | No | Minimum inflow | | inflowUsdMax | String | No | Maximum inflow | | fdvMin | String | No | FDV minimum | | fdvMax | String | No | Maximum FDV | | cursor | String | No | Pagination cursor, pass the cursor value returned from the previous request | | limit | String | No | Number of records per page, max 100 |
## Response Parameters | Field | Type | Description | |---|---|---| | chainIndex | String | Unique identifier of the chain (e.g. 1: Ethereum) | | cursor | String | Pagination cursor | | tokenSymbol | String | Token symbol | | tokenLogoUrl | String | Token Icon URL | | tokenContractAddress | String | Token contract address | | marketCap | String | Marketcap (token price × circulating supply) | | volume | String | Token trading volume (in USD) | | firstTradeTime | String | Token first transaction time | | change | String | Token price change ratio | | liquidity | String | Liquidity value (in USD) | | price | String | Token price | | holders | String | Number of holder | | uniqueTraders | String | The number of unique trader | | txsBuy | String | The number of buy transactions within the specified time | | txsSell | String | Number of sell transactions within a specified time | | txs | String | Total number of transactions within a specified time | | inflowUsd | String | Net inflow | | riskLevelControl | String | Risk control level: `0`=undefined, `1`=low, `2`=medium, `3`=medium high, `4`=high, `5`=high (manual configuration) | | devHoldPercent | String | Developer position percent | | top10HoldPercent | String | Position ratio of top 10 holding addresses | | insiderHoldPercent | String | Internal trader position percent | | bundleHoldPercent | String | Bundled trader position percent | | vibeScore | String | Social media score | | mentionsCount | String | Number of mentions |
## Request Example ```shell curl --location 'https://web3pre.okex.org/api/v6/dex/market/token/hot-token?rankingType=4&category=' \ --header 'Cookie: locale=en-US' ``` ## Response Example ```json -- param limit=10&cursor=20 -- This is not deep pagination. It is in-memory pagination, with a maximum of only 100 records. The maximum cursor value is 100. { "code": "0", "data": [ { "bundleHoldPercent": "0.055471", "chainIndex": "501", "change": "124.46", "devHoldPercent": "", "firstTradeTime": "1774376729000", "holders": "3518", "inflowUsd": "48877.03736178689", "insiderHoldPercent": "", "liquidity": "656584.515776979964291925", "marketCap": "7120200.171337115253774998", "mentionsCount": "", "price": "0.007120235922518026", "riskLevelControl": "1", "tokenContractAddress": "FtSRgyCEhKTc1PPgEAXvuHN3NyiP6LS9uyB28KCN3CAP", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-FtSRgyCEhKTc1PPgEAXvuHN3NyiP6LS9uyB28KCN3CAP-109/type=default_90_0?v=1774381887925", "tokenSymbol": "CAPTCHA", "top10HoldPercent": "20.6599", "txs": "13616", "txsBuy": "6699", "txsSell": "6917", "uniqueTraders": "3508", "vibeScore": "", "volume": "2733012.43208665053", "cursor": 21 }, { "bundleHoldPercent": "0.055471", "chainIndex": "501", "change": "124.46", "devHoldPercent": "", "firstTradeTime": "1774376729000", "holders": "3518", "inflowUsd": "48877.03736178689", "insiderHoldPercent": "", "liquidity": "656584.515776979964291925", "marketCap": "7120200.171337115253774998", "mentionsCount": "", "price": "0.007120235922518026", "riskLevelControl": "1", "tokenContractAddress": "FtSRgyCEhKTc1PPgEAXvuHN3NyiP6LS9uyB28KCN3CAP", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-FtSRgyCEhKTc1PPgEAXvuHN3NyiP6LS9uyB28KCN3CAP-109/type=default_90_0?v=1774381887925", "tokenSymbol": "CAPTCHA", "top10HoldPercent": "20.6599", "txs": "13616", "txsBuy": "6699", "txsSell": "6917", "uniqueTraders": "3508", "vibeScore": "", "volume": "2733012.43208665053", "cursor": 22 } ], "msg": "" } ```
- [Token Holder Information](https://web3.okx.com/onchainos/dev-docs/market/market-token-holder.md) {/* api-page */} # Token Holder Information Support viewing the addresses and corresponding position information of the top 100 holders ### Request Path GET `https://web3.okx.com/api/v6/dex/market/token/holder` ## Request Parameters | Parameter | Type | Required | Description | |---|---|---|---| | chainIndex | String | Yes | Unique identifier of the chain. For example: `1`: Ethereum. | | tokenContractAddress | String | Yes | Token contract address (e.g. 0x382bb369d343125bfb2117af9c149795c6c65c50) | | tagFilter | String | No | Default: No input, return the address data of the first 100 holding coin addresses, arranged in reverse order according to the total income.
Enter 1: Return the address labeled KOL
Enter 2: Return the token address labeled Developer
Enter 3: Return the address labeled Smart Money
Enter 4: Return the holding address labeled as Whale
Enter 5: Return the address labeled New Wallet
Enter 6: Return the holding address labeled Suspicious
Enter 7: Return the holding address labeled Sniper
Enter 8: Return the address labeled as suspected phishing
Enter 9: Return the address labeled as Bundle | | cursor | String | No | Pagination cursor, pass the cursor value returned from the previous request | | limit | String | No | Number of records per page, max 100 |
## Response Parameters | Field | Type | Description | |---|---|---| | holdPercent | String | Percentage of holdings | | cursor | String | Pagination cursor | | nativeTokenBalance | String | Mainnet currency balance | | boughtAmount | String | Total Buy Quantity | | avgBuyPrice | String | Average buying price | | totalSellAmount | String | Total sold quantity | | avgSellPrice | String | Average selling price | | totalPnlUsd | String | Total profit and loss | | realizedPnlUsd | String | Realized profit and loss | | unrealizedPnlUsd | String | Unrealized profit and loss | | fundingSource | String | Sources of funding |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/token/holder?chainIndex=501&tokenContractAddress=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v&tagFilter=1' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json -- Not deep pagination; only supports pagination within up to 100 records returned in memory. { "code": "0", "data": [ { "avgBuyPrice": "0", "avgSellPrice": "0", "boughtAmount": "0", "fundingSource": "9k8jWWqfmTTXrc8gmZqYVxSFJhygURvyVRztivJXFTYP", "holdAmount": "767501192.534284", "holdPercent": "76.750184380179418200", "holderWalletAddress": "2RH6rUTPBJ9rUDPpuV9b8z1YL56k1tYU6Uk5ZoaEFFSK", "nativeTokenBalance": "6.091849989", "realizedPnlUsd": "0", "totalPnlUsd": "0.000000000000000000", "totalSellAmount": "0", "unrealizedPnlUsd": "0.000000000000000000", "cursor": "0" }, { "avgBuyPrice": "0", "avgSellPrice": "0", "boughtAmount": "0", "fundingSource": "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "holdAmount": "36715842.016", "holdPercent": "3.671587317143695100", "holderWalletAddress": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM", "nativeTokenBalance": "13908916.377375046", "realizedPnlUsd": "0", "totalPnlUsd": "0.000000000000000000", "totalSellAmount": "0", "unrealizedPnlUsd": "0.000000000000000000", "cursor": "1" } ], "msg": "" } ```
- [Get Cluster Supported Chain](https://web3.okx.com/onchainos/dev-docs/market/market-token-cluster-supported-chain.md) {/* api-page */} # Get Cluster Supported Chain Get the supported chains ### Request Path GET `https://web3.okx.com/api/v6/dex/market/token/cluster/supported/chain` ## Request Parameters None ## Response Parameters | Field | Type | Description | |---|---|---| | chainIndex | String | Unique identifier of the chain | | chainName | String | Chain name | | chainLogo | String | Chain logo | ## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/token/cluster/supported/chain' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "chainIndex": "1", "chainName": "Ethereum", "chainLogo": "https://static.okx.com/cdn/wallet/logo/ETH-20220328.png" }, { "chainIndex": "501", "chainName": "Solana", "chainLogo": "https://static.okx.com/cdn/wallet/logo/SOL.png" } ], "msg": "" } ``` - [Get Token Holding Cluster Overview](https://web3.okx.com/onchainos/dev-docs/market/market-token-cluster-overview.md) {/* api-page */} # Get Token Holding Cluster Overview Get the holding cluster overview data for a specified token. ### Request Path GET `https://web3.okx.com/api/v6/dex/market/token/cluster/overview` ## Request Parameters | Parameter | Type | Required | Description | |---|---|---|---| | chainIndex | String | Yes | Unique chain identifier. Pass in the chain ID (e.g., 501 for Solana). Only supports single-chain queries | | tokenContractAddress | String | Yes | Token contract address | ## Response Parameters | Field | Type | Description | |---|---|---| | ClusterConcentration | String | Cluster concentration level: Low / Medium / High | | top100HoldingsPercent | String | Top 100 address holding percentage (%) | | rugPullPercent | String | Rug pull probability percentage (%) | | holderNewAddressPercent | String | Percentage of new addresses created within the past 3 days among the top 1000 holders (%) | | holderSameFundSourcePercent | String | Percentage of addresses among the top 1000 holders that have mutual mainstream token transactions with each other | | holderSameCreationTimePercent | String | Percentage of addresses created at the same time (%) | ## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/token/cluster/overview?chainIndex=1&tokenContractAddress=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "ClusterConcentration": "HIGH", "top100HoldingsPercent": "42.35", "rugPullPercent": "12.50", "holderNewAddressPercent": "8.20", "holderSameFundSourcePercent": "15.60", "holderSameCreationTimePercent": "6.80" } ], "msg": "" } ``` - [Get Token Cluster List](https://web3.okx.com/onchainos/dev-docs/market/market-token-cluster-list.md) {/* api-page */} # Get Token Cluster List Get the list of holding clusters for a specified token. Only includes address clusters within the top 300 holders. Limit: Returns only the top 100 clusters by holding amount ### Request Path GET `https://web3.okx.com/api/v6/dex/market/token/cluster/list` ## Request Parameters | Parameter | Type | Required | Description | |---|---|---|---| | chainIndex | string | Yes | Unique chain identifier. Pass in the chain ID (e.g., 501 for Solana). Only supports single-chain queries | | tokenContractAddress | string | Yes | Token contract address | ## Response Parameters | Field | Type | Description | |---|---|---| | clustList | array | Cluster list | | > holdingAmount | string | Total token holdings of cluster addresses (excluding black holes and liquidity pool addresses) | | > holdingValueUsd | string | Total USD value of token holdings of cluster addresses (excluding black holes and liquidity pool addresses) | | > holdingPercent | string | Percentage of token supply held by cluster addresses | | > trendType | object | Buy/Sell/Neutral/Transfer dominant. The overall direction of cluster traders' holdings over time — increasing (buying), decreasing (selling), flat (neutral), or primarily accumulated through transfers (transfer dominant) | | > averageHoldingPeriod | string | Weighted average holding period of cluster holders | | > pnlUsd | string | Total token PnL of cluster holders | | > pnlPercent | string | Total token PnL percentage of cluster holders | | > buyVolume | string | Value of tokens bought by cluster holders | | > averageBuyPriceUsd | string | Average cost price of cluster holders | | > sellVolume | string | Value of tokens sold by cluster holders | | > averageSellPriceUsd | string | Weighted average selling price of cluster holders | | > lastActiveTimestamp | string | Last active time | | > clusterAddressList | array | List of addresses in the cluster | | >> address | string | Address | | >> holdingAmount | string | Total token holdings of cluster addresses (excluding black holes and liquidity pool addresses) | | >> holdingValueUsd | string | Total USD value of token holdings of cluster addresses (excluding black holes and liquidity pool addresses) | | >> holdingPercent | string | Percentage of token supply held by cluster addresses | | >> averageHoldingPeriod | string | Average holding period of the address | | >> lastActiveTimestamp | string | Last active time | | >> isContract | boolean | Whether it is a contract address | | >> isExchange | boolean | Whether it is an exchange address | | >> isKol | boolean | Whether it is a KOL address | | >> addressRank | string | Address holding rank | ## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/token/cluster/list?chainIndex=1&tokenContractAddress=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "clustList": [ { "holdingAmount": "320000000.00", "holdingValueUsd": "320145600.00", "holdingPercent": "6.52", "trendType": { "trendType": "buy" }, "averageHoldingPeriod": "62", "pnlUsd": "45230.12", "pnlPercent": "14.15", "buyVolume": "980000.00", "averageBuyPriceUsd": "0.9982", "sellVolume": "210000.00", "averageSellPriceUsd": "1.0015", "lastActiveTimestamp": "1697630501000", "clusterAddressList": [ { "address": "0x28c6c06298d514db089934071355e5743bf21d60", "holdingAmount": "180000000.00", "holdingValueUsd": "180082800.00", "holdingPercent": "3.67", "averageHoldingPeriod": "75", "lastActiveTimestamp": "1697630501000", "isContract": false, "isExchange": true, "isKol": false, "addressRank": "1" } ] } ] } ], "msg": "" } ``` - [Get Token Top Holders Cluster Overview](https://web3.okx.com/onchainos/dev-docs/market/market-token-cluster-top-holders.md) {/* api-page */} # Get Token Top Holders Cluster Overview Get the overview data for the top 10/50/100 holding addresses of a specified token. ### Request Path GET `https://web3.okx.com/api/v6/dex/market/token/cluster/top-holders` ## Request Parameters | Parameter | Type | Required | Description | |---|---|---|---| | chainIndex | string | Yes | Unique chain identifier. Pass in the chain ID (e.g., 501 for Solana). Only supports single-chain queries | | tokenContractAddress | string | Yes | Token contract address | | rangeFilter | string | Yes | Data for the top 10/50/100 holding addresses. Values: 1=10, 2=50, 3=100 | ## Response Parameters | Field | Type | Description | |---|---|---| | holdingAmount | string | Total token holdings of the top 10/50/100 addresses (excluding black holes and liquidity pool addresses) | | holdingPercent | string | Percentage of token supply held by the top 10/50/100 addresses | | clusterTrendType | object | Buy/Sell/Neutral/Transfer dominant. The overall direction of traders' holdings over time — increasing (buying), decreasing (selling), flat (neutral), or primarily accumulated through transfers (transfer dominant) | | averageHoldingPeriod | string | Weighted average holding period of the top 10/50/100 holders | | averagePnlUsd | string | Weighted average PnL of the top 10/50/100 holders | | averageBuyPriceUsd | string | Weighted average cost price of the top 10/50/100 holders | | averageBuyPricePercent | string | Percentage difference between the average cost price of the top 10/50/100 holders and the current token price | | averageSellPriceUsd | string | Weighted average selling price of the top 10/50/100 holders | | averageSellPricePercent | string | Percentage difference between the average selling price of the top 10/50/100 holders and the current token price | ## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/token/cluster/top-holders?chainIndex=1&tokenContractAddress=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48&rangeFilter=2' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "holdingAmount": "1250000000.00", "holdingPercent": "25.40", "clusterTrendType": { "trendType": "buy" }, "averageHoldingPeriod": "45", "averagePnlUsd": "12340.56", "averageBuyPriceUsd": "0.9985", "averageBuyPricePercent": "-0.15", "averageSellPriceUsd": "1.0023", "averageSellPricePercent": "0.23" } ], "msg": "" } ``` - [Token Profit Address Information](https://web3.okx.com/onchainos/dev-docs/market/market-token-top-trader.md) {/* api-page */} # Token Profit Address Information Support viewing the top 100 profitable addresses and corresponding address information ### Request Path GET `https://web3.okx.com/api/v6/dex/market/token/top-trader` ## Request Parameters Return to the top 100 profitable addresses | Parameter | Type | Required | Description | |---|---|---|---| | chainIndex | String | Yes | Unique identifier of the chain. For example: `1`: Ethereum. | | tokenContractAddress | String | Yes | Token contract address (e.g. 0x382bb369d343125bfb2117af9c149795c6c65c50) | | tagFilter | String | No | Default: No input, return the address data of the top 100 profitable addresses, arranged in reverse order according to the realized income.
Enter 1: Return the holding address labeled KOL.
Enter 2: Return the token address labeled Developer
Enter 3: Return the holding address labeled Smart Money
Enter 4: Return the holding address labeled as Whale
Enter 5: Return the holding address labeled New Wallet
Enter 6: Return the holding address labeled Suspicious
Enter 7: Return the holding address labeled Sniper
Enter 8: Return the holding address labeled as Suspected phishing.
Enter 9: Return the holding address labeled Bundle | | cursor | String | No | Pagination cursor, pass the cursor value returned from the previous request | | limit | String | No | Number of records per page, max 100 |
## Response Parameters | Field | Type | Description | |---|---|---| | holderWalletAddress | String | Cash holding address | | cursor | String | Pagination cursor | | holdAmount | String | Number of coins held | | holdPercent | String | Percentage of holdings | | nativeTokenBalance | String | Mainnet currency balance | | boughtAmount | String | Total Buy Quantity | | avgBuyPrice | String | Average buying price | | soldAmount | String | Total sold quantity | | avgSellPrice | String | Average selling price | | totalPnlUsd | String | Total profit and loss | | realizedPnlUsd | String | Realized profit and loss | | unrealizedPnlUsd | String | Unrealized profit and loss | | fundingSource | String | Sources of funding |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/token/top-trader?chainIndex=501&tokenContractAddress=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v&tagFilter=1' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "avgBuyPrice": "0.000061961311739113", "avgSellPrice": "0.000122073405687202", "boughtAmount": "48443482.085545000000000000", "cursor": "0", "fundingSource": "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2", "holdAmount": "0", "holdPercent": "0.000000000000000000", "holderWalletAddress": "GHPyCYecXh398J72qi8nx9Sdaq8PiUJmLoL2q2yLwTY9", "nativeTokenBalance": "0.024254276", "realizedPnlUsd": "2912.039146298874538842343358", "soldAmount": "41626711.761828000000000000", "totalPnlUsd": "2912.039146298874538842343358", "unrealizedPnlUsd": "0.000000000000000000" }, { "avgBuyPrice": "0.000045836227988662", "avgSellPrice": "0.000117400306217832", "boughtAmount": "29120882.898397000000000000", "cursor": "1", "fundingSource": "FLipG5QHjZe1H12f6rr5LCnrmqjhwuBTBp78GwzxnwkR", "holdAmount": "0", "holdPercent": "0.000000000000000000", "holderWalletAddress": "HYSq1KBAvqWpEv1pCbV31muKM1za5A1WSHGdiVLUoNhb", "nativeTokenBalance": "37.572873625", "realizedPnlUsd": "2084.009141843422246184643326", "soldAmount": "29120882.898397000000000000", "totalPnlUsd": "2084.009141843422246184643326", "unrealizedPnlUsd": "0.000000000000000000" } ], "msg": "" } ```
- [Error Codes](https://web3.okx.com/onchainos/dev-docs/market/market-token-error-code.md) # Error Codes | Code | HTTP status | Message | |-------|-------------|-----------------------------------------------------------------------------------------| | 0 | 200 | Succeeded | | 50011 | 429 | Rate limit reached. Please refer to API documentation and throttle requests accordingly | | 50014 | 400 | Parameter \{param0\} cannot be empty | | 50026 | 500 | System error. Try again later | | 50103 | 401 | Request header "OK-ACCESS-KEY" cannot be empty | | 50104 | 401 | Request header "OK-ACCESS-PASSPHRASE" cannot be empty| | 50105 | 401 | Request header "OK-ACCESS-PASSPHRASE" incorrect | | 50106 | 401 | Request header "OK-ACCESS-SIGN" cannot be empty | | 50107 | 401 | Request header "OK-ACCESS-TIMESTAMP" cannot be empty | | 50111 | 401 | Invalid OK-ACCESS-KEY | | 50112 | 401 | Invalid OK-ACCESS-TIMESTAMP | | 50113 | 401 | Invalid signature | | 51000 | 400 | Parameter \{param0\} error | - [Signal API Reference](https://web3.okx.com/onchainos/dev-docs/market/market-signal-reference.md) # Signal API Reference - [Get Signal Supported Chains](https://web3.okx.com/onchainos/dev-docs/market/market-signal-chains.md) {/* api-page */} # Get Signal Supported Chains Returns a list of all blockchain networks supported by the Signal service. ## Request URL GET `https://web3.okx.com/api/v6/dex/market/signal/supported/chain` ## Request Parameters No ## Response Parameters | Parameter | Type | Description | |------------|--------|----------------------------| | chainIndex | String | Unique identifier of the chain. | | chainName | String | Chain name (e.g., Ethereum). | | chainLogo | String | Chain icon. | ## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/signal/supported/chain' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "chainIndex": "1", "chainLogo": "https://static.coinall.ltd/cdn/wallet/logo/ETH-20220328.png", "chainName": "Ethereum" }, { "chainIndex": "196", "chainLogo": "https://static.coinall.ltd/cdn/wallet/logo/okb_22400.png", "chainName": "X Layer" }, { "chainIndex": "501", "chainLogo": "https://static.coinall.ltd/cdn/wallet/logo/SOL-20220525.png", "chainName": "Solana" }, { "chainIndex": "8453", "chainLogo": "https://static.coinall.ltd/cdn/web3/dex/market/base_v2.png", "chainName": "Base" }, { "chainIndex": "56", "chainLogo": "https://static.coinall.ltd/cdn/web3/oklinkadmin/picture/new_bsc_chain_color.png", "chainName": "BNB Chain" } ], "msg": "" } ``` - [Get Latest Signal List](https://web3.okx.com/onchainos/dev-docs/market/market-signal-list.md) {/* api-page */} # Get Latest Signal List Retrieve the latest buy-direction token signal list on a specified chain, sorted in descending order by time. ## Request URL POST `https://web3.okx.com/api/v6/dex/market/signal/list` ## Request Parameters | Parameter | Type | Required | Description | |----------------------|---------|----------|-----------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier of the chain. Pass the chain ID (e.g., 1: Ethereum). Only single-chain queries are supported. | | walletType | String | No | Wallet type code. Enum: 1 = Smart Money, 2 = KOL / Influencer, 3 = Whales. Multiple values supported, separated by commas. | | minAmountUsd | String | No | Minimum total transaction amount (USD) for the selected wallet type(s). | | maxAmountUsd | String | No | Maximum total transaction amount (USD) for the selected wallet type(s). | | minAddressCount | String | No | Minimum number of addresses of the selected wallet type that triggered the signal. | | maxAddressCount | String | No | Maximum number of addresses of the selected wallet type that triggered the signal. | | tokenAddress | String | No | Token contract address. If provided, query the specified token; if not, return a filtered list within constraints. | | minMarketCapUsd | String | No | Minimum market cap (USD) of the token when the signal was triggered. | | maxMarketCapUsd | String | No | Maximum market cap (USD) of the token when the signal was triggered. | | minLiquidityUsd | String | No | Minimum liquidity (USD) of the token when the signal was triggered. | | maxLiquidityUsd | String | No | Maximum liquidity (USD) of the token when the signal was triggered. | | | cursor | String | No | Pagination cursor, pass the cursor value returned from the previous request | | limit | String | No | Number of records per page, max 100 | ## Response Parameters | Parameter | Type | Description | |-------------------------|---------|-------------| | timestamp | String | Timestamp when the signal was triggered. | | cursor | String | Pagination cursor | | chainIndex | String | Unique identifier of the chain. | | token | Object | Token information. | | >tokenAddress | String | Token address. | | >symbol | String | Token symbol. | | >name | String | Token name. | | >logo | String | Token logo. | | >marketCapUsd | String | Market cap in USD. | | >holders | String | Number of holder addresses. | | >top10HolderPercent | String | Top 10 holder percentage. | | price | String | Token price in USD when the signal was triggered. | | walletType | String | Wallet type. Enum: SMART_MONEY / WHALE / INFLUENCER. | | triggerWalletCount | String | Number of triggering wallet addresses. | | triggerWalletAddress | String | List of triggering wallet addresses, separated by commas. | | amountUsd | String | Transaction amount in USD. | | soldRatioPercent | String | Sold percentage. | ## Request Example ```shell curl --location --request POST 'https://web3.okx.com/api/v6/dex/market/signal/list' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '[ { "chainIndex": "501", "walletType": "1,2,3", "minAmountUsd": "1000", "maxAmountUsd": "500000", "minAddressCount": "2", "maxAddressCount": "50", "tokenAddress": "", "minMarketCapUsd": "168564", "maxMarketCapUsd": "", "minLiquidityUsd": "333", "maxLiquidityUsd": "" } ]' ``` ## Response Example ```json { "code": "0", "data": [ { "amountUsd": "669.455417761799554132", "chainIndex": "501", "price": "0.000122496972899498", "soldRatioPercent": "64.29", "timestamp": "1774364940575", "token": { "holders": "445", "logo": "https://static.oklink.com/cdn/web3/currency/token/pre/large/501-FN9ZSeNDdPV6bBF9DeDYxvqYK4JvFKeF7DBrhGGXJZ3Q-109/type=webp_90_0?v=1774292374274", "marketCapUsd": "64466.670905193533007211", "name": "Van Cleef Memes", "symbol": "VanCleef", "tokenAddress": "FN9ZSeNDdPV6bBF9DeDYxvqYK4JvFKeF7DBrhGGXJZ3Q", "top10HolderPercent": "17.9547" }, "triggerWalletAddress": "5jds1qi6nYu2JTZv5YTczPwyaq1RAkNkjbpsma8xSTem,4YzpSZpxDdjNf3unjkCtdWEsz2FL5mok7e5XQaDNqry8,F8sHTSpZpoNB7H2JUZ7tmMb2YWRM1pXiHPuubHVRDSsB", "triggerWalletCount": "3", "walletType": "2", "cursor": "1774364940575!@#123" }, { "amountUsd": "1912.742277985131470193", "chainIndex": "501", "price": "0.000043905847119596", "soldRatioPercent": "74.73", "timestamp": "1774350239648", "token": { "holders": "1112", "logo": "https://static.oklink.com/cdn/web3/currency/token/pre/large/501-AytNmHWe8uXfgBACLnvhyKWrecAcYFywLK2nXbegpump-109/type=webp_90_0?v=1774359780606", "marketCapUsd": "127139.702497190490981742", "name": "The Sandwich Heist", "symbol": "Sandwich", "tokenAddress": "AytNmHWe8uXfgBACLnvhyKWrecAcYFywLK2nXbegpump", "top10HolderPercent": "18.4131" }, "triggerWalletAddress": "As7HjL7dzzvbRbaD3WCun47robib2kmAKRXMvjHkSMB5,719sfKUjiMThumTt2u39VMGn612BZyCcwbM5Pe8SqFYz,3L8RAxLkvwkz4CgHivaVRtq19741FAdGLk5DgjRfc1fW,9FNz4MjPUmnJqTf6yEDbL1D4SsHVh7uA8zRHhR5K138r,FRbUNvGxYNC1eFngpn7AD3f14aKKTJVC6zSMtvj2dyCS,6iM1Ljh8zkY9Vxw6VqHmm9HJ3axD4f9yYpXnSCi22hvY", "triggerWalletCount": "6", "walletType": "2", "cursor": "1774350239648!@#123" // pass this for next pagination } ] } ``` - [Get Leaderboard Supported Chain List](https://web3.okx.com/onchainos/dev-docs/market/market-signal-leaderboard-supported-chain.md) {/* api-page */} # Get Leaderboard Supported Chain List Get the list of supported chains ### Request Path GET `https://web3.okx.com/api/v6/dex/market/leaderboard/supported/chain` ## Request Parameters None ## Response Parameters | Field | Type | Description | |---|---|---| | chainIndex | String | Unique identifier of the chain | | chainName | String | Chain name | | chainLogo | String | Chain logo URL | ## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/leaderboard/supported/chain' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "chainIndex": "1", "chainName": "Ethereum", "chainLogo": "https://static.okx.com/cdn/wallet/logo/ETH-20220328.png" }, { "chainIndex": "501", "chainName": "Solana", "chainLogo": "https://static.okx.com/cdn/wallet/logo/SOL.png" } ], "msg": "" } ``` - [Get Smart Money Leaderboard List](https://web3.okx.com/onchainos/dev-docs/market/market-signal-leaderboard-list.md) {/* api-page */} # Get Smart Money Leaderboard List Retrieve the Smart Money leaderboard according to specified sorting and filter options; can be used in conjunction with the Signal API. Limit: Maximum 20 records per request ### Request Path GET `https://web3.okx.com/api/v6/dex/market/leaderboard/list` ## Request Parameters | Parameter | Type | Required | Description | |---|---|---|---| | chainIndex | string | Yes | Unique chain identifier (e.g., 1 for Ethereum). Only supports single-chain queries | | timeFrame | string | Yes | Address transactions and PnL timeframe index (i.e. 1=1D, 2=3D, 3=7D, 4=1M, 5=3M) | | sortBy | string | Yes | Sorting according to the selected timeFrame: PnL, ProfitRate, WinRate, TxVolume, TxCount. 1=Pnl, 2=Win Rate, 3=Tx number, 4=Volume, 5=ROI (profit rate) | | walletType | string | No | Wallet type index. Enum: 1 = KOL, 2 = Developer, 3 = Smart Money, 4 = Whale, 5 = New Wallet, 6 = Insider (Mouse Position), 7 = Sniper, 8 = Suspected Phishing, 9 = Bundled Trader, 10 = Pump Smart Money. Supports single selection. If not provided, rankings for all wallet types will be returned. | | minRealizedPnlUsd | string | No | Minimum realized profit and loss amount (USD) | | maxRealizedPnlUsd | string | No | Maximum realized profit and loss amount (USD) | | minWinRatePercent | string | No | Minimum win rate percentage | | maxWinRatePercent | string | No | Maximum win rate percentage | | minTxs | string | No | Minimum number of transactions | | maxTxs | string | No | Maximum number of transactions | | minTxVolume | string | No | Minimum transaction volume (USD) | | maxTxVolume | string | No | Maximum transaction volume (USD) | ## Response Parameters | Field | Type | Description | |---|---|---| | walletAddress | string | Wallet address | | realizedPnlUsd | string | Accumulated realized PnL USD value for completed transactions within the selected timeframe | | realizedPnlPercent | string | Accumulated realized PnL percentage for completed transactions within the selected timeframe | | winRatePercent | string | The percentage of profitable tokens relative to the total number of tokens traded | | avgBuyValueUsd | string | Average buy value | | topPnlTokenList | array | Top 3 token list by PnL | | > tokenContractAddress | string | Token contract address | | > tokenSymbol | string | Token symbol | | > tokenPnlUsd | string | Token PnL in USD | | > tokenPnlPercent | string | Token PnL percentage | | txVolume | string | Transaction volume in USD within the selected timeframe | | txs | string | Transaction count within the selected timeframe | | lastActiveTimestamp | string | Last active time | ## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/leaderboard/list?chainIndex=501&timeFrame=1&sortBy=1' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "walletAddress": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU", "realizedPnlUsd": "125430.56", "realizedPnlPercent": "312.45", "winRatePercent": "68.5", "avgBuyValueUsd": "2340.00", "topPnlTokenList": [ { "tokenContractAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "tokenSymbol": "USDC", "tokenPnlUsd": "45230.12", "tokenPnlPercent": "156.78" }, { "tokenContractAddress": "So11111111111111111111111111111111111111112", "tokenSymbol": "SOL", "tokenPnlUsd": "38120.00", "tokenPnlPercent": "98.34" }, { "tokenContractAddress": "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263", "tokenSymbol": "BONK", "tokenPnlUsd": "20450.88", "tokenPnlPercent": "204.60" } ], "txVolume": "890234.50", "txs": "342", "lastActiveTimestamp": "1697630501000" } ], "msg": "" } ``` - [Trenches API Reference](https://web3.okx.com/onchainos/dev-docs/market/market-scan-chain-api-reference.md) # Trenches API Reference - [Get Supported Chains and Protocols](https://web3.okx.com/onchainos/dev-docs/market/market-memepump-get-supported-chains-and-protocols.md) {/* api-page */} # Get Supported Chains and Protocols Retrieve the list of chains and their corresponding protocols supported by Meme Pump. ## Request URL GET `https://web3.okx.com/api/v6/dex/market/memepump/supported/chainsProtocol` ## Request Parameters None ## Response Parameters | Parameter | Type | Description | |-----------------|--------|--------------------------------------------------------------| | chainIndex | String | Chain unique identifier (e.g., `501` = Solana, `56` = BSC). | | chainName | String | Chain name(eg.Ethereum) | | protocolList | Array | List of supported protocols on this chain. | | >protocolId | String | Protocol ID (e.g., `1` = PUMP_FUN). | | >protocolName | String | Protocol name (e.g., `PUMP_FUN`, `SUNPUMP`). | ## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/memepump/supported/chainsProtocol' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "msg": "", "data": [ { "chainIndex": "501", "chainName": "Solana", "protocolList": [ { "protocolId": "1", "protocolName": "PUMP_FUN" }, { "protocolId": "2", "protocolName": "MOONSHOT" } ] }, { "chainIndex": "56", "chainName": "BSC", "protocolList": [ { "protocolId": "3", "protocolName": "SUNPUMP" } ] } ] } ``` - [Get Token List](https://web3.okx.com/onchainos/dev-docs/market/market-memepump-get-token-list.md) {/* api-page */} # Get Token List Retrieve the list of tokens matching specified filter criteria,with a maximum limit of 30 entries. ## Request URL GET `https://web3.okx.com/api/v6/dex/market/memepump/tokenList` ## Request Parameters | Parameter | Type | Required | Description | |---|---|---|---| | chainIndex | String | Yes | Unique identifier for the blockchain network. e.g., `501` = Solana, `56` = BSC. Only single-chain queries are supported. | | stage | String | Yes | Token lifecycle stage filter. Enum: `NEW` = newly created tokens, `MIGRATING` = tokens nearly migrated to DEX, `MIGRATED` = tokens that have completed migration to DEX. | | walletAddress | String | No | User's wallet address. When provided, response will include user-specific position data (e.g., holdings, P&L). | | protocolIdList | String | No | Comma-separated protocol IDs to filter by. e.g., `"120596"` for PumpFun, `"120596,139661"` for multiple protocols. Get available protocol IDs from `/memepump/supported/chainsProtocol`. | | quoteTokenAddressList | String | No | Comma-separated quote token contract addresses to filter by. e.g., `"So11111111111111111111111111111111111111111"` for SOL. Filters tokens by their trading pair's quote currency. | | minTop10HoldingsPercent | String | No | Minimum percentage of total supply held by top 10 holders. Value range: 0–100. e.g., `"10"` means top 10 holders hold at least 10%. | | maxTop10HoldingsPercent | String | No | Maximum percentage of total supply held by top 10 holders. Value range: 0–100. | | minDevHoldingsPercent | String | No | Minimum percentage of total supply held by the developer wallet. Value range: 0–100. | | maxDevHoldingsPercent | String | No | Maximum percentage of total supply held by the developer wallet. Value range: 0–100. | | minInsidersPercent | String | No | Minimum percentage of insider wallets among all holders. Value range: 0–100. | | maxInsidersPercent | String | No | Maximum percentage of insider wallets among all holders. Value range: 0–100. | | minBundlersPercent | String | No | Minimum percentage of bundler wallets among all holders. Value range: 0–100. Bundlers are wallets that bundle multiple transactions together. | | maxBundlersPercent | String | No | Maximum percentage of bundler wallets among all holders. Value range: 0–100. | | minSnipersPercent | String | No | Minimum percentage of sniper wallets among all holders. Value range: 0–100. Snipers are wallets that buy tokens extremely early after launch. | | maxSnipersPercent | String | No | Maximum percentage of sniper wallets among all holders. Value range: 0–100. | | minFreshWalletsPercent | String | No | Minimum percentage of fresh (newly created) wallets among all holders. Value range: 0–100. | | maxFreshWalletsPercent | String | No | Maximum percentage of fresh (newly created) wallets among all holders. Value range: 0–100. | | minSuspectedPhishingWalletPercent | String | No | Minimum percentage of suspected phishing wallets among all holders. Value range: 0–100. | | maxSuspectedPhishingWalletPercent | String | No | Maximum percentage of suspected phishing wallets among all holders. Value range: 0–100. | | minBotTraders | String | No | Minimum number of bot trader wallets. | | maxBotTraders | String | No | Maximum number of bot trader wallets. | | minDevMigrated | String | No | Minimum number of tokens previously migrated by the same developer. Useful for evaluating dev history. | | maxDevMigrated | String | No | Maximum number of tokens previously migrated by the same developer. | | communityTakeover | Boolean | No | Filter by whether the token has undergone a community takeover (CTO). `true` = only CTO tokens, `false` = only non-CTO tokens. | | minFeesNative | String | No | Minimum total fees spent on the token, denominated in native chain currency (e.g., SOL). | | maxFeesNative | String | No | Maximum total fees spent on the token, denominated in native chain currency. | | minTxCount | String | No | Minimum total transaction count for the token. | | maxTxCount | String | No | Maximum total transaction count for the token. | | minBondingPercent | String | No | Minimum bonding curve completion percentage. Value range: 0–100. Applicable when `stage=NEW` or `stage=MIGRATING`. | | maxBondingPercent | String | No | Maximum bonding curve completion percentage. Value range: 0–100. | | minMarketCapUsd | String | No | Minimum market capitalization in USD. e.g., `"50000"` means market cap ≥ $50,000. | | maxMarketCapUsd | String | No | Maximum market capitalization in USD. | | minVolumeUsd | String | No | Minimum 24-hour trading volume in USD. | | maxVolumeUsd | String | No | Maximum 24-hour trading volume in USD. | | minHolders | String | No | Minimum number of unique token holders. e.g., `"100"` means at least 100 holders. | | maxHolders | String | No | Maximum number of unique token holders. | | minTokenAge | String | No | Minimum token age in minutes. When `stage=MIGRATED`, counted from migration timestamp; otherwise from creation timestamp. e.g., `"60"` means at least 1 hour old. | | maxTokenAge | String | No | Maximum token age in minutes. When `stage=MIGRATED`, counted from migration timestamp; otherwise from creation timestamp. | | minBuyTxCount | String | No | Minimum number of buy transactions in the last 1 hour. | | maxBuyTxCount | String | No | Maximum number of buy transactions in the last 1 hour. | | minSellTxCount | String | No | Minimum number of sell transactions in the last 1 hour. | | maxSellTxCount | String | No | Maximum number of sell transactions in the last 1 hour. | | minTokenSymbolLength | String | No | Minimum length of the token ticker symbol. e.g., `"3"` means symbol has at least 3 characters. | | maxTokenSymbolLength | String | No | Maximum length of the token ticker symbol. | | hasAtLeastOneSocialLink | Boolean | No | Filter by whether the token has at least one social media link. `true` = must have at least one social link. | | hasX | Boolean | No | Filter by whether the token has an X (Twitter) link. `true` = must have X link. | | hasTelegram | Boolean | No | Filter by whether the token has a Telegram link. `true` = must have Telegram link. | | hasWebsite | Boolean | No | Filter by whether the token has an official website link. `true` = must have a website. | | websiteTypeList | String | No | Comma-separated website type codes. Enum: `0` = official website, `1` = YouTube, `2` = Twitch, `3` = Facebook, `4` = Instagram, `5` = TikTok, `6` = Discord, `7` = GitHub. e.g., `"1,6"` for tokens with YouTube or Discord links. | | dexScreenerPaid | Boolean | No | Filter by whether the token has paid for DexScreener promotion. `true` = only tokens that have paid for DexScreener. | | liveOnPumpFun | Boolean | No | Filter by whether the token is currently live streaming on PumpFun. `true` = only tokens with active PumpFun live stream. | | bagsFeeClaimed | Boolean | No | Filter by whether the developer has claimed bags fees (royalties). `true` = developer has claimed fees. | | devSellAll | Boolean | No | Filter by whether the developer has sold all their token holdings. `true` = developer has sold everything. | | devStillHolding | Boolean | No | Filter by whether the developer is still holding tokens. `true` = developer still holds tokens. | | keywordsInclude | String | No | Filter tokens whose name or symbol contains the specified keyword. Case-insensitive. e.g., `"dog"` matches `"DOGE"`, `"DogWifHat"`. | | keywordsExclude | String | No | Exclude tokens whose name or symbol contains the specified keyword. Case-insensitive. | ## Response Parameters | Parameter | Type | Description | |------------------------------------|---------|-------------------------------------------------------------------------------| | cursor | String | Pagination cursor for the next page. Empty if no more data. | | items | Array | Token list. | | >chainIndex | String | Chain ID (e.g., `501` = Solana). | | >protocolId | String | Protocol ID (e.g., `1` = PUMP_FUN). | | >quoteTokenAddress | String | Quote token contract address. | | >tokenContractAddress | String | Token contract address. | | >symbol | String | Token symbol. | | >name | String | Token name. | | >logoUrl | String | Token logo URL. | | >createdTimestamp | String | Token creation time (millisecond timestamp). | | >market | Object | Market data. | | >>marketCapUsd | String | Market cap (USD). | | >>volumeUsd1h | String | 1h trading volume (USD). | | >>txCount1h | String | 1h total transaction count. | | >>buyTxCount1h | String | 1h buy transaction count. | | >>sellTxCount1h | String | 1h sell transaction count. | | >bondingPercent | String | Bonding curve progress (%). | | >mayhemModeTimeRemaining | String | Pump.fun Mayhem Mode remaining time. Empty if not applicable. | | >tags | Object | Audit / tag data. | | >>top10HoldingsPercent | String | Top 10 holders' combined holdings (%). | | >>devHoldingsPercent | String | Developer holdings (%). | | >>insidersPercent | String | Insiders holdings (%). | | >>bundlersPercent | String | Bundlers holdings (%). | | >>snipersPercent | String | Snipers holdings (%). | | >>freshWalletsPercent | String | Fresh wallets holdings (%). | | >>suspectedPhishingWalletPercent | String | Suspected phishing wallets (%). | | >>totalHolders | String | Total number of holder addresses. | | >social | Object | Social media info. | | >>x | String | X (Twitter) link. | | >>telegram | String | Telegram link. | | >>website | String | Website link. | | >>websiteType | String | Website type identifier. | | >>dexScreenerPaid | Boolean | Whether DEX Screener ads are active. | | >>communityTakeover | Boolean | Community takeover (CTO) flag. | | >>liveOnPumpFun | Boolean | Live on Pump.fun flag. | | >bagsFeeClaimed | Boolean | Whether bags fee has been claimed. | | >aped | String | Number of co-invested (aped) wallets. | | >migratedBeginTimestamp | String | Migration start time (ISO 8601). | | >migratedEndTimestamp | String | Migration end time (ISO 8601). | | >creatorAddress | String | Token creator wallet address. | ## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/memepump/tokenList?chainIndex=501&protocolId=1&sort=createdTimestamp&order=desc&limit=30' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "msg": "", "data": { "cursor": "eyJsYXN0SWQiOiI3R2Y5Li4ucHVtcCJ9", "items": [ { "chainIndex": "501", "protocolId": "1", "quoteTokenAddress": "11111111111111111111111111111111", "tokenContractAddress": "7Gf9...pump", "symbol": "TETANUS", "name": "tetanus", "logoUrl": "https://static.okx.com/cdn/assets/imgs/xxx.png", "createdTimestamp": "1730000000000", "market": { "marketCapUsd": "154880.12", "volumeUsd1h": "50231.11", "txCount1h": "225", "buyTxCount1h": "128", "sellTxCount1h": "97" }, "bondingPercent": "63.5", "mayhemModeTimeRemaining": "", "tags": { "top10HoldingsPercent": "0.12", "devHoldingsPercent": "0.10", "insidersPercent": "0.23", "bundlersPercent": "0.48", "snipersPercent": "0.35", "freshWalletsPercent": "0.50", "suspectedPhishingWalletPercent": "0.00", "totalHolders": "2080" }, "social": { "x": "https://x.com/xxxx", "telegram": "https://t.me/xxxx", "website": "https://xxxx.com", "websiteType": "1", "dexScreenerPaid": false, "communityTakeover": false, "liveOnPumpFun": true }, "bagsFeeClaimed": false, "aped": "12", "migratedBeginTimestamp": "", "migratedEndTimestamp": "", "creatorAddress": "3kXoZt...q1Re" } ] } } ``` - [Get Token Details](https://web3.okx.com/onchainos/dev-docs/market/market-memepump-get-token-details.md) {/* api-page */} # Get Token Details Retrieve Meme Pump scanner data for a specified token. ## Request URL GET `https://web3.okx.com/api/v6/dex/market/memepump/tokenDetails` ## Request Parameters | Parameter | Type | Required | Description | |-----------------------|--------|----------|------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Chain unique identifier (e.g., `501` = Solana). Only single-chain queries are supported. | | tokenContractAddress | String | Yes | Token contract address. | | walletAddress | String | Yes | User's wallet address. When provided, response will include user-specific position and P&L data for this token. | ## Response Parameters Same fields as individual items in the [Get Token List](#get-token-list) response, returned as a single object. | Parameter | Type | Description | |------------------------------------|---------|-------------------------------------------------------------------------------| | chainIndex | String | Chain ID (e.g., `501` = Solana). | | protocolId | String | Protocol ID (e.g., `1` = PUMP_FUN). | | quoteTokenAddress | String | Quote token contract address. | | tokenContractAddress | String | Token contract address. | | symbol | String | Token symbol. | | name | String | Token name. | | logoUrl | String | Token logo URL. | | createdTimestamp | String | Token creation time (millisecond timestamp). | | market | Object | Market data. | | >marketCapUsd | String | Market cap (USD). | | >volumeUsd1h | String | 1h trading volume (USD). | | >txCount1h | String | 1h total transaction count. | | >buyTxCount1h | String | 1h buy transaction count. | | >sellTxCount1h | String | 1h sell transaction count. | | bondingPercent | String | Bonding curve progress (%). | | mayhemModeTimeRemaining | String | Pump.fun Mayhem Mode remaining time. Empty if not applicable. | | tags | Object | Audit / tag data. | | >top10HoldingsPercent | String | Top 10 holders' combined holdings (%). | | >devHoldingsPercent | String | Developer holdings (%). | | >insidersPercent | String | Insiders holdings (%). | | >bundlersPercent | String | Bundlers holdings (%). | | >snipersPercent | String | Snipers holdings (%). | | >freshWalletsPercent | String | Fresh wallets holdings (%). | | >suspectedPhishingWalletPercent | String | Suspected phishing wallets (%). | | >totalHolders | String | Total number of holder addresses. | | social | Object | Social media info. | | >x | String | X (Twitter) link. | | >telegram | String | Telegram link. | | >website | String | Website link. | | >websiteType | String | Website type identifier. | | >dexScreenerPaid | Boolean | Whether DEX Screener ads are active. | | >communityTakeover | Boolean | Community takeover (CTO) flag. | | >liveOnPumpFun | Boolean | Live on Pump.fun flag. | | bagsFeeClaimed | Boolean | Whether bags fee has been claimed. | | aped | String | Number of co-invested (aped) wallets. | | migratedBeginTimestamp | String | Migration start time (ISO 8601). | | migratedEndTimestamp | String | Migration end time (ISO 8601). | | creatorAddress | String | Token creator wallet address. | ## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/memepump/tokenDetails?chainIndex=501&tokenContractAddress=7Gf9...pump' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "msg": "", "data": { "chainIndex": "501", "protocolId": "1", "quoteTokenAddress": "11111111111111111111111111111111", "tokenContractAddress": "7Gf9...pump", "symbol": "TETANUS", "name": "tetanus", "logoUrl": "https://static.okx.com/cdn/assets/imgs/xxx.png", "createdTimestamp": "1730000000000", "market": { "marketCapUsd": "154880.12", "volumeUsd1h": "50231.11", "txCount1h": "225", "buyTxCount1h": "128", "sellTxCount1h": "97" }, "bondingPercent": "63.5", "mayhemModeTimeRemaining": "", "tags": { "top10HoldingsPercent": "0.12", "devHoldingsPercent": "0.10", "insidersPercent": "0.23", "bundlersPercent": "0.48", "snipersPercent": "0.35", "freshWalletsPercent": "0.50", "suspectedPhishingWalletPercent": "0.00", "totalHolders": "2080" }, "social": { "x": "https://x.com/xxxx", "telegram": "https://t.me/xxxx", "website": "https://xxxx.com", "websiteType": "1", "dexScreenerPaid": false, "communityTakeover": false, "liveOnPumpFun": true }, "bagsFeeClaimed": false, "aped": "12", "migratedBeginTimestamp": "", "migratedEndTimestamp": "", "creatorAddress": "3kXoZt...q1Re" } } ``` - [Get Token Developer Info](https://web3.okx.com/onchainos/dev-docs/market/market-memepump-get-token-developer-info.md) {/* api-page */} # Get Token Developer Info Retrieve developer-related data for a specified token. ## Request URL GET `https://web3.okx.com/api/v6/dex/market/memepump/tokenDevInfo` ## Request Parameters | Parameter | Type | Required | Description | |-----------------------|--------|----------|------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Chain unique identifier (e.g., `501` = Solana). Only single-chain queries are supported. | | tokenContractAddress | String | Yes | Token contract address. | ## Response Parameters | Parameter | Type | Description | |-----------------------|--------|------------------------------------------------------------------------| | devLaunchedInfo | Object | Summary of tokens launched by this developer. | | >totalToken | String | Total number of tokens launched by this developer. | | >rugPullCount | String | Number of rug pulls. | | >migratedCount | String | Number of successfully migrated tokens. | | >goldenGemCount | String | Number of golden gem tokens. | | devHoldingInfo | Object | Developer's current holding info for this token. | | >devHoldingPercent | String | Developer's current holdings (%). | | >devAddress | String | Developer wallet address. | | >fundingAddress | String | Funding source wallet address. | | >devBalance | String | Developer's native token balance. | | >lastFundedTimestamp | String | Last time the developer wallet was funded (ISO 8601). | ## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/memepump/tokenDevInfo?chainIndex=501&tokenContractAddress=7Gf9...pump' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "msg": "", "data": { "devLaunchedInfo": { "totalToken": "18", "rugPullCount": "3", "migratedCount": "11", "goldenGemCount": "2" }, "devHoldingInfo": { "devHoldingPercent": "2.35", "devAddress": "3kXoZt...q1Re", "fundingAddress": "Fv8N...tuQ", "devBalance": "0.064", "lastFundedTimestamp": "2025-06-26T06:37:39Z" } } } ``` - [Get Similar Tokens](https://web3.okx.com/onchainos/dev-docs/market/market-memepump-get-similar-tokens.md) {/* api-page */} # Get Similar Tokens Retrieve tokens similar to the specified token. ## Request URL GET `https://web3.okx.com/api/v6/dex/market/memepump/similarToken` ## Request Parameters | Parameter | Type | Required | Description | |-----------------------|--------|----------|------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Chain unique identifier (e.g., `501` = Solana). Only single-chain queries are supported. | | tokenContractAddress | String | Yes | Token contract address. | ## Response Parameters | Parameter | Type | Description | |-----------------------|--------|--------------------------------------------------| | similarToken | Array | List of similar tokens. | | >tokenContractAddress | String | Token contract address. | | >tokenSymbol | String | Token symbol. | | >tokenLogo | String | Token logo URL. | | >marketCapUsd | String | Market cap (USD). | | >lastTxTimestamp | String | Last transaction time (ISO 8601). | | >createdTimestamp | String | Token creation time (ISO 8601). | ## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/memepump/similarToken?chainIndex=501&tokenContractAddress=7Gf9...pump' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "msg": "", "data": { "similarToken": [ { "tokenContractAddress": "8Hd92...xYp1", "tokenSymbol": "TETAX", "tokenLogo": "https://static.okx.com/cdn/assets/imgs/tetax.png", "marketCapUsd": "245800.32", "lastTxTimestamp": "2025-03-08T12:45:21Z", "createdTimestamp": "2025-03-01T08:00:00Z" }, { "tokenContractAddress": "9Ks81...LpQ9", "tokenSymbol": "TETAN", "tokenLogo": "https://static.okx.com/cdn/assets/imgs/tetan.png", "marketCapUsd": "158920.00", "lastTxTimestamp": "2025-03-08T12:40:10Z", "createdTimestamp": "2025-02-28T15:12:00Z" } ] } } ``` - [Get Token Bundle Details](https://web3.okx.com/onchainos/dev-docs/market/market-memepump-get-token-bundle-details.md) {/* api-page */} # Get Token Bundle Details Retrieve bundler-related data for a specified token. ## Request URL GET `https://web3.okx.com/api/v6/dex/market/memepump/tokenBundleInfo` ## Request Parameters | Parameter | Type | Required | Description | |-----------------------|--------|----------|------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Chain unique identifier (e.g., `501` = Solana). Only single-chain queries are supported. | | tokenContractAddress | String | Yes | Token contract address. | ## Response Parameters | Parameter | Type | Description | |----------------------|--------|-----------------------------------------------------| | bundlerAthPercent | String | Bundlers' all-time-high combined holdings (%). | | totalBundlers | String | Total number of bundler addresses. | | bundledValueNative | String | Total bundled amount in native token. | | bundledTokenAmount | String | Total bundled token amount. | ## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/memepump/tokenBundleInfo?chainIndex=501&tokenContractAddress=7Gf9...pump' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "msg": "", "data": { "bundlerAthPercent": "0.92", "totalBundlers": "9", "bundledValueNative": "375", "bundledTokenAmount": "4880000" } } ``` - [Get Token Aped Wallet Details](https://web3.okx.com/onchainos/dev-docs/market/market-memepump-get-token-aped-wallet-details.md) {/* api-page */} # Get Token Aped Wallet Details Retrieve co-invested ("aped") wallet data for a specified token,with a maximum limit of 50 entries. ## Request URL GET `https://web3.okx.com/api/v6/dex/market/memepump/apedWallet` ## Request Parameters | Parameter | Type | Required | Description | |---|---|---|---| | chainIndex | String | Yes | Unique identifier for the blockchain network. e.g., `501` = Solana, `56` = BSC. Only single-chain queries are supported. | | tokenContractAddress | String | Yes | The contract address of the token to query aped wallet list for. | | walletAddress | String | No | User's wallet address. When provided, the response will highlight whether the user's wallet is among the aped wallets. | ## Response Parameters | Parameter | Type | Description | |------------------|--------|----------------------------------------------------------------------| | apedWalletList | Array | List of co-invested wallets. | | >walletAddress | String | Wallet address. | | >walletType | String | Wallet type. Enum: `SMART_MONEY`, `INFLUENCER`, `NORMAL`. | | >holdingUsd | String | Current holdings value (USD). | | >holdingPercent | String | Current holdings as a percentage of total supply (%). | | >totalPnl | String | Total profit and loss (USD). | | >pnlPercent | String | PnL as a percentage (%). | ## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/memepump/apedWallet?chainIndex=501&tokenContractAddress=7Gf9...pump' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "msg": "", "data": { "apedWalletList": [ { "walletAddress": "9xK3ab...Tg91", "walletType": "SMART_MONEY", "holdingUsd": "12450.32", "holdingPercent": "1.28", "totalPnl": "5320.11", "pnlPercent": "74.32" }, { "walletAddress": "3Lm92Q...Hs77", "walletType": "INFLUENCER", "holdingUsd": "8420.50", "holdingPercent": "0.86", "totalPnl": "2100.00", "pnlPercent": "33.18" } ] } } ``` - [Error Codes](https://web3.okx.com/onchainos/dev-docs/market/market-scan-chain-error-code.md) # Error Codes | Code | HTTP status | Message | |-------|-------------|-----------------------------------------------------------------------------------------| | 0 | 200 | Succeeded | | 50011 | 429 | Rate limit reached. Please refer to API documentation and throttle requests accordingly | | 50014 | 400 | Parameter \{param0\} cannot be empty | | 50026 | 500 | System error. Try again later | | 50103 | 401 | Request header "OK-ACCESS-KEY" cannot be empty | | 50104 | 401 | Request header "OK-ACCESS-PASSPHRASE" cannot be empty| | 50105 | 401 | Request header "OK-ACCESS-PASSPHRASE" incorrect | | 50106 | 401 | Request header "OK-ACCESS-SIGN" cannot be empty | | 50107 | 401 | Request header "OK-ACCESS-TIMESTAMP" cannot be empty | | 50111 | 401 | Invalid OK-ACCESS-KEY | | 50112 | 401 | Invalid OK-ACCESS-TIMESTAMP | | 50113 | 401 | Invalid signature | | 51000 | 400 | Parameter \{param0\} error | - [API Reference](https://web3.okx.com/onchainos/dev-docs/market/market-portfolio-reference.md) # API Reference - [Get Supported Chains](https://web3.okx.com/onchainos/dev-docs/market/market-portfolio-supported-chain.md) {/* api-page */} # Get Supported Chains Get the list of currently supported chains. ### Request Path GET `https://web3.okx.com/api/v6/dex/market/portfolio/supported/chain` ## Request Parameters None ## Response Parameters | Parameter | Type | Description | |---|---|---| | chainIndex | String | Unique identifier of the chain | | chainName | String | Chain name | | chainLogo | String | Chain logo URL | ## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/portfolio/supported/chain' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "chainIndex": "1", "chainName": "Ethereum", "chainLogo": "https://static.okx.com/cdn/wallet/logo/ETH-20220328.png" }, { "chainIndex": "501", "chainName": "Solana", "chainLogo": "https://static.okx.com/cdn/wallet/logo/SOL.png" } ], "msg": "" } ``` - [Get Address Portfolio Overview](https://web3.okx.com/onchainos/dev-docs/market/market-portfolio-overview.md) {/* api-page */} # Get Address Portfolio Overview Get overview data related to address PnL, including total realized and unrealized PnL, winning rate, Top3 PnL tokens, and buy and sell transaction statistics ### Request Path GET `https://web3.okx.com/api/v6/dex/market/portfolio/overview` ## Request Parameters | Parameter | Type | Required | Description | |---|---|---|---| | chainIndex | String | Yes | Unique identifier of the chain, pass the chain ID (e.g., 501 for Solana), only single-chain query is supported | | walletAddress | String | Yes | Wallet address to query | | timeFrame | String | Yes | Statistical range number for address transactions and PnL (1=1D, 2=3D, 3=7D, 4=1M, 5=3M) | ## Response Parameters | Parameter | Type | Description | |---|---|---| | realizedPnlUsd | String | Realized PnL (USD) | | top3PnlTokenSumUsd | String | Total PnL of Top 3 tokens (USD) | | top3PnlTokenPercent | String | Top 3 tokens PnL percentage | | topPnlTokenList | Array | Top 3 PnL token list | | >tokenContractAddress | String | Token contract address | | >tokenSymbol | String | Token symbol | | >tokenPnLUsd | String | Token PnL (USD) | | >tokenPnLPercent | String | Token PnL percentage | | winRate | String | Win rate | | tokenCountByPnlPercent | Object | Token count statistics categorized by PnL percentage | | >over500Percent | String | Number of tokens with PnL over 500% | | >zeroTo500Percent | String | Number of tokens with PnL between 0% and 500% | | >zeroToMinus50Percent | String | Number of tokens with PnL between -50% and 0% | | >overMinus50Percent | String | Number of tokens with PnL below -50% | | buyTxCount | String | Number of buy transactions | | buyTxVolume | String | Buy transaction volume | | sellTxCount | String | Number of sell transactions | | sellTxVolume | String | Sell transaction volume | | avgBuyValueUsd | String | Average buy value (USD) | | preferredMarketCap | String | Preferred market cap range. Primary preference: `1: less than $100K, 2: $100K-$1M, 3: $1M-$10M, 4: $10M-$100M, 5: greater than $100M` | | buysByMarketCap | Array | Buy statistics categorized by market cap | | >marketCapRange | String | Market cap range. Enum includes: `1: less than $100K, 2: $100K-$1M, 3: $1M-$10M, 4: $10M-$100M, 5: greater than $100M` | | >buyCount | String | Buy count | ## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/portfolio/overview?chainIndex=1&walletAddress=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045&timeFrame=3' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": { "avgBuyValueUsd": "0", "buyTxCount": "0", "buyTxVolume": "0", "buysByMarketCap": [ { "buyCount": "0", "marketCapRange": "1" }, { "buyCount": "0", "marketCapRange": "2" }, { "buyCount": "0", "marketCapRange": "3" }, { "buyCount": "0", "marketCapRange": "4" }, { "buyCount": "0", "marketCapRange": "5" } ], "preferredMarketCap": "1", "realizedPnlUsd": "0", "sellTxCount": "4", "sellTxVolume": "0", "tokenCountByPnlPercent": { "over500Percent": "0", "overMinus50Percent": "0", "zeroTo500Percent": "0", "zeroToMinus50Percent": "0" }, "top3PnlTokenPercent": "0", "top3PnlTokenSumUsd": "0", "topPnlTokenList": [], "winRate": "0.00" }, "msg": "" } ``` - [Get Address Recent PnL List](https://web3.okx.com/onchainos/dev-docs/market/market-portfolio-recent-pnl.md) {/* api-page */} # Get Address Recent PnL List Get a list of recent PnL for an address in reverse chronological order Limit: 1000 records, up to 100 per request ### Request Path GET `https://web3.okx.com/api/v6/dex/market/portfolio/recent-pnl` ## Request Parameters | Parameter | Type | Required | Description | |---|---|---|---| | chainIndex | String | Yes | Unique identifier of the chain, pass the chain ID (e.g., 501 for Solana), only single-chain query is supported | | walletAddress | String | Yes | Wallet address to query | | cursor | String | No | Pagination cursor, pass the cursor value returned from the previous request | | limit | String | No | Number of records per page, max 100 | ## Response Parameters | Parameter | Type | Description | |---|---|---| | cursor | String | Pagination cursor | | pnlList | Array | PnL list | | >chainIndex | String | Unique identifier of the chain | | >tokenContractAddress | String | Token contract address | | >tokenSymbol | String | Token symbol | | >lastActiveTimestamp | String | Last active timestamp (milliseconds) | | >unrealizedPnlUsd | String | Unrealized PnL (USD), returns SELL_ALL if the address has sold all holdings | | >unrealizedPnlPercent | String | Unrealized PnL percentage | | >realizedPnlUsd | String | Realized PnL (USD) | | >realizedPnlPercent | String | Realized PnL percentage | | >totalPnlUsd | String | Total PnL (USD) | | >totalPnlPercent | String | Total PnL percentage | | >tokenBalanceUsd | String | Token balance value (USD) | | >tokenBalanceAmount | String | Token balance amount | | >tokenPositionPercent | String | Token position percentage | | >tokenPositionDuration | Object | Token position duration info | | >>holdingTimestamp | String | Holding start timestamp (milliseconds) | | >>sellOffTimestamp | String | Sell-off timestamp (milliseconds), empty if still holding | | >buyTxCount | String | Number of buy transactions | | >buyTxVolume | String | Buy transaction volume | | >buyAvgPrice | String | Average buy price | | >sellTxCount | String | Number of sell transactions | | >sellTxVolume | String | Sell transaction volume | | >sellAvgPrice | String | Average sell price | ## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/portfolio/recent-pnl?chainIndex=1&walletAddress=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045&limit=10' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": { "pnlList": [ { "chainIndex": "1", "tokenContractAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7", "tokenSymbol": "USDT", "lastActiveTimestamp": "1710000000000", "unrealizedPnlUsd": "100.00", "unrealizedPnlPercent": "10.00", "realizedPnlUsd": "200.00", "realizedPnlPercent": "20.00", "totalPnlUsd": "300.00", "totalPnlPercent": "30.00", "tokenBalanceUsd": "1000.00", "tokenBalanceAmount": "1000", "tokenPositionPercent": "10.00", "tokenPositionDuration": { "holdingTimestamp": "1700000000000", "sellOffTimestamp": "" }, "buyTxCount": "5", "buyTxVolume": "900.00", "buyAvgPrice": "0.99", "sellTxCount": "2", "sellTxVolume": "400.00", "sellAvgPrice": "1.01" } ] }, "msg": "" } ``` - [Get Address Latest PnL for Specific Token](https://web3.okx.com/onchainos/dev-docs/market/market-portfolio-latest-pnl.md) {/* api-page */} # Get Address Latest PnL for Specific Token Get the latest income of the specified token of the address ### Request Path GET `https://web3.okx.com/api/v6/dex/market/portfolio/token/latest-pnl` ## Request Parameters | Parameter | Type | Required | Description | |---|---|---|---| | chainIndex | String | Yes | Unique identifier of the chain, pass the chain ID (e.g., 501 for Solana) | | walletAddress | String | Yes | Wallet address to query | | tokenContractAddress | String | Yes | Token contract address | ## Response Parameters | Parameter | Type | Description | |---|---|---| | totalPnlUsd | String | Total PnL (USD) | | totalPnlPercent | String | Total PnL percent | | unrealizedPnlUsd | String | Unrealized PnL (USD) | | unrealizedPnlPercent | String | Unrealized PnL percent | | realizedPnlUsd | String | Realized PnL (USD) | | realizedPnlPercent | String | Realized PnL percent | | isPnlSupported | Boolean | Whether PnL calculation is supported | ## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/portfolio/token/latest-pnl?chainIndex=1&walletAddress=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045&tokenContractAddress=0xdac17f958d2ee523a2206206994597c13d831ec7' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": 0, "data": { "totalPnlUsd": "1371.68", "totalPnlPercent": "20.22", "unrealizedPnlUsd": "685.4", "unrealizedPnlPercent": "10.11", "realizedPnlUsd": "-685.4", "realizedPnlPercent": "-10.11", "isPnlSupported": true } } ``` - [Get Address DEX Transaction List](https://web3.okx.com/onchainos/dev-docs/market/market-portfolio-dex-history.md) {/* api-page */} # Get Address DEX Transaction List Get the historical DEX transaction list of the address in reverse chronological order Limit: 1000 records, up to 100 per request ### Request Path GET `https://web3.okx.com/api/v6/dex/market/portfolio/dex-history` ## Request Parameters | Parameter | Type | Required | Description | |---|---|---|---| | chainIndex | String | Yes | Unique identifier of the chain, pass the chain ID (e.g., 501 for Solana) | | walletAddress | String | Yes | Wallet address to query | | begin | String | Yes | Start timestamp (milliseconds) | | end | String | Yes | End timestamp (milliseconds) | | tokenContractAddress | String | No | Token contract address; if not provided, returns transactions for all tokens | | type | String | No | Transaction type: 1=BUY, 2=SELL, 3=Transfer In, 4=Transfer Out, supports comma-separated multiple types | | cursor | String | No | Pagination cursor, pass the cursor value returned from the previous request | | limit | String | No | Number of records per page, max 100 | ## Response Parameters | Parameter | Type | Description | |---|---|---| | transactionList | Array | Transaction list | | >type | String | Transaction type (1=BUY, 2=SELL, 3=Transfer In, 4=Transfer Out) | | >chainIndex | String | Unique identifier of the chain | | >tokenContractAddress | String | Token contract address | | >tokenSymbol | String | Token symbol | | >valueUsd | String | Transaction value (USD) | | >amount | String | Token amount | | >price | String | Transaction price | | >marketCap | String | Market cap | | >pnlUsd | String | PnL (USD) | | >time | String | Transaction timestamp (milliseconds) | | cursor | String | Pagination cursor for retrieving the next page of data | ## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/portfolio/dex-history?chainIndex=1&walletAddress=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045&begin=1700000000000&end=1710000000000&limit=10' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": { "transactionList": [ { "type": "1", "chainIndex": "1", "tokenContractAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7", "tokenSymbol": "USDT", "valueUsd": "1000.00", "amount": "1000", "price": "1.00", "marketCap": "100000000000", "pnlUsd": "50.00", "time": "1709900000000" } ], "cursor": "0" }, "msg": "" } ``` - [Get Latest DEX Trades for Multiple Addresses](https://web3.okx.com/onchainos/dev-docs/market/market-portfolio-address-tracker-trades.md) {/* api-page */} # Get Latest DEX Trades for Multiple Addresses Retrieve on-chain transaction dynamics of tracked addresses. Supports filtering by dynamic type (custom grouping, platform KOL addresses, smart money addresses), trade type, volume, market cap, liquidity, chain, and more. ### Request Path GET `https://web3.okx.com/api/v6/dex/market/address-tracker/trades` ## Request Parameters | Parameter | Type | Required | Description | |---|---|---|---| | trackerType | String | Yes | Track dynamic type. 1: smart_money, platform smart money addresses; 2: kol, platform Top 100 KOL addresses; 3: multi_address, query multiple addresses | | walletAddress | String | No | Required when trackerType=multi_address. Can be a single address or multiple addresses separated by commas, up to 20 | | tradeType | String | No | Trade type: 0: all (default); 1: buy; 2: sell | | chainIndex | String | No | Chain identifier, defaults to all. Options: 501 (Solana), 1 (Ethereum), 56 (BNB Chain), 8453 (Base), 196 (X Layer) | | minVolume | String | No | Minimum trade volume (USD) | | maxVolume | String | No | Maximum trade volume (USD) | | minHolders | String | No | Minimum number of holding addresses | | minMarketCap | String | No | Minimum market cap (USD) | | maxMarketCap | String | No | Maximum market cap (USD) | | minLiquidity | String | No | Minimum liquidity (USD) | | maxLiquidity | String | No | Maximum liquidity (USD) | ## Response Parameters | Parameter | Type | Description | |---|---|---| | trades | Array | List of transaction dynamics for tracked addresses | | >txHash | String | Transaction hash | | >walletAddress | String | Wallet address of the transaction | | >quoteTokenSymbol | String | Pricing token symbol; only mainnet tokens are returned here | | >quoteTokenAmount | String | Quantity of pricing tokens traded, indicating the amount priced in the mainnet token | | >tokenSymbol | String | Trading token symbol | | >tokenContractAddress | String | Trading token contract address | | >chainIndex | String | Chain identifier where the trading token is located | | >tokenPrice | String | Trading price of the token (USD) | | >marketCap | String | Market cap corresponding to the token's transaction price (USD) | | >realizedPnlUsd | String | Realized profit and loss of the trading token (USD) | | >tradeType | String | Trade type for the token: 1: buy; 2: sell | | >tradeTime | String | Transaction time (millisecond timestamp) | ## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/address-tracker/trades?trackerType=1' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": { "trades": [ { "chainIndex": "56", "marketCap": "6781.4431281050000000000000000000", "quoteTokenAmount": "0.105214264768396182", "quoteTokenSymbol": "BSC", "realizedPnlUsd": "-28.212213718646256043110124512", "tokenContractAddress": "0xcad59e019f06003303e56d4cc38fab0667114444", "tokenPrice": "0.000006781443128105", "tokenSymbol": "DoraemonToken", "tradeTime": "1773736186000", "tradeType": "2", "txHash": "0x1daf1ab1c393ea5bf901f2d8efdd4a67ce1e1e0e7dfd748820e195f2398a8afd", "walletAddress": "0xeb1222a0c07d4e62b0235d8b4b3e7e617d259be2" } ] }, "msg": "" } ``` - [Error Codes](https://web3.okx.com/onchainos/dev-docs/market/market-portfolio-error-code.md) # Error Codes | Code | HTTP status | Message | |-------|-------------|-----------------------------------------------------------------------------------------| | 0 | 200 | Succeeded | | 50011 | 429 | Rate limit reached. Please refer to API documentation and throttle requests accordingly | | 50014 | 400 | Parameter \{param0\} cannot be empty | | 50026 | 500 | System error. Try again later | | 50103 | 401 | Request header "OK-ACCESS-KEY" cannot be empty | | 50104 | 401 | Request header "OK-ACCESS-PASSPHRASE" cannot be empty| | 50105 | 401 | Request header "OK-ACCESS-PASSPHRASE" incorrect | | 50106 | 401 | Request header "OK-ACCESS-SIGN" cannot be empty | | 50107 | 401 | Request header "OK-ACCESS-TIMESTAMP" cannot be empty | | 50111 | 401 | Invalid OK-ACCESS-KEY | | 50112 | 401 | Invalid OK-ACCESS-TIMESTAMP | | 50113 | 401 | Invalid signature | | 51000 | 400 | Parameter \{param0\} error | - [API Reference](https://web3.okx.com/onchainos/dev-docs/market/balance-reference.md) # API Reference - [Get Supported Chains](https://web3.okx.com/onchainos/dev-docs/market/balance-chains.md) {/* api-page */} # Get Supported Chains Retrieve information on chains supported by the DEX Balance endpoint ### Request URL GET `https://web3.okx.com/api/v6/dex/balance/supported/chain` ## Request Parameters None ## Response Parameters | Parameter | Type | Description | |-----------|--------|-------------------| | name | String | Chain name | | logoUrl | String | Chain logo URL | | shortName | String | Chain short name | | chainIndex| String | Chain unique identifier | ## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/balance/supported/chain' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "name": "Ethereum", "logoUrl": "http://www.eth.org/eth.png", "shortName": "ETH", "chainIndex": "1" } ], "msg": "" } ``` - [Get Total Value](https://web3.okx.com/onchainos/dev-docs/market/balance-total-value.md) {/* api-page */} # Get Total Value Retrieve the total balance of all tokens and DeFi assets under an account. ### Request URL GET `https://web3.okx.com/api/v6/dex/balance/total-value-by-address` ## Request Parameters | Parameter | Type | Required | Description | | ------------------| ------- | -------- | ------------------------------------------------------------------ | | address | String | Yes | Get the total valuation for the address | | chains | String | Yes | Filter chains for which to query total assets, separated by ",". Supports up to 50 chains..
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). | | assetType | String | No | Query balance type. Default is to query all asset balances.
`0`: Query total balance for all assets, including tokens and DeFi assets.
`1`: Query only token balance.
`2`: Query only DeFi balance. | | excludeRiskToken | Boolean | No | Option to filter out risky airdrop & honeypot tokens. Default is to filter.
`true`: filter out, `false`: do not filter out
It supports only `ETH`、`BSC`、`SOL`、`BASE` for honeypot tokens, more chains will be supported soon. |
## Response Parameters | Parameter | Type | Description | | --- | --- | --- | | totalValue | String | Total asset balance based on the query type, returned in USD |
## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/balance/total-value-by-address?address=0x0b32aa5c1e71715206fe29b7badb21ad95f272c0&chains=1&assetType=0' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ``` json { "code": "0", "msg": "success", "data": [ { "totalValue": "1172.895057177065864522056725546579939398" } ] } ```
- [Get Total Token Balances](https://web3.okx.com/onchainos/dev-docs/market/balance-total-token-balances.md) {/* api-page */} # Get Total Token Balances Retrieve the list of token balances for an address across multiple chains or specified chains. ### Request URL GET `https://web3.okx.com/api/v6/dex/balance/all-token-balances-by-address` ## Request Parameters | Parameter | Type | Required | Description | |----------------|--------|----------|-----------------------------------------| | address | String | Yes | Address | | chains | Array | Yes | When filtering the chains for querying asset details, multiple chains should be separated by commas (`,`). A maximum of 50 chains is supported.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain).| | excludeRiskToken | String | No | Option to filter out risky airdrop & honeypot tokens. Default is to filter.
`0`: Filter out
`1`: Do not filter out
It supports only `ETH`、`BSC`、`SOL`、`BASE` for honeypot tokens, more chains will be supported soon. |
## Response Parameters | Parameter | Type | Description | |---------------|--------|------------------------------------------| | tokenAssets | Array | List of token balances | | >chainIndex | String | Unique identifier for the chain | | >tokenContractAddress | String | Contract address | | >address | String | Address | | >symbol | String | Token symbol | | >balance | String | Token balance | | >rawBalance | String | Raw balance of token address. For unsupported chains, this field is empty. More chains will be supported soon. | | >tokenPrice | String | Token unit value, priced in USD | | >isRiskToken | Boolean| `true`: flagged as a risky airdrop & honeypot token
`false`: not flagged as a risky airdrop & honeypot token |
## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/balance/all-token-balances-by-address?address=0xEd0C6079229E2d407672a117c22b62064f4a4312&chains=1' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ``` json { "code": "0", "msg": "success", "data": [ { "tokenAssets": [ { "chainIndex": "1", "tokenContractAddress": "0x386ae941d4262b0ee96354499df2ab8442734ec0", "symbol": "PT-sUSDE-27FEB2025", "balance": "47042180.520700015", "tokenPrice": "0.968391562089677097", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0", "symbol": "wstETH", "balance": "7565.892480395067", "tokenPrice": "4321.611627695311", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", "symbol": "WBTC", "balance": "329.10055205", "tokenPrice": "98847.8", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x23878914efe38d27c4d67ab83ed1b93a74d4086a", "symbol": "aEthUSDT", "balance": "30057379.938443", "tokenPrice": "0.99978", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x657e8c867d8b37dcc18fa4caead9c45eb088c642", "symbol": "eBTC", "balance": "271.94970471", "tokenPrice": "99094.345321371", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8", "symbol": "aEthWETH", "balance": "6080.001975381972", "tokenPrice": "3634.32", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xe00bd3df25fb187d6abbb620b3dfd19839947b81", "symbol": "PT-sUSDE-27MAR2025", "balance": "19016580.895408865", "tokenPrice": "0.952031186961110727", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xa17581a9e3356d9a858b789d68b4d866e593ae94", "symbol": "cWETHv3", "balance": "3000.000734740809", "tokenPrice": "3663.74", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x9d39a5de30e57443bff2a8307a4256c8797a3497", "symbol": "sUSDe", "balance": "4863500.628333919", "tokenPrice": "1.144688569528375454", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xec5a52c685cc3ad79a6a347abace330d69e0b1ed", "symbol": "PT-LBTC-27MAR2025", "balance": "46.02912324", "tokenPrice": "97165.169717785655331396", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x8236a87084f8b84306f72007f36f2618a5634494", "symbol": "LBTC", "balance": "38.09998", "tokenPrice": "99187.19184268864", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xbeef047a543e45807105e51a8bbefcc5950fcfba", "symbol": "steakUSDT", "balance": "482651.8612595832", "tokenPrice": "1.063", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x4c9edd5852cd905f086c759e8383e09bff1e68b3", "symbol": "USDe", "balance": "69564", "tokenPrice": "0.99977", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x8be3460a480c80728a8c4d7a5d5303c85ba7b3b9", "symbol": "sENA", "balance": "42294.989425", "tokenPrice": "1.19", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "", "symbol": "ETH", "balance": "8.135546539084933", "tokenPrice": "3638.63", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xbf5495efe5db9ce00f80364c8b423567e58d2110", "symbol": "ezETH", "balance": "5.270854886240325", "tokenPrice": "3763.152404188635320082", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x6b175474e89094c44da98b954eedeac495271d0f", "symbol": "DAI", "balance": "1196.2693184870445", "tokenPrice": "1.0002", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xc00e94cb662c3520282e6f5717214004a7f26888", "symbol": "COMP", "balance": "0.007643", "tokenPrice": "84.43345772756197", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x9abfc0f085c82ec1be31d30843965fcc63053ffe", "symbol": "Q*", "balance": "900", "tokenPrice": "0.000419255747329174", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xa1290d69c65a6fe4df752f95823fae25cb99e5a7", "symbol": "rsETH", "balance": "0.00007090104120006", "tokenPrice": "3765.640772858747921444", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x56015bbe3c01fe05bc30a8a9a9fd9a88917e7db3", "symbol": "CAT", "balance": "0.42", "tokenPrice": "0.06242994543936436", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xec53bf9167f50cdeb3ae105f56099aaab9061f83", "symbol": "EIGEN", "balance": "0.002496149915967488", "tokenPrice": "4.018538365202288", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x58d97b57bb95320f9a05dc918aef65434969c2b2", "symbol": "MORPHO", "balance": "0.001409373661132556", "tokenPrice": "3.3568669630371337", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xaf5191b0de278c7286d6c7cc6ab6bb8a73ba2cd6", "symbol": "STG", "balance": "0.000009547670354338", "tokenPrice": "0.49707759500034454", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xba3335588d9403515223f109edc4eb7269a9ab5d", "symbol": "GEAR", "balance": "0.000009005734110189", "tokenPrice": "0.012329598382413718", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x35fa164735182de50811e8e2e824cfb9b6118ac2", "symbol": "eETH", "balance": "0.000000000000000001", "tokenPrice": "3637.93", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xae7ab96520de3a18e5e111b5eaab095312d7fe84", "symbol": "stETH", "balance": "0.000000000000000001", "tokenPrice": "3637.93", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xa3931d71877c0e7a3148cb7eb4463524fec27fbd", "symbol": "sUSDS", "balance": "67435907.43236613", "tokenPrice": "0", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xa8705a14c79fa1cded70875510211fec822b3c30", "symbol": "BEEX", "balance": "5000000", "tokenPrice": "0", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xabc0abace9fb9625fcefbedc423e8f94225bd251", "symbol": "TANUKI", "balance": "3548102.746002181", "tokenPrice": "0", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x356b8d89c1e1239cbbb9de4815c39a1474d5ba7d", "symbol": "syrupUSDT", "balance": "1750000", "tokenPrice": "0", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" } ] } ] } ```
- [Get Specific Token Balance](https://web3.okx.com/onchainos/dev-docs/market/balance-specific-token-balance.md) {/* api-page */} # Get Specific Token Balance Query the balance of a specific token under an address. ### Request URL POST `https://web3.okx.com/api/v6/dex/balance/token-balances-by-address` ## Request Parameters | Parameter | Type | Required | Description | |----------------|--------|----------|-----------------------------------------| | address | String | Yes | Address | | tokenContractAddresses | Array | Yes | List of tokens addresses to query. Maximum of 20 items. | | >chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](../home/supported-chain). | | >tokenContractAddress | String | Yes | Token address.
`1`: Pass an empty string `""` to query the native token of the corresponding chain.
`2`: Pass the specific token contract address to query the corresponding token. | | excludeRiskToken | String | No | Option to filter out risky airdrop & honeypot tokens. Default is to filter
`0`: Filter out
`1`: Do not filter out
It supports only `ETH`、`BSC`、`SOL`、`BASE` for honeypot tokens, more chains will be supported soon. |
## Response Parameters | Parameter | Type | Description | |--------------|--------|-----------------------------------------| | tokenAssets | Array | List for token balances | | >chainIndex | String | Unique identifier for the chain | | >tokenContractAddress | String | Token address.If the return is an empty string `""`, it means the query is for the native token of the corresponding blockchain. | | >address | String | Address | | >symbol | String | Token symbol | | >balance | String | Token balance. | | >rawBalance | String | Raw balance of token address. For unsupported chains, this field is empty. More chains will be supported soon. | | >tokenPrice | String | Token price in USD | | >isRiskToken | Boolean| `true`: flagged as a risky airdrop & honeypot token
`false`: not flagged as a risky airdrop & honeypot token |
## Request Example ```shell curl --location --request POST 'https://web3.okx.com/api/v6/dex/balance/token-balances' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '{ "address": "0x50c476a139aab23fdaf9bca12614cdd54a4244e3", "tokenContractAddresses": [ { "chainIndex": "1", "tokenContractAddress": "" } ] }' ``` ## Response Example ``` json { "code": "0", "msg": "success", "data": [ { "tokenAssets": [ { "chainIndex": "1", "tokenContractAddress": "", "symbol": "eth", "balance": "0", "tokenPrice": "3640.43", "isRiskToken": false, "rawBalance": "", "address": "" } ] } ] } ```
- [Error Codes](https://web3.okx.com/onchainos/dev-docs/market/balance-error-code.md) # Error Codes | Code | HTTP status | Message | |-------|-------------|-----------------------------------------------------------------| | 50014 | 400 | param \{param0\} is invalid | | 50001 | 200 | Service temporarily unavailable. Try again later | | 81001 | 200 | Incorrect parameter: : \{param0\} | | 50011 | 429 | Too Many Requests | | 81104 | 200 | Chain not support | | 81001 | 200 | Required request body is missing | - [API Reference](https://web3.okx.com/onchainos/dev-docs/market/tx-history-reference.md) # API Reference - [Get Supported Chains](https://web3.okx.com/onchainos/dev-docs/market/tx-history-chains.md) {/* api-page */} # Get Supported Chains Retrieve information on chains supported by Transaction history API ### Request URL GET `https://web3.okx.com/api/v6/dex/balance/supported/chain` ## Request Parameters None ## Response Parameters | Parameter | Type | Description | |-----------|--------|-------------------| | name | String | Chain name | | logoUrl | String | Chain logo URL | | shortName | String | Chain short name | | chainIndex| String | Chain unique identifier | ## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/balance/supported/chain' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "name": "Ethereum", "logoUrl": "http://www.eth.org/eth.png", "shortName": "ETH", "chainIndex": "1" } ], "msg": "" } ``` - [Get History by Address](https://web3.okx.com/onchainos/dev-docs/market/tx-history-transactions-by-address.md) {/* api-page */} # Get History by Address Query the transaction history under the address dimension for 6 months, sorted in descending chronological order. ### Request URL GET `https://web3.okx.com/api/v6/dex/post-transaction/transactions-by-address` ## Request Parameters | Parameter | Type | Required | Description | |-------------- |-------- |---------- |--------------------------------------------------------------------------------------------------------------- | | address | String | Yes | Address to query the transaction history for | | chains | String | No | Filter the chains whose transaction history needs to be queried. Multiple chains are separated by ",". A maximum of 50 chains are supported. | | tokenContractAddress | String | No | Token contract address; if empty, query addresses with main chain currency balance;if not pass, query all | | begin | String | No | Start time, queries transactions after this time. Unix timestamp, in milliseconds | | end | String | No | End time, queries transactions before this time. If both begin and end are not provided, queries transactions before the current time. Unix timestamp, in milliseconds | | cursor | String | No | Cursor | | limit | String | No | Number of records to return, defaults to the most recent 20 records.
Up to a maximum of 20 records for query on single chain.
Up to a maximum of 100 records for query on multiple chain. | |
## Response Parameters | Parameter | Type | Description | |----------------- |--------------------------------- |----------------------------------------------------- | | transactions | Array | List of transactions | | >chainIndex | String | Chain ID | | >txHash | String | Transaction hash | | >itype | String | Transaction tier type
`0`: Outer main chain coin transfer
`1`: Contract inner main chain coin transfer
`2`: Token transfer | | >methodId | String | Contract Function Call | | >nonce | String | The nth transaction initiated by the sender address | | >txTime | String | Transaction time in Unix timestamp format, in milliseconds, e.g., 1597026383085 | | >from | Array | Transaction input | | >>address | String | Sending/input address, comma-separated for multi-signature transactions | | >>amount | String | Input amount | | >to | Array | Transaction output | | >>address | String | Receiving/output address, comma-separated for multiple addresses | | >>amount | String | Output amount | >tokenContractAddress | String | Token contract address | | >amount | String | Transaction amount | | >symbol | String | Currency symbol corresponding to the transaction amount | | >txFee | String | Transaction fee | | >txStatus | String | Transaction status: `success` for successful transactions, `fail` for failed transactions, `pending` for pending transactions | | >hitBlacklist | Boolean | `false`: Not in blacklist, `true`: In blacklist | | cursor | String | Cursor |
## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/post-transaction/transactions-by-address?addresses=0x50c476a139aab23fdaf9bca12614cdd54a4244e4&chains=1' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ``` json { "code": "0", "msg": "success", "data": [ { "cursor": "1706197403", "transactionList": [ { "chainIndex": "1", "txHash": "0x963767695543cfb7804039c470b110b87adf9ab69ebc002b571523b714b828ca", "methodId": "", "nonce": "", "txTime": "1724213411000", "from": [ { "address": "0xae7ab96520de3a18e5e111b5eaab095312d7fe84" "amount": "" } ], "to": [ { "address": "0x50c476a139aab23fdaf9bca12614cdd54a4244e4" "amount": "" } ], "tokenContractAddress": "0xe13c851c331874028cd8f681052ad3367000fb13", "amount": "1", "symbol": "claim rewards on stethdao.net", "txFee": "", "txStatus": "success", "hitBlacklist": true, "itype": "2" } ] } ] } ```
- [Get Specific Transaction](https://web3.okx.com/onchainos/dev-docs/market/tx-history-specific-transaction-detail-by-txhash.md) {/* api-page */} # Get Specific Transaction Retrieve details of a transaction based on `txHash` for 6 months. It decomposes a transaction and its internal transactions into sub-transactions based on asset type:
`0`: Outer layer mainnet coin transfer
`1`: Inner layer mainnet coin transfer in a contract
`2`: Token transfer It decomposes a transaction into sub-transactions based on asset type. For EVM transactions, different sub-transaction types include:
`0`: Outer layer mainnet coin transfer
`1`: Inner layer mainnet coin transfer in a contract
`2`: Token transfer
### Request URL GET `https://web3.okx.com/api/v6/dex/post-transaction/transaction-detail-by-txhash` ## Request Parameters | Parameter | Type | Required | Description | |--------------------|----------------|------------------|--------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain | | txHash | String | Yes | Transaction hash | | itype | String | No | Layer type for transactions
`0`: Outer layer mainnet coin transfer
`1`: Inner layer mainnet coin transfer
`2`: Token transfer |
## Response Parameters | Parameter | Type | Description | |------------------------------------|----------------|----------------------------------------------------------------| | chainIndex | String | Unique identifier for the chain | | height | String | Block height where the transaction occurred | | txTime | String | Transaction time; Unix timestamp in milliseconds | | txhash | String | Transaction hash | | txStatus | String | Transaction status:
`1`: pending
`2`: success
`3`: fail | | gasLimit | String | Gas limit | | gasUsed | String | Gas used | | gasPrice | String | Gas price | | txFee | String | Transaction fee. | | nonce | String | Nonce | | amount | String | Transaction amount | | symbol | String | Currency symbol for the transaction amount | | methodId | String | Contract method ID | | fromDetails | Array | Details of transaction inputs | | >address | String | Sender/input address | | >vinIndex | String | Index of the input in the current transaction | | >preVoutIndex | String | Index of the output in the previous transaction | | >txhash | String | Transaction hash, used with `preVoutIndex` to uniquely identify the UTXO | | >isContract | Boolean | Whether the sender address is a contract (true: yes; false: no) | | >amount | String | Transaction amount | | toDetails | Array | Details of transaction outputs | | >address | String | Receiver/output address | | >voutIndex | String | Output index | | >isContract | Boolean | Whether the receiver address is a contract (true: yes; false: no) | | >amount | String | Transaction amount | | internalTransactionDetails | Array | Internal transaction details | | >from | String | Sender address for the internal transaction | | >to | String | Receiver address for the internal transaction | | >isFromContract | Boolean | Whether the sender address is a contract (true: yes; false: no) | | >isToContract | Boolean | Whether the receiver address is a contract (true: yes; false: no) | | >amount | String | Transaction amount | | >txStatus | String | Transaction status | | tokenTransferDetails | Array | Token transfer details | | >from | String | Sender address for token transfer | | >to | String | Receiver address for token transfer | | >isFromContract | Boolean | Whether the sender address is a contract (true: yes; false: no) | | >isToContract | Boolean | Whether the receiver address is a contract (true: yes; false: no) | | >tokenContractAddress | String | Token contract address | | >symbol | String | Token symbol | | >amount | String | Token amount | | l1OriginHash | String | Hash of the L1 transaction executed |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/post-transaction/transaction-detail-by-txhash?txHash=0x9ab8ccccc9f778ea91ce4c0f15517672c4bd06d166e830da41ba552e744d29a5&chainIndex=42161' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ``` json { "code": "0", "msg": "success", "data": [ { "chainIndex": "42161", "height": "245222398", "txTime": "1724253417000", "txhash": "0x9ab8ccccc9f778ea91ce4c0f15517672c4bd06d166e830da41ba552e744d29a5", "gasLimit": "2000000", "gasUsed": "2000000", "gasPrice": "10000000", "txFee":"", "nonce": "0", "symbol": "ETH", "amount": "0", "txStatus": "success", "methodId": "0xc9f95d32", "l1OriginHash": "0xa6a87ba2f18cc32bbae8f3b2253a29a9617ed1eb0940d80443f6e3bf9873dbad", "fromDetails": [ { "address": "0xd297fa914353c44b2e33ebe05f21846f1048cfeb", "vinIndex": "", "preVoutIndex": "", "txHash": "", "isContract": false, "amount": "" } ], "toDetails": [ { "address": "0x000000000000000000000000000000000000006e", "voutIndex": "", "isContract": false, "amount": "" } ], "internalTransactionDetails": [ { "from": "0x0000000000000000000000000000000000000000", "to": "0xd297fa914353c44b2e33ebe05f21846f1048cfeb", "isFromContract": false, "isToContract": false, "amount": "0.02", "txStatus": "success" }, { "from": "0xd297fa914353c44b2e33ebe05f21846f1048cfeb", "to": "0x428ab2ba90eba0a4be7af34c9ac451ab061ac010", "isFromContract": false, "isToContract": false, "amount": "0.00998", "txStatus": "success" }, { "from": "0xd297fa914353c44b2e33ebe05f21846f1048cfeb", "to": "0x428ab2ba90eba0a4be7af34c9ac451ab061ac010", "isFromContract": false, "isToContract": false, "amount": "0.009977946366846017", "txStatus": "success" } ], "tokenTransferDetails": [] } ] } ```
- [Error Codes](https://web3.okx.com/onchainos/dev-docs/market/tx-history-error-code.md) # Error Codes | Code | HTTP status | Message | |-------|-------------|-----------------------------------------------------------------------------------------| | 81001 | 200 | Incorrect parameter | - [What is Connecting Wallet](https://web3.okx.com/onchainos/dev-docs/sdks/okx-wallet-integration-introduction.md) # What is Connecting Wallet In a DApp, adding a "Connect OKX Wallet" button allows interaction with the OKX Wallet. OKX Wallet comes in various forms and currently supports:
  1. App Wallet
  2. Browser Extension Wallet

DApps can choose the appropriate connection method: **Please note that you can choose between UI SDK and ProviderAPI when accessing. It is recommended to choose UI SDK for one-time access and multi-end compatibility.** - [Supported Networks](https://web3.okx.com/onchainos/dev-docs/sdks/okx-wallet-integration-supported-networks.md) # Supported Networks As a leading global Web3 wallet, OKX Wallet supports over 100 networks, including EVM series, UTXO series, Solana, Ton, and other popular networks. It also supports the latest ecosystems such as Ordinals. The current mainstream networks in the industry can all connect and invoke the OKX Wallet. You can refer to the table below to understand the support status of DApp connections for each network. | | Connect Browser Extension Wallet | Connect Mobile App Wallet | |----------|-----------------------------------------------|--------------------------------------------| | EVM | [Supported](./chains/evm/introduce) | [Supported](./app-connect-evm) | | Bitcoin | [Supported](./chains/bitcoin/introduce) | [Supported](./app-connect-bitcoin) | | Solana | [Supported](./chains/solana/introduce) | [Supported](./app-connect-solana) | | Ton | [Supported](./chains/ton/introduce) | [Supported](./app-connect-ton) | | SUI | [Supported](./chains/sui/introduce) | [Supported](./app-connect-sui) | | Aptos | [Supported](./chains/aptos/introduce) | [Supported](./app-connect-aptos) | | Cosmos | [Supported](./chains/cosmos/introduce) | [Supported](./app-connect-cosmos) | | Tron | [Supported](./chains/tron/introduce) | [Supported](./app-connect-tron) | | Starknet | [Supported](./chains/starknet/introduce) | [Supported](./app-connect-starknet) | | NEAR | [Supported](./chains/near/introduce) | Coming Soon | | Stacks | [Supported](./chains/stacks/introduce) | Coming Soon | | Cardano | [Supported](./chains/cardano/introduce) | Coming Soon | | Nostr | [Supported](./chains/nostr/introduce) | Coming Soon | | WAX | [Supported](./chains/wax/introduce) | Coming Soon | - [Connection Prerequisites](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-preparation.md) # Connection Prerequisites The OKX Connect protocol allows connection to the OKX mobile App Wallet, suitable for DApp operations in mobile browsers.
  • If connecting via SDK, add a "Connect OKX Wallet" button within the DApp. Clicking this button will launch the mobile App Wallet and enable interaction with the OKX Wallet, such as retrieving addresses, initiating wallet signatures, and other functions.
  • In addition to SDK, we also provide a UI interface.
If you haven't downloaded the OKX App Wallet yet, please visit the download page: [Download OKX App](https://web3.okx.com/download) If you have already downloaded the App Wallet, find the network where your DApp is deployed in the left menu and follow the corresponding method to start the connection. Connection methods vary by network. - [EVM-Compatible Chains](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-evm.md) # EVM-Compatible Chains EVM-compatible chains refer to blockchain networks that use Ethereum Virtual Machine (EVM) technology. These chains share the same smart contract execution environment as Ethereum, allowing developers to easily deploy Ethereum-based applications on these networks. This compatibility enables developers to use existing Ethereum tools and libraries, such as Solidity, Web3.js, and Truffle, to build and deploy decentralized applications (DApps). Common EVM-compatible chains include Polygon, Avalanche, and Fantom. The emergence of these networks has enriched the blockchain ecosystem, providing users with more options while promoting the development of cross-chain interoperability.
  • If connecting via SDK, add a "Connect OKX Wallet" button within the DApp. Clicking this button will launch the mobile App Wallet and enable interaction with the OKX Wallet, such as retrieving addresses, initiating wallet signatures, and other functions.
  • In addition to SDK, we also provide a UI interface.
- [SDK](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-evm-sdk.md) # SDK ## Installation and Initialization Make sure to update the OKX App to version 6.88.0 or later to start integration: To integrate OKX Connect into your DApp, use npm: ``` npm install @okxconnect/universal-provider ``` Before connecting to the wallet, you need to create an object for subsequent wallet connection, transaction sending, and other operations. `OKXUniversalProvider.init({DAppMetaData: {name, icon}})` **Request Parameters** - DAppMetaData - object - name - string: Application name, not used as a unique identifier - icon - string: URL of the application icon. Must be in PNG, ICO, or similar formats; SVG icons are not supported. Ideally, provide a URL for a 180x180px PNG icon. **Return Value** - OKXUniversalProvider **Example** ```typescript import {OKXUniversalProvider} from "@okxconnect/universal-provider"; const okxUniversalProvider = await OKXUniversalProvider.init({ DAppMetaData: { name: "application name", icon: "application icon url" }, }) ``` ## Connect to Wallet Connect the wallet to obtain the wallet address, which serves as an identifier and is necessary for signing transactions `okxUniversalProvider.connect(connectParams: ConnectParams);` **Request Parameters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace; Information required for connection. The key for EVM systems is "eip155". If any chain requested is not supported by the wallet, the wallet will reject the connection. - chains: string[]; Chain ID information - defaultChain?: string; default chain - rpcMap?: [chainId: string]: string; rpc information, configure rpc url to request rpc information on the chain, only support EVM system, the chain configured for RPC must be included in the chains - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information for requesting connection, the key of EVM system is 'eip155', if the corresponding chain information is not supported by the wallet, it can still be connected; if you need to connect to a custom network, you can add the request of the custom network to this parameter, if the wallet does not support it, you can add the request of the custom network to this parameter. If you need to connect to a custom network, you can add the request for the custom network to this parameter, if the wallet already has the custom network, the information of the custom chain will be returned in the request result session; if the wallet doesn't support it, and there is no information of the custom chain in the request result session, you can add the custom chain by calling the request method again, with the method set to wallet_addEthereumChain. Add the custom chain. - chains: string[]; chain id information - defaultChain?: string; default chain - rpcMap?: [chainId: string]: string; rpc information, configure rpc url to request rpc information on the chain, only support EVM system, the chain configured for RPC must be included in the chains - sessionConfig: object - redirect: string; Redirection parameter after a successful connection. If in a Telegram Mini App, set this to the Telegram deeplink: "tg://resolve". **Return Value** - Promise `` - topic: string; The session identifier - namespaces: `Record`; namespace information for a successful connection - chains: string[]; Chain information for the connection - accounts: string[]; accounts information for the connection - methods: string[]; methods supported by the wallet under the current namespace - defaultChain?: string; default chain for the current session - sessionConfig?: SessionConfig - DAppInfo: object DApp information - name:string - icon:string - redirect?: string, the redirect parameter after successful connection **Example** ```typescript var session = await okxUniversalProvider.connect({ namespaces: { eip155: { // Please pass in as many chain ids as you need. chains: ["eip155:1","eip155:137"], defaultChain: "1", rpcMap: { "137":"https://polygon.drpc.org" } } }, optionalNamespaces: { eip155: { chains: ["eip155:43114"] } }, sessionConfig: { redirect: "tg://resolve" } }) ``` ## Determine if the wallet is connected Get whether the wallet is currently connected **Return Value** - boolean **Example** ```typescript okxUniversalProvider.connected(); ``` ## Sending Signature and Transactions This method allows sending messages to the wallet, supporting signatures, transactions ``` okxUniversalProvider.request(requestArguments, chain); ``` **Request Parameters** - requestArguments - object - method: string; the name of the requested method - params?: unknown[] | Record`` | object | undefined; Parameters corresponding to the requested method - redirect -string 'none' | `${string}://${string}`; App wallet, the return policy of the deep link when the user signs or rejects the request, if it is a Mini App in Telegram, it can be configured with tg://resolve, if it's not configured here, it'll take the redirect passed by connect method, default is 'none' - chain: string, the chain in which the requested method will be executed, it is recommended to pass this parameter, if not, it will be set to the current defaultChain **Return Values** The results returned vary depending on the method executed. Refer to the examples below for specific parameters - personal_sign - Promise - string: Signature result - eth_signTypedData_v4 - Promise - string: Signature result - eth_sendTransaction - Promise - string: Transaction hash - eth_accounts - Promise - string[]: Returns addresses for the default chainId - eth_requestAccounts - Promise - string[]: Returns addresses for the default chainId - eth_chainId - Promise - number: Returns the default chain ID - wallet_switchEthereumChain - Promise - null - wallet_addEthereumChain - Promise - null - wallet_watchAsset - Promise - boolean: Successfully added **Examples** ```typescript let chain ='eip155:1' var data = {} // Execute personalSign on the chain. // The first parameter in the params array is mandatory for Challenge; // The second parameter, hex encoded address, is optional. data = { "params": [ "0x506c65617365207369676e2074686973206d65737361676520746f20636f6e6669726d20796f7572206964656e746974792e", "0x4B0897b0513FdBeEc7C469D9aF4fA6C0752aBea7" ] } var personalSignResult = await okxUniversalProvider.request(data, chain) //personalSignResult: "0xe8d34297c33a61" // Execute eth_signTypedData_v4 on chain // params array, first parameter is Address is optional; // The second parameter is TypedData, which must be passed. data = { "method": "eth_signTypedData_v4", "params": [ "0x00000", { "domain": { "name": "Ether Mail", "version": "1", "chainId": 1, "verifyingContract": "0xcccccccccccccccccccccccccccccccccccccccc" }, "message": { "from": {"name": "Cow", "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"}, "to": {"name": "Bob", "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"}, "contents": "Hello, Bob!" }, "primaryType": "Mail", "types": { "EIP712Domain": [{"name": "name", "type": "string"}, { "name": "version", "type": "string" }, {"name": "chainId", "type": "uint256"}, {"name": "verifyingContract", "type": "address"}], "Person": [{"name": "name", "type": "string"}, {"name": "wallet", "type": "address"}], "Mail": [{"name": "from", "type": "Person"}, {"name": "to", "type": "Person"}, { "name": "contents", "type": "string" }] } } ] } var signTypeV4Result = await okxUniversalProvider.request(data, chain) //signTypeV4Result: "0xa8bb3c6b33a119d..." // Execute sendTransaction on the chain, data = { "method": "eth_sendTransaction", "params": [ { to: "0x4B...", from: "0xDe...", gas: "0x76c0", value: "0x8ac7230489e80000", data: "0x", gasPrice: "0x4a817c800" } ] } var sendTransactionResult = await okxUniversalProvider.request(data, chain) // "0x1ccf2c4a3d689067fc2ac..." // Get address information for the default chain; data = {"method": "eth_requestAccounts"} var ethRequestAccountsResult = await okxUniversalProvider.request(data, chain) // ["0xf2f3e73b..."] // Get the default chain information; data = {"method": "eth_chainId"} var chainIdResult = await okxUniversalProvider.request(data, chain) //chainIdResult 1 // Switching chains; data = { "method": "wallet_switchEthereumChain", "params": [ { chainId: "0x1" } ] } var switchResult = await okxUniversalProvider.request(data, chain) // switchResult null // Add chain data = { "method": "wallet_addEthereumChain", "params": [{ "blockExplorerUrls": ["https://explorer.fuse.io"], "chainId": "0x7a", "chainName": "Fuse", "nativeCurrency": {"name": "Fuse", "symbol": "FUSE", "decimals": 18}, "rpcUrls": ["https://rpc.fuse.io"] }] } var addEthereumChainResult = await okxUniversalProvider.request(data, chain) //addEthereumChainResult null // add coins to the chain watchAsset data = { "method": "wallet_watchAsset", "params": [{ "type": "ERC20", "options": { "address": "0xeB51D9A39AD5EEF215dC0Bf39a8821ff804A0F01", "symbol": "LGNS", "image": "https://polygonscan.com/token/images/originlgns_32.png", "decimals": 9 } }] } var watchAssetResult = await okxUniversalProvider.request(data, chain) // watchAssetResult // true/false ``` ## Using RPC When EVM request method can not meet the demand, you can configure RPC to achieve more functions, in the connection wallet connect(), RPC configuration in the rpcMap. **Example** ```typescript // Query the details of the transaction hash let rpcData = { method: "eth_getTransactionByHash", params: ["0xd62fa4ea3cf7ee3bf6f5302b764490730186ed6a567c283517e8cb3c36142e1a"], }; let result = await universalUi.request(rpcData,"eip155:137") ``` ## Set Default Network In the case of multiple networks, if the developer does not specify the network where the current operation is performed, the interaction will be performed through the default network. **Example** ```typescript okxUniversalProvider.setDefaultChain("eip155:1") ``` ## Disconnect wallet Disconnect from a connected wallet and delete the current session. If you want to switch wallets, disconnect from the current wallet first. ```typescript okxUniversalProvider.disconnect(); ``` ## Event ```typescript // Generate universalLink okxUniversalProvider.on('display_uri', (uri) => { console.log(uri); }); // Session information changes will trigger this event; okxUniversalProvider.on('session_update', (session) => { console.log(JSON.stringify(session)); // Session information changes (e.g., adding a custom chain). }); // Disconnecting triggers this event; okxUniversalProvider.on('session_delete', ({topic}) => { console.log(topic); }); ``` ## Error codes Exceptions that may be thrown during connection, transaction, and disconnection. **Exception** | Error Code | Description | |----------------------------------------------|-------------------------| | OKX_CONNECT_ERROR_CODES.UNKNOWN_ERROR | Unknown Error | | OKX_CONNECT_ERROR_CODES.ALREADY_CONNECTED_ERROR | Wallet Already Connected | | OKX_CONNECT_ERROR_CODES.NOT_CONNECTED_ERROR | Wallet Not Connected | | OKX_CONNECT_ERROR_CODES.USER_REJECTS_ERROR | User Rejected | | OKX_CONNECT_ERROR_CODES.METHOD_NOT_SUPPORTED | Method Not Supported | | OKX_CONNECT_ERROR_CODES.CHAIN_NOT_SUPPORTED | Chain Not Supported | | OKX_CONNECT_ERROR_CODES.WALLET_NOT_SUPPORTED | Wallet Not Supported | | OKX_CONNECT_ERROR_CODES.CONNECTION_ERROR | Connection Error | ```typescript export enum OKX_CONNECT_ERROR_CODES { UNKNOWN_ERROR = 0, ALREADY_CONNECTED_ERROR = 11, NOT_CONNECTED_ERROR = 12, USER_REJECTS_ERROR = 300, METHOD_NOT_SUPPORTED = 400, CHAIN_NOT_SUPPORTED = 500, WALLET_NOT_SUPPORTED = 600, CONNECTION_ERROR = 700 } ``` - [UI](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-evm-ui.md) # UI Make sure to update the OKX App to version 6.90.1 or later to start accessing: To integrate OKX Connect into your DApp, you can use npm: ## Install via npm ``` npm install @okxconnect/ui ``` ## Initialization Before connecting to the wallet, you need to create an object for subsequent operations such as connecting to the wallet and sending transactions. ``` OKXUniversalConnectUI.init(DAppMetaData, actionsConfiguration, uiPreferences, language, restoreConnection) ``` **Request Parameterseters** - dappMetaData - object - name - string: the name of the application, will not be used as a unique representation. - icon - string: URL of the application icon, must be in PNG, ICO, etc. SVG icons are not supported. SVG icons are not supported. It is better to pass a url pointing to a 180x180px PNG icon. - actionsConfiguration - object - modals - ('before' |'success' |'error')[] |'all' The modes of displaying alerts during transaction, defaults to'before'. - returnStrategy -string'none' | `${string}://${string}`; For app wallet, specify the return strategy for the deep link when the user signs/rejects the request, or configure tg://resolve if it's in tg; - uiPreferences -object - theme - Theme can be: THEME.DARK, THEME.LIGHT,'SYSTEM'. - language -'en_US' |'ru_RU' |'zh_CN' |'ar_AE' |'cs_CZ' |'de_DE' |'es_ES' |'es_LAT' |'fr_FR' |'id_ID' |'it_IT' |'nl_NL' |'pl_PL' |'pt_BR' |'pt_PT' |'ro_RO' |'tr_TR' |'uk_UA' |'vi_VN'. , defaults to en_US - restoreConnection?: boolean - Whether to automatically restore the previous connection; **Return Value**. - OKXUniversalConnectUI **Examples** ```typescript import { OKXUniversalConnectUI } from "@okxconnect/ui"; const universalUi = await OKXUniversalConnectUI.init({ DAppMetaData: { icon: "https://static.okx.com/cdn/assets/imgs/247/58E63FEA47A2B7D7.png", name: "OKX Connect Demo" }, actionsConfiguration: { returnStrategy:'tg://resolve', modals:'all', tmaReturnUrl:'back' }, language: "en_US", uiPreferences: { theme: THEME.LIGHT }, }); ``` ## Connecting to a wallet Connecting to a wallet goes to get the wallet address as an identifier and the necessary parameters used to sign the transaction, the ``` await universalUi.openModal(connectParams: ConnectParams); ``` **Request Parameters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace; The necessary information for requesting a connection. The key for the EVM system is "eip155". If any chain in the request is not supported by a wallet, the connection will be rejected. - chains: string[]; Chain ID information, defined as decimal numbers in EIP155, for example, Ethereum is eip155:1. - defaultChain?: string; The default chain. - rpcMap?: [chainId: string]: string; rpc information, configure rpc url to request rpc information on the chain, only support EVM system, the chain configured for RPC must be included in the chains; - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information for requesting connection, the key of EVM system is "eip155", if the corresponding chain information is not supported by the wallet, it can still be connected; if you need to connect to a custom network, you can add the request of the custom network to this parameter, if the wallet does not support it, you can add the request of the custom network to this parameter. If you need to connect to a custom network, you can add the request for the custom network to this parameter, if the wallet already has the custom network, the information of the custom chain will be returned in the request result session; if the wallet doesn't support it, and there is no information of the custom chain in the request result session, you can add the custom chain by calling the request method again, with the method set to wallet_addEthereumChain. Add the custom chain. - chains: string[]; chain id information - rpcMap?: [chainId: string]: string; rpc information, configure rpc url to request rpc information on the chain, only support EVM system, the chain configured with RPC must be included in the chains; **Return value** - Promise `` - topic: string; the session identifier - namespaces: `Record`; namespace information for a successful connection - chains: string[]; Chain information for the connection - accounts: string[]; accounts information for the connection - methods: string[]; methods supported by the wallet under the current namespace - defaultChain?: string; The default chain for the current session - sessionConfig?: SessionConfig - DAppInfo: object DApp information - name:string - Info: object DApp info; name:string **Example** ```typescript var session = await universalUi.openModal({ namespaces: { eip155: { // Please pass in as many chain ids as you need. chains: ["eip155:1","eip155:137"], defaultChain: "1", rpcMap: { "137":"https://polygon.drpc.org" } } }, optionalNamespaces: { eip155: { chains: ["eip155:43114"] } } }) ``` ## Connect to wallet and sign Connect to the wallet to get the wallet address and sign the data; the result will be called back in the event 'connect_signResponse'; ``` await universalUi.openModalAndSign(connectParams: ConnectParams,signRequest: RequestParams[]); ``` **Request Parameterseters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace ; Necessary information for requesting a connection, the EVM system key is 'eip155'. If any of the requested chains are not supported by the wallet, the wallet will reject the connection; - chains: string[]; chain id information, decimal number defined in EIP155, e.g. eip155:1 - defaultChain?: string; default chain - rpcMap?: [chainId: string]: string; rpc information, configure rpc url to request rpc information on the chain, only support EVM system, the chain configured for RPC must be included in the chains; - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information for requesting connection, the key of EVM system is 'eip155', if the corresponding chain information is not supported by the wallet, it can still be connected; if you need to connect to a custom network, you can add the request of the custom network to this parameter, if the wallet does not support it, you can add the request of the custom network to this parameter. If you need to connect to a custom network, you can add the request for the custom network to this parameter, if the wallet already has the custom network, the information of the custom chain will be returned in the request result session; if the wallet doesn't support it, and there is no information of the custom chain in the request result session, you can add the custom chain by calling the request method again, with the method set to wallet_addEthereumChain. Add the custom chain. - chains: string[]; chain id information - rpcMap?: [chainId: string]: string; rpc information, configure rpc url to request rpc information on the chain, only support EVM system, configure RPC chain must be included in chains; - signRequest - RequestParams[]; the method to request the connection and sign, only up to one method is supported at a time - method: string; the name of the requested method, EVM systems support methods such as 'personal_sign' - chainId: string; the ID of the chain in which the method is executed, this chainId must be included in the namespaces above - params: unknown[] | Record`` | object | undefined; Parameters for the requested method **Return Value** - Promise `` - topic: string; The session identifier - namespaces: `Record`; namespace information for a successful connection - chains: string[]; Chain information for the connection - accounts: string[]; accounts information for the connection - methods: string[]; Methods supported by the wallet in the current namespace - defaultChain?: string; The default chain for the current session - sessionConfig?: SessionConfig - dappInfo: object DApp information - name: string - icon:string **Example** ```typescript // Add the signature result listener first universalUi.on("connect_signResponse", (signResponse) => { console.log(signResponse); }); var session = await universalUi.openModalAndSign({ namespaces: { eip155: { // Please pass in as many chain ids as you need, more than one for more than one chain. chains: ["eip155:1","eip155:137"], defaultChain: "1", rpcMap: { "137":"https://polygon.drpc.org" } } }, optionalNamespaces: { eip155: { chains: ["eip155:43114"] } }, sessionConfig: { redirect: "tg://resolve" } },[{ method: "personal_sign", chainId: "eip155:1", params: [ "0x4d7920656d61696c206973206a6f686e40646f652e636f6d202d2031373237353937343537313336", ], }]) ``` ## Determine if the wallet is connected Get whether the wallet is currently connected. **Return Value** - boolean **Example** ```typescript universalUi.connected(); ``` ## Prepare the transaction Methods for sending messages to the wallet, supporting signatures, transactions. ``` universalUi.request(requestArguments, chain, actionConfigurationRequest); ``` **requestArguments** - requestArguments - object - method: string; the name of the requested method. - params?: unknown[] | Record`` | object | undefined; The parameters corresponding to the requested method - returnStrategy -string'none' | `${string}://${string}`; The return strategy for the deep link in the App wallet when the user signs or rejects the request, if it is a Mini App in Telegram, it can be configured with tg://resolve, and if it's not configured here, the will take the returnStrategy passed by the init method, default is'none' - chain: string; the chain in which the requested method will be executed, it is recommended to pass this parameter, if not it will be set to the current defaultChain - actionConfigurationRequest - object - modals : ('before' |'success' |'error')[] |'all' The modals of the alert display during the transaction, if request does not have this parameter set, take the parameter added during init, if init does not have this parameter set as well, then take the default value:'before' ** return value ** [return parameter details same as EVM-compatible chain for sending signatures and transactions](https://web3.okx.com/web3/build/docs/sdks/app-connect-evm-sdk#sending-signature-and-transactions) **Examples** [Example same EVM-compatible chain for sending signatures and transactions](https://web3.okx.com/web3/build/docs/sdks/app-connect-evm-sdk#sending-signature-and-transactions) ```typescript let chain ='eip155:1' var data = {} data = { "method": "personal_sign", "params": [ "0x506c65617365207369676e2074686973206d65737361676520746f20636f6e6669726d20796f7572206964656e746974792e", "0x4B0897b0513FdBeEc7C469D9aF4fA6C0752aBea7" ] } var personalSignResult = await universalUi.request(data, chain,'all') //personalSignResult: 0xe8d34297c33a61" ``` ## Using RPC When EVM request method can not meet the demand, you can configure RPC to achieve more functions, in the connection wallet openModal or openModalAndSign, RPC configuration in the rpcMap. **Example ```typescript //Query the details of the transaction hash let rpcData = { method: "eth_getTransactionByHash", params: ["0xd62fa4ea3cf7ee3bf6f5302b764490730186ed6a567c283517e8cb3c36142e1a"], }; let result = await universalUi.request(rpcData,"eip155:137") ``` ## Close connection popup **Example** ```typescript universalUi.closeModal(); ``` ## Monitoring the state changes of connection popup **Example** ```typescript const unsubscribe = universalUi.onModalStateChange((state)=>{ }) ``` Remove the monitor when it's not needed ``` typescript const unsubscribe = universalUi.onModalStateChange(state) => { } unsubscribe() ``` ## Get information about the currently connected session Get information about whether there is a currently connected wallet, and the connected wallets; **Example** ``` typescript universalUi.session. ``` ## Set ui configuration items Support to change the theme, text language setting, also can add these configurations during initialisation; **Example** ```typescript universalUi.uiOptions = { language:'zh_CN', uiPreferences: { theme: THEME.DARK } }; ``` ## Setting the default network In the case of multiple networks, if the developer does not specify the network where the current operation is taking place, the interaction will take place through the default network. 'setDefaultChain(chain)' **Example** ```typescript universalUi.setDefaultChain('eip155:1') ``` ## Disconnect the wallet **Example** ```typescript universalUi.disconnect(); ``` ## Event ```typescript // Generate universalLink universalUi.on("display_uri", (uri) => { console.log(uri); }); // Session information changes (e.g. adding a custom chain) will trigger this event; universalUi.on("session_update", (session) => { console.log(JSON.stringify(session)); }); // Disconnecting triggers this event; universalUi.on("session_delete", ({topic}) => { console.log(topic); }); // This event is triggered when a connection is made and the signature is signed. universalUi.on("connect_signResponse", (signResponse) => { console.log(signResponse); }); // This event is triggered when connected to OKX Extension wallet and switch wallet universalUi.on("accountChanged", (session) => { if (session){ console.log(`accountChanged `, JSON.stringify(session)); } }); ``` ## Error codes Exceptions that may be thrown during connection, transaction, and disconnection. **Exception** | Error Code | Description | |----------------------------------------------|-------------------------| | OKX_CONNECT_ERROR_CODES.UNKNOWN_ERROR | Unknown Error | | OKX_CONNECT_ERROR_CODES.ALREADY_CONNECTED_ERROR | Wallet Already Connected | | OKX_CONNECT_ERROR_CODES.NOT_CONNECTED_ERROR | Wallet Not Connected | | OKX_CONNECT_ERROR_CODES.USER_REJECTS_ERROR | User Rejected | | OKX_CONNECT_ERROR_CODES.METHOD_NOT_SUPPORTED | Method Not Supported | | OKX_CONNECT_ERROR_CODES.CHAIN_NOT_SUPPORTED | Chain Not Supported | | OKX_CONNECT_ERROR_CODES.WALLET_NOT_SUPPORTED | Wallet Not Supported | | OKX_CONNECT_ERROR_CODES.CONNECTION_ERROR | Connection Error | ```typescript export enum OKX_CONNECT_ERROR_CODES { UNKNOWN_ERROR = 0, ALREADY_CONNECTED_ERROR = 11, NOT_CONNECTED_ERROR = 12, USER_REJECTS_ERROR = 300, METHOD_NOT_SUPPORTED = 400, CHAIN_NOT_SUPPORTED = 500, WALLET_NOT_SUPPORTED = 600, CONNECTION_ERROR = 700 } ``` - [Bitcoin-Compatible Chains](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-bitcoin.md) # Bitcoin-Compatible Chains The Bitcoin network is a peer-to-peer electronic cash system that uses blockchain technology to record all transactions without relying on a central authority or intermediary. It is maintained by thousands of nodes around the world, working together to uphold a public distributed ledger. Key features of Bitcoin and similar blockchains (such as Fractal Bitcoin) include a fixed supply, transparent transaction records, anonymity (or pseudonymity), and a tamper-resistant design. These chains typically employ Proof of Work (PoW) or other consensus mechanisms (like Proof of Stake) to ensure the security and consistency of the network. As the first successful cryptocurrency, Bitcoin pioneered a new category of digital assets and laid the foundation for subsequent blockchain projects and decentralized systems. Emerging chains like Fractal Bitcoin build on Bitcoin's foundation, aiming to improve transaction efficiency, scalability, and community governance, advancing the development of the digital currency ecosystem.
  • If connecting via SDK, add a "Connect OKX Wallet" button within the DApp. Clicking this button will launch the mobile App Wallet and enable interaction with the OKX Wallet, such as retrieving addresses, initiating wallet signatures, and other functions.
  • In addition to SDK, we also provide a UI interface.
- [SDK](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-bitcoin-sdk.md) # SDK ## Installation and Initialization Make sure to update to version 6.92.0 or later to get started with access: to integrate OKX Connect into your DApp, you can use npm: ``` npm install @okxconnect/universal-provider ``` Before connecting to a wallet, you need to create an object that will be used to connect to the wallet, send transactions, and so on. `OKXUniversalProvider.init({dappMetaData: {name, icon}})` **Request Parameterseters** - dappMetaData - object - name - string: the name of the application, will not be used as a unique representation. - icon - string: URL of the application icon, must be in PNG, ICO, etc. SVG icons are not supported. SVG icons are not supported. It is better to pass a url pointing to a 180x180px PNG icon. **Returns a value** - OKXUniversalProvider **Examples** ```typescript import { OKXUniversalProvider } from "@okxconnect/universal-provider"; const okxUniversalProvider = await OKXUniversalProvider.init({ dappMetaData: { name: "application name", icon: "application icon url" }, }) ``` ## Connecting to a wallet Connect to the wallet to get the wallet address as an identifier and the necessary parameters for signing transactions. `okxUniversalProvider.connect(connectParams: ConnectParams);` **Request Parameters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace ; Optional information for the requested connection, the key is 'eip155' for EVM and 'btc' for BTC, if any of the requested chain is not supported by the wallet, the wallet will reject the connection; - chains: string[]; Chain id information - defaultChain?: string; default chain - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information for connection request, the key is 'eip155' for EVM system and 'btc' for BTC system, if the corresponding chain information is not supported by the wallet, you can still connect; - chains: string[]; Chain id information, chain information of the wallet - defaultChain?: string; default chain - sessionConfig: object - redirect: string Jump parameter after successful connection, if it is Mini App in Telegram, here can be set to Telegram's deeplink: 'tg://resolve' **Return value** - Promise `` - topic: string; the session identifier; - namespaces: `Record`; namespace information for a successful connection; - chains: string[]; Chain information for the connection; - accounts: string[]; accounts information for the connection; - methods: string[]; methods supported by the wallet under the current namespace; - defaultChain?: string; The default chain for the current session. - sessionConfig?: SessionConfig - dappInfo: object DApp information; - name:string - icon:string - redirect?: string, the redirect parameter after successful connection; **Example** ```typescript var session = await okxUniversalProvider.connect({ namespaces: { btc: { chains: [ "btc:mainnet", // "fractal:mainnet" ], } }, sessionConfig: { redirect: "tg://resolve" } }) ``` ## Determine if the wallet is connected Gets whether the wallet is currently connected. **Return Value** - boolean **Example** ```typescript okxUniversalProvider.connected(); ``` ## Send signature and transaction First create an OKXBtcProvider object and pass OKXUniversalProvider into the constructor. ```typescript import { OKXBtcProvider } from "@okxconnect/universal-provider"; let okxBtcProvider = new OKXBtcProvider(okxUniversalProvider) ``` **getAccount** `okxBtcProvider.getAccount(chainId);` ***Request Parameterseters*** - chainId: the requested chain, e.g. btc:mainnet, fractal:mainnet ***Return value*** - Object - address: string wallet address - publicKey: string public key ***Example*** ```typescript let result = okxBtcProvider.getAccount("btc:mainnet") // Return structure { "address": "038936b367d47b3796b430a31694320918afdc458d81dea9bb7dd35c0aad8bc694", "publicKey": "03cbaedc26f03fd3ba02fc936f338e980c9e2172c5e23128877ed46827e935296f" } ``` **Signature** `okxBtcProvider.signMessage(chain, message, type?);` ***Request Parameterseters*** - chain - string, the chain of the requested execution method - signStr - string the message to be signed - type - (optional) 'ecdsa' | 'bip322-simple', default is 'ecdsa'. ***Return Value*** - Promise - string: Signature result ***Example*** ```ts let chain = "btc:mainnet" let signStr = "data need to sign ..." let result = okxBtcProvider.signMessage(chain, signStr) // Return structure: "H83jZpulbMDDGUiTA4M8QNChmWwaKxwPCm8U5EBvftKlSMMzuvtVxBHlygtof5NBbdSVPiAtCvOUwZmz2vViHHU=" ``` ## Send `okxBtcProvider.send(chainId, input);` ***Request Parameterseters*** - chainId - string, the chain for which the signature is requested to be executed, mandatory parameter, e.g. btc:mainnet - input - Object - from - string, the BTC address of the currently connected wallet - to - string, the address of the wallet receiving BTC - value - string, the amount of BTC to send - satBytes - string, (optional) customised rate - memo - string, (optional) specify outputs OP_RETURN content example - memoPos - number, (optional) Specify the outputs OP_RETURN output position, if you pass memo then you must pass in memoPos to specify the position, otherwise memo will not take effect. ***Return Value*** - Promise - Object - txHash The transaction hash. ***Example*** ```ts let chain = "btc:mainnet" let input = { from: '', to: '1NKnZ3uAuQLnm....Y44u1efwCgTiAxBn', value: '0.000015' } let result = okxBtcProvider.send(chain, input) /** Return structure: {"txhash":"ff18d01ef6abed3b7fd23247a1fc457ca...f49b6bb4529a19a5fb637f18ce2e"} */ ``` **Send Bitcoin** `okxBtcProvider.sendBitcoin(chainId, toAddress, satoshis, options);` ***Request Parameterseters*** - chainId - string, the chain for which the signature is requested to be executed, mandatory parameter, e.g. btc:mainnet - toAddress - string, string, accepted address - satoshis - number, the number of satoshis to be sent - options - Object (optional) - feeRate - number (optional) customised fee rate ***Return Value*** - Promise - string The transaction hash ***Example*** ```ts let chain = "btc:mainnet" let toAddress = '1NKnZ3uAuQLnmE...4u1efwCgTiAxBn' // pattern测试钱包的legacy地址 let satoshis = 17000 let options = { feeRate: 16 } let result = okxBtcProvider.sendBitcoin(chain, toAddress, satoshis, options) /** Return structure: "ff18d01ef6abed3b7fd23247a1fc457ca...f49b6bb4529a19a5fb637f18ce2e" */ ``` ## signPsbt `okxBtcProvider.signPsbt(chainId, psbtHex, options);` ***Request Parameterseters*** - chain - string, the chain for which the signature is requested, must be passed, e.g. btc:mainnet - psbtHex - string, the hexadecimal string of the psbt to be signed. - options. - autoFinalized - boolean: whether the psbt is finalised after signing, default is true - toSignInputs - array: - index - number: the input to sign - address - string: the address of the corresponding private key to be used for signing - publicKey - string: the public key of the corresponding private key to be used for signature - sighashTypes - number[]: (optional) sighashTypes - disableTweakSigner - boolean: (optional) When signing and unlocking Taproot addresses, tweakSigner is used to generate signatures by default, enable this option to allow signing with the original private key. ***Return Values*** - Promise - string hex string of the signed psbt. ***Example*** ```ts let chain = "btc:mainnet" let psbtHex = "" let options = { autoFinalized: false } let result = okxBtcProvider.signPsbt(chain, psbtHex, options) /** Return structure: "cHNidP8BAP0GAQIAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAA/////yjWH1Uvx225V01diYYZ2i5jVAORF4nLWUWCg5bBaLQwAAAAAAD/////AwEAAAAAAAAAIlEgwSVNrUCq6hIeU+DOwJmGNi9s1CInltGUjJR5GzUoHLUBAAAAAAAAACJRIMElTa1AquoSHlPgzsCZhjYvbNQiJ5bRlIyUeRs1KBy1AIb9jA0AAAAiUSDwUTBk/h5bXDG+3/Q7lD8vEhHRSrKJFockGxONIUiI4wAAAAAAAQErAQAAAAAAAAAiUSDBJU2tQKrqEh5T4M7AmYY2L2zUIieW0ZSMlHkbNSgctQETQD9magM5RHYbdRd4KZ70FfVEAW5hw3rLjrocWIyn2Gi2P2c6Gri0E/S/wREhgjM8u5zQ3GrpcSaC8KhCRxBq5/oBFyANVBOudKlTUiKevmZzGqdVcp6Y8XbMOTfPV03fEyLOFgABASsBAAAAAAAAACJRIMElTa1AquoSHlPgzsCZhjYvbNQiJ5bRlIyUeRs1KBy1ARNA83DNEJj5u/mgUoOhCWL07enXpb6RX/WfEBh97tyrXLlA/e0CowU1fpgrKn+PQ+9Z/5/EXGwcr1UkYaqBJ0ZpKQEXIA1UE650qVNSIp6+ZnMap1Vynpjxdsw5N89XTd8TIs4WAAEBK+gDAAAAAAAAIlEg8FEwZP4eW1wxvt/0O5Q/LxIR0UqyiRaHJBsTjSFIiOMBAwSDAAAAARNBZcHpcb6YDNWF+eIcFckjF1c8C83uRmEhS/8jJQOBFkIQol8hBCTYXOFAaeu6/4o2MsS20iITiM/rAOAOBZkXC4MBFyANVBOudKlTUiKevmZzGqdVcp6Y8XbMOTfPV03fEyLOFgABBSBhbicyOEDuDCrkNNmYJn+BFwmIupR3943NAPwkeifbQAABBSBhbicyOEDuDCrkNNmYJn+BFwmIupR3943NAPwkeifbQAABBSCJNrNn1Hs3lrQwoxaUMgkYr9xFjYHeqbt901wKrYvGlAA=" */ ``` ## Sign multiple Psbts ``` okxBtcProvider.signPsbts(chainId, psbtHexs, options); ``` ***Request Parameters*** - chainId - string, the chain for which the signature execution is requested, mandatory parameter, e.g. btc:mainnet - psbtHexs - string[], hexadecimal string of the psbt to be signed. - options - object[], a hexadecimal string of the psbt to be signed. - autoFinalized - boolean: whether the psbt is finalised after signing, default is true - toSignInputs - array: - index - number: the input to sign - address - string: the address of the corresponding private key to be used for signing - publicKey - string: the public key of the corresponding private key to be used for signature - sighashTypes - number[]: (optional) sighashTypes - disableTweakSigner - boolean: (optional) When signing and unlocking Taproot addresses, tweakSigner is used to generate signatures by default, enable this option to allow signing with the original private key. ***Return Values*** - Promise - string[] Hexadecimal string of the signed psbt. ***Example*** ```ts let chain = "btc:mainnet" let psbtHexs = [""] let options = [{ autoFinalized: false }] let result = okxBtcProvider.signPsbts(chain, psbtHexs, options) /** Return structure: ["cHNidP8BAP0GAQIAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAA/////yjWH1Uvx225V01diYYZ2i5jVAORF4nLWUWCg5bBaLQwAAAAAAD/////AwEAAAAAAAAAIlEgwSVNrUCq6hIeU+DOwJmGNi9s1CInltGUjJR5GzUoHLUBAAAAAAAAACJRIMElTa1AquoSHlPgzsCZhjYvbNQiJ5bRlIyUeRs1KBy1AIb9jA0AAAAiUSDwUTBk/h5bXDG+3/Q7lD8vEhHRSrKJFockGxONIUiI4wAAAAAAAQErAQAAAAAAAAAiUSDBJU2tQKrqEh5T4M7AmYY2L2zUIieW0ZSMlHkbNSgctQETQD9magM5RHYbdRd4KZ70FfVEAW5hw3rLjrocWIyn2Gi2P2c6Gri0E/S/wREhgjM8u5zQ3GrpcSaC8KhCRxBq5/oBFyANVBOudKlTUiKevmZzGqdVcp6Y8XbMOTfPV03fEyLOFgABASsBAAAAAAAAACJRIMElTa1AquoSHlPgzsCZhjYvbNQiJ5bRlIyUeRs1KBy1ARNA83DNEJj5u/mgUoOhCWL07enXpb6RX/WfEBh97tyrXLlA/e0CowU1fpgrKn+PQ+9Z/5/EXGwcr1UkYaqBJ0ZpKQEXIA1UE650qVNSIp6+ZnMap1Vynpjxdsw5N89XTd8TIs4WAAEBK+gDAAAAAAAAIlEg8FEwZP4eW1wxvt/0O5Q/LxIR0UqyiRaHJBsTjSFIiOMBAwSDAAAAARNBZcHpcb6YDNWF+eIcFckjF1c8C83uRmEhS/8jJQOBFkIQol8hBCTYXOFAaeu6/4o2MsS20iITiM/rAOAOBZkXC4MBFyANVBOudKlTUiKevmZzGqdVcp6Y8XbMOTfPV03fEyLOFgABBSBhbicyOEDuDCrkNNmYJn+BFwmIupR3943NAPwkeifbQAABBSBhbicyOEDuDCrkNNmYJn+BFwmIupR3943NAPwkeifbQAABBSCJNrNn1Hs3lrQwoxaUMgkYr9xFjYHeqbt901wKrYvGlAA="] */ ``` ## Sign and Push psbt > required App: >= 6.93.0 `okxBtcProvider.signAndPushPsbt(chainId, psbtHex, options);` ***Request Parameterseters*** - chain - string, the chain for which the signature is requested, must be passed, e.g. btc:mainnet - psbtHex - string, the hexadecimal string of the psbt to be signed. - options: - object - autoFinalized - boolean: whether the psbt is finalised after signing, default is true - toSignInputs - array: - index - number: the input to sign - address - string: the address of the corresponding private key to be used for signing - publicKey - string: the public key of the corresponding private key to be used for signing - sighashTypes - number[]: (optional) sighashTypes - disableTweakSigner - boolean: (optional) When signing and unlocking Taproot addresses, tweakSigner is used to generate signatures by default, enable this option to allow signing with the original private key. ***Returns a value*** - Promise - object - txhash Transaction hash - signature Hexadecimal string of the signed psbt. ***Example*** ```ts let chain = "btc:mainnet" let psbtHex = "" let options = { autoFinalized: false } let result = okxBtcProvider.signAndPushPsbt(chain, psbtHex, options) /** Return structure: { txhash: "", signature: "" } */ ``` ## Disconnect wallet Disconnect the connected wallet and delete the current session. If you want to switch the connected wallet, please disconnect the current wallet first. ```typescript okxUniversalProvider.disconnect(); ``` ## Event ```typescript // Generate universalLink okxUniversalProvider.on('display_uri', (uri) => { console.log(uri); }); // Session information changes will trigger this event; okxUniversalProvider.on('session_update', (session) => { console.log(JSON.stringify(session)); // Session information changes (e.g., adding a custom chain). }); // Disconnecting triggers this event; okxUniversalProvider.on('session_delete', ({topic}) => { console.log(topic); }); ``` ## Error codes Exceptions that may be thrown during connection, transaction, and disconnection. **Exception** | Error Code | Description | |----------------------------------------------|-------------------------| | OKX_CONNECT_ERROR_CODES.UNKNOWN_ERROR | Unknown Error | | OKX_CONNECT_ERROR_CODES.ALREADY_CONNECTED_ERROR | Wallet Already Connected | | OKX_CONNECT_ERROR_CODES.NOT_CONNECTED_ERROR | Wallet Not Connected | | OKX_CONNECT_ERROR_CODES.USER_REJECTS_ERROR | User Rejected | | OKX_CONNECT_ERROR_CODES.METHOD_NOT_SUPPORTED | Method Not Supported | | OKX_CONNECT_ERROR_CODES.CHAIN_NOT_SUPPORTED | Chain Not Supported | | OKX_CONNECT_ERROR_CODES.WALLET_NOT_SUPPORTED | Wallet Not Supported | | OKX_CONNECT_ERROR_CODES.CONNECTION_ERROR | Connection Error | ```typescript export enum OKX_CONNECT_ERROR_CODES { UNKNOWN_ERROR = 0, ALREADY_CONNECTED_ERROR = 11, NOT_CONNECTED_ERROR = 12, USER_REJECTS_ERROR = 300, METHOD_NOT_SUPPORTED = 400, CHAIN_NOT_SUPPORTED = 500, WALLET_NOT_SUPPORTED = 600, CONNECTION_ERROR = 700 } ``` - [UI](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-bitcoin-ui.md) # UI ## Installation and Initialization Make sure to update the OKX App to version 6.92.0 or later to begin access: To integrate OKX Connect into your DApp, you can use npm: ``` npm install @okxconnect/ui npm install @okxconnect/universal-provider ``` Before connecting to the wallet, you need to create an object that can provide a UI interface for subsequent operations such as connecting to the wallet and sending transactions. ```typescript OKXUniversalConnectUI.init(dappMetaData, actionsConfiguration, uiPreferences, language) ``` **Request Parameterseters** - dappMetaData - object - name - string: The name of the application, will not be used as a unique representation. - icon - string: URL of the application icon, must be in PNG, ICO, etc. SVG icons are not supported. SVG icons are not supported. It is best to pass a url pointing to a 180x180px PNG icon. - actionsConfiguration - object - modals - ('before' | 'success' | 'error')[] | 'all' The modes of displaying alerts during transaction, defaults to 'before'. - returnStrategy -string 'none' | `${string}://${string}`; for app wallet, specify the return strategy for the deep link when the user signs/rejects the request, if it is in telegram, you can configure tg://resolve - uiPreferences -object - theme - Theme can be: THEME.DARK, THEME.LIGHT, 'SYSTEM'. - language - 'en_US' | 'ru_RU' | 'zh_CN' | 'ar_AE' | 'cs_CZ' | 'de_DE' | 'es_ES' | 'es_LAT' | 'fr_FR' | 'id_ID' | 'it_IT' | 'nl_NL' | 'pl_PL' | 'pt_BR' | 'pt_PT' | 'ro_RO' | 'tr_TR' | 'uk_UA' | 'vi_VN'. , defaults to en_US **Return value** - OKXUniversalConnectUI **Example** ```typescript import { OKXUniversalConnectUI } from "@okxconnect/ui"; const okxUniversalConnectUI = await OKXUniversalConnectUI.init({ dappMetaData: { icon: "https://static.okx.com/cdn/assets/imgs/247/58E63FEA47A2B7D7.png", name: "OKX Connect UI Demo" }, actionsConfiguration: { returnStrategy: 'tg://resolve', modals:"all" }, language: "en_US", uiPreferences: { theme: THEME.LIGHT }, }); ``` ## Connecting to OKX wallet Connecting to a wallet goes to get the wallet address as an identifier and the necessary parameters used to sign the transaction; ```typescript okxUniversalConnectUI.connect(connectParams: ConnectParams); ``` **Request Parameterseters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace ; Optional information for requesting a connection, the key is 'eip155' for EVM, or 'btc' for BTC, if any of the requested chain is not supported by the wallet, the wallet will reject the connection; - chains: string[]; Chain id information - defaultChain?: string; default chain - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information for connection request, the key is 'eip155' for EVM system and 'btc' for BTC system, if the corresponding chain information is not supported by the wallet, you can still connect; - chains: string[]; Chain id information, chain information of the wallet - defaultChain?: string; default chain - sessionConfig: object - redirect: string Jump parameter after successful connection, if it is Mini App in Telegram, here can be set to Telegram's deeplink: 'tg://resolve' **Return value** - Promise `` - topic: string; the session identifier - namespaces: `Record`; namespace information for a successful connection - chains: string[]; Chain information for the connection - accounts: string[]; accounts information for the connection - methods: string[]; methods supported by the wallet under the current namespace - defaultChain?: string; The default chain for the current session - sessionConfig?: SessionConfig - dappInfo: object DApp information - name:string - icon:string - redirect?: string, the redirect parameter after successful connection **Example** ```typescript var session = await okxUniversalConnectUI.connect({ namespaces: { btc: { chains: [ "btc:mainnet", // "fractal:mainnet" ], } }, sessionConfig: { redirect: "tg://resolve" } }) ``` ## Connect to wallet and sign Connect to the wallet to get the wallet address and sign the data; the result will be called back in the event 'connect_signResponse' ``` await okxUniversalConnectUI.openModalAndSign(connectParams: ConnectParams, signRequest: RequestParams[]); ``` **Request Parameters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace ; Optional information for requesting a connection, the key for the BTC system is 'btc', if any of the requested chains is not supported by the wallet, the wallet will reject the connection; - chains: string[]; chain id information - defaultChain?: string; default chain - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information of the requested connection, the key of BTC is 'btc', if the corresponding chain information is not supported by the wallet, it can still be connected; - chains: string[]; chain id information - defaultChain?: string; default chain - sessionConfig: object - redirect: string The jump parameter after successful connection, if it is Mini App in Telegram, here can be set to Telegram's deeplink: 'tg://resolve' - signRequest - RequestParams[]; the method to request the connection and sign the request, at most one method can be supported at the same time; - method: string; the name of the requested method, the BTC system supports methods such as 'btc_signMessage'; - chainId: string; the ID of the chain in which the method is executed, the chainId must be included in the namespaces above; - params: unknown[] | Record`` | object | undefined; Parameters corresponding to the requested method; **Return Value** - Promise `` - topic: string; the session identifier; - namespaces: `Record`; namespace information for a successful connection; - chains: string[]; Chain information for the connection; - accounts: string[]; accounts information for the connection; - methods: string[]; Methods supported by the wallet in the current namespace; - defaultChain?: string; The default chain for the current session. - sessionConfig?: SessionConfig - dappInfo: object DApp information; - name: string - icon:string **Example** ```typescript // Add the signature result listener first okxUniversalConnectUI.on("connect_signResponse", (signResponse) => { console.log(signResponse); }); var session = await okxUniversalConnectUI.openModalAndSign({ namespaces: { btc: { chains: [ "btc:mainnet", // "fractal:mainnet" ], } }, sessionConfig: { redirect: "tg://resolve" } }, [ { method: "btc_signMessage", chainId: "btc:mainnet", params: { message: "Welcome to BTC" } } ]) ``` ## Determine if the wallet is connected Gets whether the wallet is currently connected. **Return Value** - boolean **Example** ```typescript universalUi.connected(); ``` ## Prepare to trade First create an OKXBtcProvider object, the constructor passes in okxUniversalConnectUI ```typescript import { OKXBtcProvider } from '@okxconnect/universal-provider'; let okxBtcProvider = new OKXBtcProvider(okxUniversalConnectUI) ``` ## Get wallet account information ```typescript okxBtcProvider.getAccount(chainId); ``` ***Request Parameterseters*** - chainId: the requested chain, e.g. btc:mainnet, fractal:mainnet ***Return Value*** - Object - address: string wallet address - publicKey: string public key ***Example*** ```typescript let result = okxBtcProvider.getAccount('btc:mainnet') // return structure { "address": "038936b367d47b3796b430a31694320918afdc458d81dea9bb7dd35c0aad8bc694", "publicKey": "03cbaedc26f03fd3ba02fc936f338e980c9e2172c5e23128877ed46827e935296f" } ``` ## signMessage ```typescript okxBtcProvider.signMessage(chain, message, type?); ``` ***Request Parameterseters*** - chain - string, the chain of the requested execution method - signStr - string the message to be signed - type - (optional) 'ecdsa' | 'bip322-simple', default is 'ecdsa'. ***Return Value*** - Promise - string: Signature result ***Example*** ```ts let chain = "btc:mainnet" let signStr = "data need to sign ..." let result = okxBtcProvider.signMessage(chain, signStr) //Return structure: "H83jZpulbMDDGUiTA4M8QNChmWwaKxwPCm8U5EBvftKlSMMzuvtVxBHlygtof5NBbdSVPiAtCvOUwZmz2vViHHU=" ``` ## Send Bitcoin ``` okxBtcProvider.sendBitcoin(chainId, toAddress, satoshis, options); ``` ***Request Parameterseters*** - chainId - string, the chain for which the signature is requested to be executed, mandatory parameter, e.g. btc:mainnet - toAddress - string, string, accepted address - satoshis - number, the number of satoshis to be sent - options - Object (optional) - feeRate - number (optional) customised fee rate ***Return Value*** - Promise - string The transaction hash ***Example*** ```ts let chain = "btc:mainnet" let toAddress = '1NKnZ3uAuQLnmE...4u1efwCgTiAxBn' let satoshis = 17000 let options = { feeRate: 16 } let result = okxBtcProvider.sendBitcoin(chain, toAddress, satoshis, options) /** Return structure: "ff18d01ef6abed3b7fd23247a1fc457ca...f49b6bb4529a19a5fb637f18ce2e" */ ``` ## signPsbt ``` okxBtcProvider.signPsbt(chainId, psbtHex, options); ``` ***Request Parameterseters*** - chain - string, the chain for which the signature is requested, must be passed, e.g. btc:mainnet - psbtHex - string, the hexadecimal string of the psbt to be signed. - options. - autoFinalized - boolean: whether the psbt is finalised after signing, default is true - toSignInputs - array: - index - number: the input to sign - address - string: the address of the corresponding private key to be used for signing - publicKey - string: the public key of the corresponding private key to be used for signature - sighashTypes - number[]: (optional) sighashTypes - disableTweakSigner - boolean: (optional) When signing and unlocking Taproot addresses, tweakSigner is used to generate signatures by default, enable this option to allow signing with the original private key. ***Return Values*** - Promise - string hex string of the signed psbt. ***Example*** ```ts let chain = "btc:mainnet" let psbtHex = "" let options = { autoFinalized: false } let result = okxBtcProvider.signPsbt(chain, psbtHex, options) /** Return structure: "cHNidP8BAP0GAQIAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAA/////yjWH1Uvx225V01diYYZ2i5jVAORF4nLWUWCg5bBaLQwAAAAAAD/////AwEAAAAAAAAAIlEgwSVNrUCq6hIeU+DOwJmGNi9s1CInltGUjJR5GzUoHLUBAAAAAAAAACJRIMElTa1AquoSHlPgzsCZhjYvbNQiJ5bRlIyUeRs1KBy1AIb9jA0AAAAiUSDwUTBk/h5bXDG+3/Q7lD8vEhHRSrKJFockGxONIUiI4wAAAAAAAQErAQAAAAAAAAAiUSDBJU2tQKrqEh5T4M7AmYY2L2zUIieW0ZSMlHkbNSgctQETQD9magM5RHYbdRd4KZ70FfVEAW5hw3rLjrocWIyn2Gi2P2c6Gri0E/S/wREhgjM8u5zQ3GrpcSaC8KhCRxBq5/oBFyANVBOudKlTUiKevmZzGqdVcp6Y8XbMOTfPV03fEyLOFgABASsBAAAAAAAAACJRIMElTa1AquoSHlPgzsCZhjYvbNQiJ5bRlIyUeRs1KBy1ARNA83DNEJj5u/mgUoOhCWL07enXpb6RX/WfEBh97tyrXLlA/e0CowU1fpgrKn+PQ+9Z/5/EXGwcr1UkYaqBJ0ZpKQEXIA1UE650qVNSIp6+ZnMap1Vynpjxdsw5N89XTd8TIs4WAAEBK+gDAAAAAAAAIlEg8FEwZP4eW1wxvt/0O5Q/LxIR0UqyiRaHJBsTjSFIiOMBAwSDAAAAARNBZcHpcb6YDNWF+eIcFckjF1c8C83uRmEhS/8jJQOBFkIQol8hBCTYXOFAaeu6/4o2MsS20iITiM/rAOAOBZkXC4MBFyANVBOudKlTUiKevmZzGqdVcp6Y8XbMOTfPV03fEyLOFgABBSBhbicyOEDuDCrkNNmYJn+BFwmIupR3943NAPwkeifbQAABBSBhbicyOEDuDCrkNNmYJn+BFwmIupR3943NAPwkeifbQAABBSCJNrNn1Hs3lrQwoxaUMgkYr9xFjYHeqbt901wKrYvGlAA=" */ ``` ## Sign multiple Psbts ``` okxBtcProvider.signPsbts(chainId, psbtHexs, options); ``` ***Request Parameters*** - chainId - string, the chain for which the signature execution is requested, mandatory parameter, e.g. btc:mainnet - psbtHexs - string[], hexadecimal string of the psbt to be signed. - options - object[], a hexadecimal string of the psbt to be signed. - autoFinalized - boolean: whether the psbt is finalised after signing, default is true - toSignInputs - array: - index - number: the input to sign - address - string: the address of the corresponding private key to be used for signing - publicKey - string: the public key of the corresponding private key to be used for signing - sighashTypes - number[]: (optional) sighashTypes - disableTweakSigner - boolean: (optional) When signing and unlocking Taproot addresses, tweakSigner is used to generate signatures by default, enable this option to allow signing with the original private key. ***Return Value*** - Promise - string[] hex string of signed psbt ***Example*** ```ts let chain = "btc:mainnet" let psbtHexs = [""] let options = [{ autoFinalized: false }] let result = okxBtcProvider.signPsbts(chain, psbtHexs, options) /** Return structure: ["cHNidP8BAP0GAQIAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAA/////yjWH1Uvx225V01diYYZ2i5jVAORF4nLWUWCg5bBaLQwAAAAAAD/////AwEAAAAAAAAAIlEgwSVNrUCq6hIeU+DOwJmGNi9s1CInltGUjJR5GzUoHLUBAAAAAAAAACJRIMElTa1AquoSHlPgzsCZhjYvbNQiJ5bRlIyUeRs1KBy1AIb9jA0AAAAiUSDwUTBk/h5bXDG+3/Q7lD8vEhHRSrKJFockGxONIUiI4wAAAAAAAQErAQAAAAAAAAAiUSDBJU2tQKrqEh5T4M7AmYY2L2zUIieW0ZSMlHkbNSgctQETQD9magM5RHYbdRd4KZ70FfVEAW5hw3rLjrocWIyn2Gi2P2c6Gri0E/S/wREhgjM8u5zQ3GrpcSaC8KhCRxBq5/oBFyANVBOudKlTUiKevmZzGqdVcp6Y8XbMOTfPV03fEyLOFgABASsBAAAAAAAAACJRIMElTa1AquoSHlPgzsCZhjYvbNQiJ5bRlIyUeRs1KBy1ARNA83DNEJj5u/mgUoOhCWL07enXpb6RX/WfEBh97tyrXLlA/e0CowU1fpgrKn+PQ+9Z/5/EXGwcr1UkYaqBJ0ZpKQEXIA1UE650qVNSIp6+ZnMap1Vynpjxdsw5N89XTd8TIs4WAAEBK+gDAAAAAAAAIlEg8FEwZP4eW1wxvt/0O5Q/LxIR0UqyiRaHJBsTjSFIiOMBAwSDAAAAARNBZcHpcb6YDNWF+eIcFckjF1c8C83uRmEhS/8jJQOBFkIQol8hBCTYXOFAaeu6/4o2MsS20iITiM/rAOAOBZkXC4MBFyANVBOudKlTUiKevmZzGqdVcp6Y8XbMOTfPV03fEyLOFgABBSBhbicyOEDuDCrkNNmYJn+BFwmIupR3943NAPwkeifbQAABBSBhbicyOEDuDCrkNNmYJn+BFwmIupR3943NAPwkeifbQAABBSCJNrNn1Hs3lrQwoxaUMgkYr9xFjYHeqbt901wKrYvGlAA="] */ ``` ## Sign and Push psbt > required App: >= 6.93.0 ```typescript okxBtcProvider.signAndPushPsbt(chainId, psbtHex, options); ``` ***Request Parameterseters*** - chain - string, the chain for which the signature is requested, must be passed, e.g. btc:mainnet - psbtHex - string, hexadecimal string of the psbt to be signed. - options: - object - autoFinalized - boolean: whether the psbt is finalised after signing, default is true - toSignInputs - array: - index - number: the input to sign - address - string: the address of the corresponding private key to be used for signing - publicKey - string: the public key of the corresponding private key to be used for signing - sighashTypes - number[]: (optional) sighashTypes - disableTweakSigner - boolean: (optional) When signing and unlocking Taproot addresses, tweakSigner is used to generate signatures by default, enable this option to allow signing with the original private key. ***Return Value*** - Promise - object - txhash Transaction hash - signature hex string of signed psbt ***Example*** ```ts let chain = "btc:mainnet" let psbtHex = "" let options = { autoFinalized: false } let result = okxBtcProvider.signAndPushPsbt(chain, psbtHex, options) /** Return structure: { txhash: "", signature: "" } */ ``` ## Disconnect wallet Disconnect the connected wallet and delete the current session. If you want to switch the connected wallet, please disconnect the current wallet first. ```typescript okxUniversalConnectUI.disconnect(); ``` ## Event ```typescript // Generate universalLink okxUniversalConnectUI.on("display_uri", (uri) => { console.log(uri); }); // Session information changes will trigger this event; okxUniversalConnectUI.on("session_update", (session) => { console.log(JSON.stringify(session)); }); // Disconnecting triggers this event; okxUniversalConnectUI.on("session_delete", ({topic}) => { console.log(topic); }); // This event is triggered when a connection is made and the signature is signed. okxUniversalConnectUI.on("connect_signResponse", (signResponse) => { console.log(signResponse); }); ``` ## Error codes Exceptions that may be thrown during connection, transaction, and disconnection. **Exception** | Error Code | Description | |----------------------------------------------|-------------------------| | OKX_CONNECT_ERROR_CODES.UNKNOWN_ERROR | Unknown Error | | OKX_CONNECT_ERROR_CODES.ALREADY_CONNECTED_ERROR | Wallet Already Connected | | OKX_CONNECT_ERROR_CODES.NOT_CONNECTED_ERROR | Wallet Not Connected | | OKX_CONNECT_ERROR_CODES.USER_REJECTS_ERROR | User Rejected | | OKX_CONNECT_ERROR_CODES.METHOD_NOT_SUPPORTED | Method Not Supported | | OKX_CONNECT_ERROR_CODES.CHAIN_NOT_SUPPORTED | Chain Not Supported | | OKX_CONNECT_ERROR_CODES.WALLET_NOT_SUPPORTED | Wallet Not Supported | | OKX_CONNECT_ERROR_CODES.CONNECTION_ERROR | Connection Error | ```typescript export enum OKX_CONNECT_ERROR_CODES { UNKNOWN_ERROR = 0, ALREADY_CONNECTED_ERROR = 11, NOT_CONNECTED_ERROR = 12, USER_REJECTS_ERROR = 300, METHOD_NOT_SUPPORTED = 400, CHAIN_NOT_SUPPORTED = 500, WALLET_NOT_SUPPORTED = 600, CONNECTION_ERROR = 700 } ``` - [Solana-Compatible Chains](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-solana.md) # Solana-Compatible Chains Solana is a high-performance blockchain platform committed to providing fast, secure, and scalable solutions for decentralized applications and cryptocurrencies. The platform utilizes an innovative consensus algorithm called Proof of History (PoH) that can handle tens of thousands of transactions per second (TPS) while maintaining decentralization and security. Overall, Solana aims to achieve mass adoption of blockchain through its unique technological advantages, catering to various complex decentralized applications and global financial systems. Common Solana-compatible networks include SOON, Sonic, etc.
  • If connecting via SDK, add a "Connect OKX Wallet" button within the DApp. Clicking this button will launch the mobile App Wallet and enable interaction with the OKX Wallet, such as retrieving addresses, initiating wallet signatures, and other functions.
  • In addition to SDK, we also provide a UI interface.
- [SDK](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-solana-sdk.md) # SDK ## Installation and Initialization Make sure to update the OKX App to version 6.90.1 or later to start integrating OKX Connect into your DApp can be done using npm: ``` npm install @okxconnect/solana-provider ``` Before connecting the wallet, you need to create an object for subsequent wallet connections, transaction submissions, and other operations. ``` OKXUniversalProvider.init({dappMetaData: {name, icon}}) ``` **Request Parameters** - dappMetaData - object - name - string: the name of the application, will not be used as a unique representation. - icon - string: URL of the application icon, must be in PNG, ICO, etc. SVG icons are not supported. SVG icons are not supported. It is better to pass a url pointing to a 180x180px PNG icon. **Returns a value** - OKXUniversalProvider **Example** ```typescript import { OKXUniversalProvider } from "@okxconnect/universal-provider"; const okxUniversalProvider = await OKXUniversalProvider.init({ dappMetaData: { name: "application name", icon: "application icon url" }, }) ``` ## Connect to Wallet Connect the wallet to obtain the wallet address, which serves as an identifier and is necessary for signing transactions. ``` okxUniversalProvider.connect(connectParams: ConnectParams); ``` **Request Parameters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace ; information necessary to request a connection, the key for Solana is "solana" . If any of the requested chains are not supported by the wallet, the wallet will reject the connection; - chains: string[]; Chain id information - defaultChain?: string; default chain - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information for requesting a connection, the key for Solana is "solana". If the corresponding chain information is not supported by the wallet, the connection can still be made - chains: string[]; Chain id information - defaultChain?: string; default chain - sessionConfig: object - redirect: string Jump parameter after successful connection, if it is Mini App in Telegram, here can be set deeplink: "tg://resolve" in Telegram - Promise `` - topic: string; The session identifier; - namespaces: `Record`; namespace information for a successful connection - chains: string[]; Chain information for the connection - accounts: string[]; accounts information for the connection - methods: string[]; methods supported by the wallet under the current namespace - defaultChain?: string; default chain for the current session - sessionConfig?: SessionConfig - dappInfo: object DApp information - name:string - icon:string - redirect?: string, the redirect parameter after successful connection **Example** ```typescript var session = await okxUniversalProvider.connect({ namespaces: { solana: { chains: ["solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", // solana mainnet // "sonic:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",// sonic mainnet // "solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z",// solana testnet // "sonic:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z",// sonic testnet ; ], } }, sessionConfig: { redirect: "tg://resolve" } }) ``` ## Determine if the wallet is connected Gets whether the wallet is currently connected **Return Value** - boolean **Example** ```typescript okxUniversalProvider.connected(); ``` ## Sending Signature and Transactions This method allows sending messages to the wallet, supporting signatures, transactions First create an OKXSolanaProvider object, passing OKXUniversalProvider into the constructor ```typescript import { OKXSolanaProvider } from "@okxconnect/solana-provider/OKXSolanaProvider"; let okxSolanaProvider = new OKXSolanaProvider(okxUniversalProvider) ``` ## Signature `okxSolanaProvider.signMessage(message, chain);` **Request Parameters** - message - string, the message to be signed - chain: string, the chain for which the signature is requested, recommended to pass this parameter; mandatory when connecting multiple chains; if a chain is not passed, it will be treated as solana:mainnet or sonic:mainnet **Return Value** - Promise - object - publicKey:string wallet address - signature:Uint8Array Signature result ## Signature for single transaction ``` okxSolanaProvider.signTransaction(transaction, chain); ``` **Request Parameterseters** - transaction - Transaction | VersionedTransaction transaction data object - chain: string, the chain for which the signature execution is requested, it is recommended to pass this parameter; it is mandatory to pass this parameter when connecting multiple chains; connecting a chain without passing it will be handled according to solana:mainnet or sonic:mainnet **Return value** - Promise - Transaction | VersionedTransaction signed transaction object ***Signs multiple transactions*** `okxSolanaProvider.signAllTransactions(transactions, chain);` **Request Parameterseters** - transactions - [Transaction | VersionedTransaction] Array of transaction data objects - chain: string, the chain for which the signature execution is requested, it is recommended to pass this parameter; it is mandatory to pass this parameter when connecting multiple chains; connecting a chain without passing it will be handled according to solana:mainnet or sonic:mainnet **Return value** - Promise - [Transaction | VersionedTransaction] An array of signed transaction objects ## Signs a transaction and broadcasts on chain ``` okxSolanaProvider.signAllTransactions(transactions, chain); ``` **Request Parameters - transactions - Transaction | VersionedTransaction transaction data object - chain: string, the chain for which the signature execution is requested, it is recommended to pass this parameter; it is mandatory to pass this parameter when connecting multiple chains; connecting a chain without passing it will be handled according to solana:mainnet or sonic:mainnet; **Return Value - Promise - string transactionhash ## get wallet address and pubKey ``` okxSolanaProvider.getAccount(chain); ``` **Request Parameters** - chain: string, get the chain id of the wallet address, if not passed then the first connected svm address will be taken by default **Return Value** - Object - address: string wallet address - publicKey: PublicKey **Example** ```typescript // Signing a transfer transaction on solana mainnet let provider = new OKXSolanaProvider(okxUniversalProvider) const transaction = new Transaction({ feePayer: new PublicKey(provider.getAccount().address), recentBlockhash: "xNWbUfdEPktMsZQHY6Zk5RJqamWFcTKasekjr7c3wFX", }).add(SystemProgram.transfer( { fromPubkey: new PublicKey(provider.getAccount().address), toPubkey: new PublicKey(provider.getAccount().address), lamports: 1000, } )) let result = await provider.signTransaction(transaction, "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp") ``` ## Disconnect wallet Disconnect from a connected wallet and delete the current session. If you want to switch wallets, disconnect from the current wallet first ```typescript okxUniversalProvider.disconnect(); ``` ## Event ```typescript // Generate universalLink okxUniversalProvider.on('display_uri', (uri) => { console.log(uri); }); // Session information changes will trigger this event; okxUniversalProvider.on('session_update', (session) => { console.log(JSON.stringify(session)); // Session information changes (e.g., adding a custom chain). }); // Disconnecting triggers this event; okxUniversalProvider.on('session_delete', ({topic}) => { console.log(topic); }); ``` ## Error codes Exceptions that may be thrown during connection, transaction, and disconnection **Exception** | Error Code | Description | |----------------------------------------------|-------------------------| | OKX_CONNECT_ERROR_CODES.UNKNOWN_ERROR | Unknown Error | | OKX_CONNECT_ERROR_CODES.ALREADY_CONNECTED_ERROR | Wallet Already Connected | | OKX_CONNECT_ERROR_CODES.NOT_CONNECTED_ERROR | Wallet Not Connected | | OKX_CONNECT_ERROR_CODES.USER_REJECTS_ERROR | User Rejected | | OKX_CONNECT_ERROR_CODES.METHOD_NOT_SUPPORTED | Method Not Supported | | OKX_CONNECT_ERROR_CODES.CHAIN_NOT_SUPPORTED | Chain Not Supported | | OKX_CONNECT_ERROR_CODES.WALLET_NOT_SUPPORTED | Wallet Not Supported | | OKX_CONNECT_ERROR_CODES.CONNECTION_ERROR | Connection Error | ```typescript export enum OKX_CONNECT_ERROR_CODES { UNKNOWN_ERROR = 0, ALREADY_CONNECTED_ERROR = 11, NOT_CONNECTED_ERROR = 12, USER_REJECTS_ERROR = 300, METHOD_NOT_SUPPORTED = 400, CHAIN_NOT_SUPPORTED = 500, WALLET_NOT_SUPPORTED = 600, CONNECTION_ERROR = 700 } ``` - [UI](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-solana-ui.md) # UI ## Installation and Initialisation Make sure to update the OKX App to version 6.90.1 or later to start accessing: To integrate OKX Connect into your DApp, you can use npm: ``` npm install @okxconnect/ui npm install @okxconnect/solana-provider ``` Before connecting to the wallet, you need to create an object that can provide a UI interface for subsequent operations such as connecting to the wallet and sending transactions. ``` OKXUniversalConnectUI.init(dappMetaData, actionsConfiguration, uiPreferences, language) ``` **Request Parameterseters** - dappMetaData - object - name - string: name of the application, will not be used as a unique representation - icon - string: URL of the application icon, must be in PNG, ICO, etc. SVG icons are not supported. SVG icons are not supported. It is best to pass a url pointing to a 180x180px PNG icon. - actionsConfiguration - object - modals - ('before' | 'success' | 'error')[] | 'all' The modes of displaying alerts during transaction, defaults to 'before'. - returnStrategy -string 'none' | `${string}://${string}`; for app wallet, specify the return strategy of the deep link when the user signs/rejects the request, in case of telegram, you can configure tg://resolve - uiPreferences -object - theme - Theme can be: THEME.DARK, THEME.LIGHT, 'SYSTEM'. - language - 'en_US' | 'ru_RU' | 'zh_CN' | 'ar_AE' | 'cs_CZ' | 'de_DE' | 'es_ES' | 'es_LAT' | 'fr_FR' | 'id_ID' | 'it_IT' | 'nl_NL' | 'pl_PL' | 'pt_BR' | 'pt_PT' | 'ro_RO' | 'tr_TR' | 'uk_UA' | 'vi_VN'. , defaults to en_US **Return value** - OKXUniversalConnectUI **Examples** ```typescript import { OKXUniversalConnectUI } from '@okxconnect/ui'; const universalUi = await OKXUniversalConnectUI.init({ dappMetaData: { icon: 'https://static.okx.com/cdn/assets/imgs/247/58E63FEA47A2B7D7.png', name: 'OKX Connect Demo' }, actionsConfiguration: { returnStrategy: 'tg://resolve', modals: 'all', tmaReturnUrl:'back' }, language: 'en_US', uiPreferences: { theme: THEME.LIGHT }, }); // Switching the plugin to connect to the wallet fires this event; universalUi.on('accountChanged', (session) => { if (session){ console.log(`accountChanged `, JSON.stringify(session)); } }); ``` ## Connect to the wallet Connects to the wallet to get the wallet address as an identifier and the necessary parameters used to sign the transaction. ``` universalUi.openModal(connectParams: ConnectParams); ``` **Request Parameterseters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace ; Necessary information for the requested connection, the Solana line has a key of 'solana' If any of the requested chains are not supported by the wallet, the wallet will reject the connection - chains: string[]; chain id information - defaultChain?: string; default chain - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information about the requested connection, Solana key is 'solana'. If the corresponding chain information is not supported by the wallet, the connection can still be made - chains: string[]; chain id information - defaultChain?: string; default chain **Return Value** - Promise `` - topic: string; The session identifier; - namespaces: `Record`; namespace information for a successful connection - chains: string[]; Chain information for the connection - accounts: string[]; accounts information for the connection - methods: string[]; Methods supported by the wallet in the current namespace - defaultChain?: string; The default chain for the current session - sessionConfig?: SessionConfig - dappInfo: object DApp information - name: string - icon:string **Example** ```typescript var session = await universalUi.openModal({ namespaces: { solana: { chains: ['solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', // solana mainnet // "sonic:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",// sonic mainnet // 'solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z', // solana testnet // 'sonic:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z',// sonic testnet ; ], } } }) ``` ## Connect to wallet and sign Connect to the wallet to get the wallet address and sign the data; the result will be called back in the event 'connect_signResponse' ``` await universalUi.openModalAndSign(connectParams: ConnectParams,signRequest: RequestParams[]); ``` **Request Parameters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace ; information necessary to request a connection, the Solana key is 'solana'. If any of the requested chains are not supported by the wallet, the wallet will reject the connection - chains: string[]; chain id information - defaultChain?: string; default chain - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information about the requested connection, Solana key is 'solana'. If the corresponding chain information is not supported by the wallet, the connection can still be made - chains: string[]; chain id information - defaultChain?: string; default chain - signRequest - RequestParams[]; the method for requesting a connection and signing the request, at most one method can be supported at a time - method: string; The name of the requested method, Solana supports methods such as: 'solana_signMessage' - chainId: string; the ID of the chain in which the method is executed, the chainId must be included in the namespaces above - params: unknown[] | Record`` | object | undefined; Parameters corresponding to the requested method **ReturnValue** - Promise `` - topic: string; The session identifier - namespaces: `Record`; namespace information for a successful connection - chains: string[]; Chain information for the connection - accounts: string[]; accounts information for the connection - methods: string[]; Methods supported by the wallet in the current namespace - defaultChain?: string; The default chain for the current session - sessionConfig?: SessionConfig - dappInfo: object DApp information - name: string - icon: string **Examples** ```typescript // Start by adding a signature result listener universalUi.on('connect_signResponse', (signResponse) => { console.log(signResponse); }); var session = await universalUi.openModalAndSign({ namespaces: { solana: { chains: ['solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', // solana mainnet // "sonic:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",// sonic mainnet // 'solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z', // solana testnet // 'sonic:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z',// sonic testnet ; ], } }, sessionConfig: { redirect: 'tg://resolve' } },[ { chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', method: 'solana_signMessage', params: { message: 'Hello Solana', } } ]) ``` ## Determine if the wallet is connected Gets whether the wallet is currently connected ** return value ** - boolean **example** ``typescript universalUi.connected(); `` ## Prepare a transaction Methods to send a message to a wallet, support signature, transaction First create an OKXSolanaProvider object, the constructor passes in OKXUniversalProviderUI, and when the OKXSolanaProvider related methods are called, the actionsConfiguration.mode configuration will be handled according to the values passed at init time ```typescript import { OKXSolanaProvider } from '@okxconnect/solana-provider'; let okxSolanaProvider = new OKXSolanaProvider(universalUi) ``` ## Signature ## ``` okxSolanaProvider.signMessage(message, chain); ``` **Request Parameters** - message - string, the message to be signed - chain: string, the chain to be executed by the request signature, it is recommended to pass this parameter; it is mandatory to pass this parameter when connecting multiple chains; connecting a chain without passing it will be handled according to solana:mainnet or sonic:mainnet **Return value** - Promise - object - publicKey:string wallet address - signature:Uint8Array The signature result ***Sign a single transaction*** ``` okxSolanaProvider.signTransaction(transaction, chain); ``` **Request Parameterseters** - transaction - Transaction | VersionedTransaction transaction data object - chain: string, the chain for which the signature execution is requested, it is recommended to pass this parameter; it is mandatory to pass this parameter when connecting multiple chains; connecting a chain without passing it will be handled according to solana:mainnet or sonic:mainnet **Return Value** - Promise - Transaction | VersionedTransaction signed transaction object ## Sign multiple transactions ``` okxSolanaProvider.signAllTransactions(transactions, chain); ``` **Request Parameterseters** - transactions - [Transaction | VersionedTransaction] array of transaction data objects - chain: string, the chain for which the signature execution is requested, it is recommended to pass this parameter; it is mandatory to pass this parameter when connecting multiple chains; connecting a chain without passing it will be handled according to solana:mainnet or sonic:mainnet **Return value** - Promise - [Transaction | VersionedTransaction] An array of signed transaction objects ## Sign a transaction and broadcast it on the chain ``` okxSolanaProvider.signAndSendTransaction(transaction, chain); ``` **Request Parameterseters** - transactions - Transaction | VersionedTransaction transaction data object - chain: string, the chain for which the signature execution is requested, it is recommended to pass this parameter; it is mandatory to pass this parameter when connecting multiple chains; connecting a chain without passing it will be handled according to solana:mainnet or sonic:mainnet **Return Value** - Promise - string transactionhash ## Get wallet account information ``` okxSolanaProvider.getAccount(chain); ``` **Request Parameters** - chain: string, get the chain id of the wallet address, if not passed then the first connected svm address will be taken by default **Return Value** - Object - address: string The address of the wallet - publicKey: PublicKey **Example** ```typescript // Sign a transfer transaction on solana mainnet. let provider = new OKXSolanaProvider(universalUi) const transaction = new Transaction({ feePayer: new PublicKey(provider.getAccount().address), recentBlockhash: 'xNWbUfdEPktMsZQHY6Zk5RJqamWFcTKasekjr7c3wFX', }).add(SystemProgram.transfer( { fromPubkey: new PublicKey(provider.getAccount().address), toPubkey: new PublicKey(provider.getAccount().address), lamports: 1000, } )) let result = await provider.signTransaction(transaction, 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp') ``` ## Disconnect wallet Disconnect the connected wallet and delete the current session, if you want to switch the connected wallet, please disconnect the current wallet first ``` Typescript universalUi.disconnect(); ``` ## Event [Same as EVM compatibility chain](https://web3.okx.com/zh-hans/web3/build/docs/sdks/app-connect-evm-ui#event%E4%BA%8B%E4%BB%B6) ## Error code [Same as EVM compatibility chain](https://web3.okx.com/zh-hans/web3/build/docs/sdks/app-connect-evm-sdk#%E9%94%99%E8%AF%AF%E7%A0%81) - [TON](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-ton.md) # TON TON chain, fully known as The Open Network, aims to provide fast and efficient transaction processing capabilities, while supporting smart contracts and decentralized applications. TON uses an innovative design called "multi-chain architecture," enabling high scalability and allowing multiple blockchains to run in parallel, thus improving the throughput and performance of the entire network.
  • If connecting via SDK, add a "Connect OKX Wallet" button within the DApp. Clicking this button will launch the mobile App Wallet and enable interaction with the OKX Wallet, such as retrieving addresses, initiating wallet signatures, and other functions.
  • In addition to SDK, we also provide a UI interface.
If you've used Ton Connect before, this document is a seamless way to reduce your development costs. If you have used OKX Connect before, you can reduce your development costs by connecting to it with this documentation - [SDK](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-ton-sdk.md) # SDK If you have used Ton Connect before, you can continue to use this document to connect, which can reduce development costs. If you have used OKX Connect before, you can jump to using ProviderSDK to connect, which can reduce development costs and support multiple network requests at the same time. # SDK Installation SDK can be installed via cdn or npm **Installation via cdn** You can add the following code to the HTML file, or replace "latest" with a specific version number, such as "1.3.7". `` Once introduced, OKXTonConnectSDK will be available as a global object that can be directly referenced. `` **Using npm** ``` npm install @okxconnect/tonsdk ``` ## Initialization Before connecting to the wallet, create an instance of the SDK: `new OKXTonConnect({metaData: {name, icon}})` **Request Parameters** - metaData - object - name - string: Application name (not unique). - icon - string: URL for the application icon (PNG, ICO formats; best as 180x180px PNG). **Return Value** - okxTonConnect - OKXTonConnect **Example** ```typescript import { OKXTonConnect } from "@okxconnect/tonsdk"; const okxTonConnect = new OKXTonConnect({ metaData: { name: "application name", icon: "application icon url" } }); ``` ## Connect to Wallet Connect to the wallet to get the wallet address as an identifier and the necessary parameters used to sign the transaction. `connect(request): Promise;` **Request Parameters** - request - object (optional) - tonProof - string (optional): signature information; - redirect - string (optional) : After processing the wallet event, the app will return the required deeplink, e.g. in Telegram environment, this field needs to pass the Telegram deeplink, when the wallet signing is done, OKX App will open the Telegram program through this deeplink, it is not recommended to set it in non-Telegram environment; - openUniversalLink - boolean (可选) : When connecting to the wallet, whether to call up the OKX App client via Universal link; if set to true, when the user initiates the connection to the wallet, the OKX App client will be pulled up and a confirmation page will pop up, and if the OKX App client is not installed on the cell phone, it will be redirected to the download page; **Return Value** - Promise - string: PC web side can generate QR code according to this field, OKX App client can scan the generated QR code in web3 and connect to DApp; **Recommendations** - Set openUniversalLink to true in your mobile browser or mobile Telegram environment; - Set openUniversalLink to false in PC browser environment, and generate QR code according to the returned universalLink, you can use OKX App client to scan the code to connect to it, and cancel the QR code pop-up window after successful connection; **Example** ```typescript import { OKXConnectError } from "@okxconnect/tonsdk"; try { okxTonConnect.connect({ tonProof: "signmessage", redirect: "tg://resolve", openUniversalLink: true }) } catch (error) { if (error instanceof OKXConnectError) { if (error.code === OKX_CONNECT_ERROR_CODES.USER_REJECTS_ERROR) { alert('User reject'); } else if (error.code === OKX_CONNECT_ERROR_CODES.ALREADY_CONNECTED_ERROR) { alert('Already connected'); } else { alert('Unknown error happened'); } } else { alert('Unknown error happened'); } } ``` ## Restore Connection If the user has previously connected their wallet, use this method to restore the connection state: `restoreConnection(): Promise` **Request Parameterseters** None **Return Value** None **Example** ```typescript okxTonConnect.restoreConnection() ``` ## Disconnect Disconnects the connected wallet and deletes the current session. If you want to switch connected wallets, disconnect the current wallet first. **Example** ```typescript import { OKX_CONNECT_ERROR_CODES } from "@okxconnect/tonsdk"; try { await okxTonConnect.disconnect() } catch (error) { if (error instanceof OKXConnectError) { switch (error.code) { case OKX_CONNECT_ERROR_CODES.NOT_CONNECTED_ERROR: alert('Not connected'); break; default: alert('Unknown error happened'); break; } } else { alert('Unknown error happened'); } } ``` ## Connected Get whether there is currently a connected wallet **Example** ```typescript var connect: boolean = okxTonConnect.connected() ``` ## Send transaction Method for sending a message to a wallet: `sendTransaction(transaction, options): Promise` **Request Parameterseters** - transaction - object - validUntil - number :unix timestamp. The transaction will be invalid after this point - from - string (optional): address of the sender to which the DApp is sending the transaction, defaults to the currently connected wallet address; - messages - object[] : (array of messages): 1-4 output messages from the wallet contract to other accounts. All messages are sent out in order, but the The wallet cannot guarantee that the messages will be delivered and executed in the same order. - address - string : the destination of the message - amount - string : The amount to be sent. - stateInit - string (optional) : The original cell BoC encoded in Base64. - payload - string (optional) : Base64 encoded raw cell BoC. - options - object - onRequestSent - () => void : This method is called when a signature request is sent; **Return value** - Promise - `{boc: string}`: signed result **Example** ```typescript import { OKXConnectError } from "@okxconnect/tonsdk"; let transactionRequest = { "validUntil": Date.now() / 1000 + 360, "from": "0:348bcf827469c5fc38541c77fdd91d4e347eac200f6f2d9fd62dc08885f0415f", "messages": [ { "address": "0:412410771DA82CBA306A55FA9E0D43C9D245E38133CB58F1457DFB8D5CD8892F", "amount": "20000000", "stateInit": "base64bocblahblahblah==" //deploy contract }, { "address": "0:E69F10CC84877ABF539F83F879291E5CA169451BA7BCE91A37A5CED3AB8080D3", "amount": "60000000", "payload": "base64bocblahblahblah==" //transfer nft to new deployed account 0:412410771DA82CBA306A55FA9E0D43C9D245E38133CB58F1457DFB8D5CD8892F } ] } let requestOptions = { onRequestSent: () => { //requestMsgSend } } try { const result = await okxTonConnect.sendTransaction(transactionRequest, requestOptions); } catch (error) { if (error instanceof OKXConnectError) { switch (error.code) { case OKX_CONNECT_ERROR_CODES.USER_REJECTS_ERROR: alert('You rejected the transaction.'); break; case OKX_CONNECT_ERROR_CODES.NOT_CONNECTED_ERROR: alert('Not connected'); break; default: alert('Unknown error happened'); break; } } else { alert('Unknown error happened'); } } ``` ## Monitor wallet state changes The wallet statuses are: successful connection, successful restoration of connection, disconnection, etc. You can use this method to get the status. `onStatusChange( callback: (walletInfo) => void, errorsHandler?: (err) => void ): () => void;` **Request Parameters** - callback - (walletInfo) => void : This callback is called when the wallet state changes; - walletinfo - object - device - object - appName - string : the name of the wallet - platform - string : the platform of the wallet, (android,ios) - appVersion - string : the version number of the wallet - maxProtocolVersion - number : the version of the wallet, (android,ios) - features - string[] : supported methods, current version is sendTransaction - account - Account - address - string : TON address raw (`0:`) - chain - "-239" - walletStateInit - string : Base64 (not url safe) encoded stateinit cell for the wallet contract - publicKey - string : HEX string without 0x - connectItems - object - name - string : "ton_proof" - proof - object - timestamp - number : timestamp - domain - object - lengthBytes - number : AppDomain Length - value - string : app domain name (as url part, without encoding) - payload - string: Base64-encoded signature - signature - string: payload from the request - errorsHandler - (err: OKXConnectError) => void : This errorsHandler is called when an exception occurs due to a change in the wallet state; - err - TonConnectError - code - number - message - string **Return Value** - () => void : Execute this method to save resources when there is no longer a need to listen for updates. **Example** ```typescript import { Wallet } from "@okxconnect/tonsdk"; const unsubscribe = okxTonConnect.onStatusChange((walletInfo: Wallet | null) => { console.log('Connection status:', walletInfo); }, (err: OKXConnectError) => { console.log('Connection status:', err); } ) ``` Call unsubscribe to save resources when you no longer need to listen for updates. ```typescript unsubscribe() ``` ## Listening to Event When the following events occur, corresponding event notifications will be sent, and the Dapp can add listeners as needed to handle the corresponding logic; **event** | event name | trigger timing | |----------------------------------------|----------------------| | OKX_TON_CONNECTION_STARTED | When the user starts to connect to the wallet | | OKX_TON_CONNECTION_COMPLETED | When the user successfully connects to the wallet | | OKX_TON_CONNECTION_ERROR | When the user canceled the connection or there was an error during the connection process | | OKX_TON_CONNECTION_RESTORING_STARTED | When the dApp starts to resume the connection | | OKX_TON_CONNECTION_RESTORING_COMPLETED | When the dApp successfully restores the connection | | | OKX_TON_CONNECTION_RESTORING_ERROR | When the dApp fails to restore the connection | | OKX_TON_DISCONNECTION | When the user starts to disconnect from the wallet | | OKX_TON_TRANSACTION_SENT_FOR_SIGNATURE | When the user sends a transaction for signature | | OKX_TON_TRANSACTION_SIGNED | When the user successfully signs a transaction | | OKX_TON_TRANSACTION_SIGNING_FAILED | When the user canceled the transaction signing or there was an error during the signing process | **Example** ```typescript import { OKX_TON_CONNECTION_AND_TRANSACTION_EVENT } from "@okxconnect/tonsdk"; window.addEventListener(OKX_TON_CONNECTION_AND_TRANSACTION_EVENT.OKX_TON_CONNECTION_STARTED, (event) => { if (event instanceof CustomEvent) { console.log('Transaction init', event.detail); } }); ``` ## Get account information Get the currently connected account **example** ```typescript import { Account } from "@okxconnect/tonsdk"; var connect: Account = okxTonConnect.account() ``` ## Get wallet information Get the currently connected wallet **Example** ```typescript import { Wallet } from "@okxconnect/tonsdk"; var connect: Wallet = okxTonConnect.wallet() ``` ## Event ```typescript // Generate universalLink okxUniversalProvider.on('display_uri', (uri) => { console.log(uri); }); // Session information changes will trigger this event; okxUniversalProvider.on('session_update', (session) => { console.log(JSON.stringify(session)); // Session information changes (e.g., adding a custom chain). }); // Disconnecting triggers this event; okxUniversalProvider.on('session_delete', ({topic}) => { console.log(topic); }); ``` ## Error codes Exceptions that may be thrown during connection, transaction, and disconnection. **Exception** | Error Code | Description | |----------------------------------------------|-------------------------| | OKX_CONNECT_ERROR_CODES.UNKNOWN_ERROR | Unknown Error | | OKX_CONNECT_ERROR_CODES.ALREADY_CONNECTED_ERROR | Wallet Already Connected | | OKX_CONNECT_ERROR_CODES.NOT_CONNECTED_ERROR | Wallet Not Connected | | OKX_CONNECT_ERROR_CODES.USER_REJECTS_ERROR | User Rejected | | OKX_CONNECT_ERROR_CODES.METHOD_NOT_SUPPORTED | Method Not Supported | | OKX_CONNECT_ERROR_CODES.CHAIN_NOT_SUPPORTED | Chain Not Supported | | OKX_CONNECT_ERROR_CODES.WALLET_NOT_SUPPORTED | Wallet Not Supported | | OKX_CONNECT_ERROR_CODES.CONNECTION_ERROR | Connection Error | ```typescript export enum OKX_CONNECT_ERROR_CODES { UNKNOWN_ERROR = 0, ALREADY_CONNECTED_ERROR = 11, NOT_CONNECTED_ERROR = 12, USER_REJECTS_ERROR = 300, METHOD_NOT_SUPPORTED = 400, CHAIN_NOT_SUPPORTED = 500, WALLET_NOT_SUPPORTED = 600, CONNECTION_ERROR = 700 } ``` - [UI](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-ton-ui.md) # UI If you have used Ton Connect before, you can continue to use this document to connect, which can reduce development costs. If you have used OKX Connect before, you can jump to using ProviderUI to connect, which can reduce development costs and support multiple network requests at the same time. ## Install via npm ``` npm install @okxconnect/ui ``` ## Initialization Before connecting to the wallet, you need to create an object for subsequent operations such as connecting to the wallet and sending transactions. `new OKXTonConnectUI(dappMetaData, buttonRootId, actionsConfiguration, uiPreferences, language, restoreConnection)` **Request Parameterseters** - metaData - object - name - string: The name of the application, will not be used as a unique representation. - icon - string: URL of the application icon, must be in PNG, ICO, etc. SVG icons are not supported. It is better to pass a url pointing to a 180x180px PNG icon. - buttonRootId - string: the HTML element ID of the button used to attach the wallet connection. if not passed, the button will not appear;. - actionsConfiguration - object - modals - ('before' |'success' |'error')[] |'all' The modals for displaying the alert screen during a transaction. - returnStrategy -string'none' | `${string}://${string}`; Specify the return strategy for deep links when the user signs/rejects the request, if in telegram, configure tg://resolve - uiPreferences -object - theme - Theme can be: THEME.DARK, THEME.LIGHT,'SYSTEM'. - language -'en_US’ |'ru_RU’ |'zh_CN’ |'ar_AE’ |'cs_CZ’ |'de_DE’ |'es_ES’ |'es_LAT’ |'fr_FR’ |'id_ID’ |'it_IT’ |'nl_NL’ |'pl_PL’ |'pt_BR’ |'pt_PT’ |'ro_RO’ |'tr_TR’ |'uk_UA’ |'vi_VN’. , defaults to en_US - restoreConnection?: boolean - Whether to automatically restore the previous connection; **Returns the value** - OKXTonConnectUI **Example** ```typescript import { OKXTonConnectUI } from "@okxconnect/ui"; const okxTonConnectUI = new OKXTonConnectUI({ dappMetaData: { name: "application name", icon: "application icon url" }, buttonRootId:'button-root', actionsConfiguration:{ returnStrategy:'none', tmaReturnUrl:'back' }, uiPreferences: { theme: THEME.LIGHT }, language:'en_US', restoreConnection: true }); ``` ## Monitor wallet state changes The wallet status are: connect successfully, resume connect successfully, disconnect, etc. You can use this method to get the status. [Method details same as OKXTonConnect.onStatusChange](https://web3.okx.com/web3/build/docs/sdks/app-connect-ton-sdk#monitor-wallet-state-changes) **Example** ```typescript import { Wallet } from "@okxconnect/tonsdk"; const unsubscribe = okxTonConnectUI.onStatusChange((walletInfo: Wallet | null) => { console.log('Connection status:', walletInfo); }, (err: OKXConnectError) => { console.log('Connection status:', err); } ) ``` Call unsubscribe to save resources when you no longer need to listen for updates. ```typescript unsubscribe() ``` ## Connect to Wallet Connecting to a wallet goes to get the wallet address, which serves as the identifier and the necessary parameters used to sign the transaction. The “Connect Button” (added to buttonRootId) automatically handles the click and invokes the connection. If no buttonRootId is added, this method needs to be called. `await okxTonConnectUI.openModal();` **Example** ```typescript okxTonConnectUI.openModal(); ``` ## Set the tonProof Add the connection signature parameter, the If you need to set tonProof, set state:'loading', before the tonProof parameter is ready. When ready, set state to'ready' and add value;. You can also remove the loading state by setting setConnectRequestParameters(null); **Example** ```typescript okxtonConnectUI.setConnectRequestParameters({ state:'loading' }); const tonProofPayload: string | null = await fetchTonProofPayloadFromBackend(); if (!tonProofPayload) { okxtonConnectUI.setConnectRequestParameters(null); } else { okxtonConnectUI.setConnectRequestParameters({ state: "ready", value: { tonProof: tonProofPayload } }); } ``` ## Close connection popup **Example** ```typescript okxTonConnectUI.closeModal(); ``` ## Get the currently connected Wallet and WalletInfo Get information about whether there is a currently connected wallet, and the connected wallet; **Example** ```typescript const currentWallet = okxTonConnectUI.wallet; const currentAccount = okxTonConnectUI.account; const isConnected = okxTonConnectUI.connected; ``` ## Disconnect **Example** ```typescript okxTonConnectUI.disconnect(); ``` ## Send transaction Method for sending a message to a wallet: `sendTransaction(transaction, actionConfigurationRequest): Promise` **Request Parameterseters** - transaction - object, [parameters same as OKXTonConnect.sendTransaction's transaction](/web3/build/docs/sdks/app-connect-ton-sdk#%E5%8F%91%E9%80%81% E4%BA%A4%E6%98%93) - actionConfigurationRequest - object - modals : ('before' |'success' |'error')[] |'all' Mode of displaying the alert screen during the transaction, defaults to'before' - returnStrategy -string'none’ | `${string}://${string}`; The return strategy for the deep link in the App wallet when the user signs or rejects the request, if it is a Mini App in Telegram, it can be configured with tg://resolve, and if it's not configured here, the will take the returnStrategy passed by the init method, default is'none’ **Return Value** - Promise - `{boc: string}`: Signature Result ```typescript import { OKXConnectError, OKX_CONNECT_ERROR_CODES } from "@okxconnect/core"; let transactionRequest = { "validUntil": Date.now() / 1000 + 360, "from": "0:348bcf827469c5fc38541c77fdd91d4e347eac200f6f2d9fd62dc08885f0415f", "messages": [ { "address": "0:412410771DA82CBA306A55FA9E0D43C9D245E38133CB58F1457DFB8D5CD8892F", "amount": "20000000", "stateInit": "base64bocblahblahblah==" //deploy contract }, { "address": "0:E69F10CC84877ABF539F83F879291E5CA169451BA7BCE91A37A5CED3AB8080D3", "amount": "60000000", "payload": "base64bocblahblahblah==" //transfer nft to new deployed account 0:412410771DA82CBA306A55FA9E0D43C9D245E38133CB58F1457DFB8D5CD8892F } ] } okxTonConnectUI.sendTransaction(transactionRequest, { modals:'all', tmaReturnUrl:'back' }).then((result) => { let boc = result.boc }).catch((error) => { if (error instanceof OKXConnectError && error.code == OKX_CONNECT_ERROR_CODES.USER_REJECTS_ERROR) { //userReject; } else { //other error; } }) ``` ## Set ui configuration items Support to modify theme, text language setting, also can add these configurations during initialisation; **Example** ```typescript okxTonConnectUI.uiOptions = { language:'zh_CN', uiPreferences: { theme: THEME.DARK } }; ``` ## Listening to Events When the following events occur, a notification of the corresponding event will be sent, and the Dapp can add listeners as needed to handle the corresponding logic; **event** | Event Name | Trigger Timing | |---------------------------------------|----------------------| | OKX_UI_CONNECTION_STARTED | When the user starts to connect to the wallet | | OKX_UI_CONNECTION_COMPLETED | When the user successfully connects to the wallet | | OKX_UI_CONNECTION_ERROR | When the user canceled the connection or there was an error during the connection process | | OKX_UI_CONNECTION_RESTORING_STARTED | When the dApp starts restoring the connectio | | OKX_UI_CONNECTION_RESTORING_COMPLETED | When the dApp successfully restores the connection | | OKX_UI_CONNECTION_RESTORING_ERROR | When the dApp failed to restore the connection | | OKX_UI_DISCONNECTION | When the user starts to disconnect from the wallet | | OKX_UI_TRANSACTION_SENT_FOR_SIGNATURE | When the user sends a transaction for signature | | OKX_UI_TRANSACTION_SIGNED | When the user successfully signs a transaction | | OKX_UI_TRANSACTION_SIGNING_FAILED | When the user canceled the transaction signing or there was an error during the signing process | **Example** ```typescript import { OKX_UI_CONNECTION_AND_TRANSACTION_EVENT } from "@okxconnect/ui"; window.addEventListener(OKX_UI_CONNECTION_AND_TRANSACTION_EVENT.OKX_UI_CONNECTION_STARTED, (event) => { if (event instanceof CustomEvent) { console.log('Transaction init', event.detail); } }); ``` ## Event ```typescript // Generate universalLink universalUi.on("display_uri", (uri) => { console.log(uri); }); // Session information changes will trigger this event; universalUi.on("session_update", (session) => { console.log(JSON.stringify(session)); }); // Disconnecting triggers this event; universalUi.on("session_delete", ({topic}) => { console.log(topic); }); // This event is triggered when a connection is made and the signature is signed. universalUi.on("connect_signResponse", (signResponse) => { console.log(signResponse); }); ``` ## Error codes Exceptions that may be thrown during connection, transaction, and disconnection. **Exception** | Error Code | Description | |----------------------------------------------|-------------------------| | OKX_CONNECT_ERROR_CODES.UNKNOWN_ERROR | Unknown Error | | OKX_CONNECT_ERROR_CODES.ALREADY_CONNECTED_ERROR | Wallet Already Connected | | OKX_CONNECT_ERROR_CODES.NOT_CONNECTED_ERROR | Wallet Not Connected | | OKX_CONNECT_ERROR_CODES.USER_REJECTS_ERROR | User Rejected | | OKX_CONNECT_ERROR_CODES.METHOD_NOT_SUPPORTED | Method Not Supported | | OKX_CONNECT_ERROR_CODES.CHAIN_NOT_SUPPORTED | Chain Not Supported | | OKX_CONNECT_ERROR_CODES.WALLET_NOT_SUPPORTED | Wallet Not Supported | | OKX_CONNECT_ERROR_CODES.CONNECTION_ERROR | Connection Error | ```typescript export enum OKX_CONNECT_ERROR_CODES { UNKNOWN_ERROR = 0, ALREADY_CONNECTED_ERROR = 11, NOT_CONNECTED_ERROR = 12, USER_REJECTS_ERROR = 300, METHOD_NOT_SUPPORTED = 400, CHAIN_NOT_SUPPORTED = 500, WALLET_NOT_SUPPORTED = 600, CONNECTION_ERROR = 700 } ``` - [SUI](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-sui.md) # SUI Sui (or Sui Network) is the first Layer 1 blockchain designed from the ground up to enable creators and developers to build experiences that cater for the next billion users in Web3. Sui is horizontally scalable to support a wide range of DApp development with fast speeds and low costs. The platform brings users a general-purpose blockchain with high throughput, instant settlement speeds, rich on-chain assets, and user-friendly Web3 experiences. Sui is a step-function advancement in blockchain, designed from the bottom up to meet the needs of everyone involved in crypto.
  • If connecting via SDK, add a "Connect OKX Wallet" button within the DApp. Clicking this button will launch the mobile App Wallet and enable interaction with the OKX Wallet, such as retrieving addresses, initiating wallet signatures, and other functions.
  • In addition to SDK, we also provide a UI interface.
- [SDK](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-sui-sdk.md) # SDK ## Installation and Initialization Make sure to update the OKX App to version 6.90.1 or later to start integrating OKX Connect into your DApp can be done using npm: ``` npm install @okxconnect/sui-provider ``` Before connecting the wallet, you need to create an object for subsequent wallet connections, transaction submissions, and other operations. `OKXUniversalProvider.init({dappMetaData: {name, icon}})` **Request Parameterseters** - dappMetaData - object - name - string: the name of the app, will not be used as a unique representation - icon - string: URL of the application icon, must be in PNG, ICO, etc. SVG icons are not supported. SVG icons are not supported. It is better to pass a url pointing to a 180x180px PNG icon. **Returns a value**. - OKXUniversalProvider **Example** ```typescript import { OKXUniversalProvider } from "@okxconnect/universal-provider" const okxUniversalProvider = OKXUniversalProvider.init({dappMetaData: { name: "application name", icon: "application icon url" }}) ``` ## Connecting to Wallet Connecting to a wallet goes to get the wallet address as an identifier and the necessary parameters used to sign the transaction. `okxUniversalProvider.connect(connectParams: ConnectParams);` **Request Parameterseters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace ; Necessary information for the requested connection, the key for the Sui line is 'sui' If any of the requested chains are not supported by the wallet, the wallet will reject the connection; - chains: string[]; chain id information, the chain's key is 'sui', the wallet will reject the connection if any of the requested chains is not supported. - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information for requesting connection, the key for EVM is 'eip155', the key for Sui is 'sui'. If the corresponding chain information is not supported by the wallet, the connection can still be made; - chains: string[]; chain id information, if the corresponding chain is not supported by the wallet. - sessionConfig: object - redirect: string Jump parameter after successful connection, if it is a Mini App in Telegram, here can be set to Telegram's deeplink: 'tg://resolve'. **Return value** - Promise `` - topic: string; The session identifier; - namespaces: `Record`; namespace information for a successful connection; - chains: string[]; Chain information for the connection; - accounts: string[]; accounts information for the connection; - methods: string[]; methods supported by the wallet under the current namespace; - defaultChain?: string; default chain for the current session - sessionConfig?: SessionConfig - dappInfo: object DApp information; - name:string - icon:string - redirect?: string, the redirect parameter after successful connection; **Example** ```typescript var session = await okxUniversalProvider.connect({ namespaces: { sui: { chains: ["sui:mainnet"] } }, sessionConfig: { redirect: "tg://resolve" } }) ``` ## Determine if the wallet is connected Gets whether the wallet is currently connected. **Return Value** - boolean **Example** ```typescript okxUniversalProvider.connected(); ``` ## Disconnect wallet Disconnect from a connected wallet and delete the current session. If you want to switch wallets, disconnect from the current wallet first. **Example** ```typescript okxUniversalProvider.disconnect(); ``` ## Prepare the transaction Methods to send messages to the wallet, support signature, transaction. First create an OKXSuiProvider object, pass OKXUniversalProvider into the constructor. ```typescript import { OKXSuiProvider } from '@okxconnect/sui-provider' let suiProvider = new OKXSuiProvider(okxUniversalProvider) ``` ## Get the account ``suiProvider.getAccount();`` ***Return Value*** - Object - address: string wallet address - publicKey: string public key (requires App 6.92.0 or later support) ***Example*** ```typescript let result = suiProvider.getAccount() // Return structure { 'address": “0x7995ca23961fe06d8cea7da58ca751567ce820d7cba77b4a373249034eecca4a”, 'publicKey": “tUvCYrG22rHKR0c306MxgnhXOSf16Ot6H3GMO7btwDI=”, } ``` ## SignMessage ```typescript suiProvider.signMessage(input: SuiSignMessageInput); ``` ***Request Parameters*** - SuiSignMessageInput - object - message: Uint8Array ***Return Value*** - Promise - object - messageBytes: string - signature: string ## SignPersonalMessage ```typescript suiProvider.signPersonalMessage(input: SuiSignMessageInput); ``` ***Request Parameters*** - SuiSignMessageInput - object - message: Uint8Array ***Return Value*** - Promise - object - bytes: string - signature: string **Example** ```typescript const data = [76, 111, 103, 105, 110, 32, 119, 105, 116, 104, 32, 66, 108, 117, 101, 109, 111, 118, 101]; const uint8Array = new Uint8Array(data); let input = { message: uint8Array } let signResult1 = await suiProvider.signMessage(input) let signResult2 = await suiProvider.signPersonalMessage(input) ``` ## Sign Transaction ```typescript suiProvider.signTransaction(input); ``` ***Request Parameters*** ```typescript // txBytes and txSerialize are the serialization of the transactionBlock. // and transactionBlock can be passed in one way or the other, but not both. interface SuiSignTransactionBlockInput { transactionBlock: TransactionBlock; chain: IdentifierString; txBytes: string?; txSerialize: string? } ``` ***Return Value*** - Promise - object - signature: string, - transactionBlockBytes: string ## Signs a transaction and broadcasts onchain ```typescript suiProvider.signAndExecuteTransaction(input); ``` ***Request Parameters*** ```typescript // txBytes and txSerialize are the serialization of the transactionBlock. // and transactionBlock can be passed in one way or the other, but not both. interface SuiSignTransactionBlockInput { transactionBlock: TransactionBlock; chain: IdentifierString; txBytes: string?; txSerialize: string?; } ``` ***Return Value*** - Promise - object - confirmedLocalExecution: bool, - digest: string, - txBytes: string **Example** ```typescript // Define the amount to be transferred and the destination address const amount = 109; // Amount to be transferred const recipientAddress = '0x'; // destination address /// Construct a transfer transaction const tx = new Transaction(); const [coin] = tx.splitCoins(tx.gas, [amount]); tx.transferObjects([coin], recipientAddress) const input = { transactionBlock: tx, chain: 'sui:mainnet', options: { showEffects: true, } } let signResult1 = await suiProvider.signTransaction(input) let signResult2 = await suiProvider.signAndExecuteTransaction(input) ``` ## Event ```typescript // Generate universalLink okxUniversalProvider.on('display_uri', (uri) => { console.log(uri); }); // Session information changes will trigger this event; okxUniversalProvider.on('session_update', (session) => { console.log(JSON.stringify(session)); // Session information changes (e.g., adding a custom chain). }); // Disconnecting triggers this event; okxUniversalProvider.on('session_delete', ({topic}) => { console.log(topic); }); ``` ## Error codes Exceptions that may be thrown during connection, transaction, and disconnection. **Exception** | Error Code | Description | |----------------------------------------------|-------------------------| | OKX_CONNECT_ERROR_CODES.UNKNOWN_ERROR | Unknown Error | | OKX_CONNECT_ERROR_CODES.ALREADY_CONNECTED_ERROR | Wallet Already Connected | | OKX_CONNECT_ERROR_CODES.NOT_CONNECTED_ERROR | Wallet Not Connected | | OKX_CONNECT_ERROR_CODES.USER_REJECTS_ERROR | User Rejected | | OKX_CONNECT_ERROR_CODES.METHOD_NOT_SUPPORTED | Method Not Supported | | OKX_CONNECT_ERROR_CODES.CHAIN_NOT_SUPPORTED | Chain Not Supported | | OKX_CONNECT_ERROR_CODES.WALLET_NOT_SUPPORTED | Wallet Not Supported | | OKX_CONNECT_ERROR_CODES.CONNECTION_ERROR | Connection Error | ```typescript export enum OKX_CONNECT_ERROR_CODES { UNKNOWN_ERROR = 0, ALREADY_CONNECTED_ERROR = 11, NOT_CONNECTED_ERROR = 12, USER_REJECTS_ERROR = 300, METHOD_NOT_SUPPORTED = 400, CHAIN_NOT_SUPPORTED = 500, WALLET_NOT_SUPPORTED = 600, CONNECTION_ERROR = 700 } ``` - [UI](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-sui-ui.md) # UI ## Installation and Initialisation: Make sure to update the OKX App to version 6.90.1 or later to start accessing: To integrate OKX Connect into your DApp, you can use npm: ``` npm install @okxconnect/ui npm install @okxconnect/sui-provider ``` Before connecting to a wallet, you need to create an object that can provide a UI interface for subsequent operations such as connecting to the wallet and sending transactions. ```OKXUniversalConnectUI.init(dappMetaData, actionsConfiguration, uiPreferences, language)``` **Request Parameterseters** - dappMetaData - object - name - string: the name of the application, will not be used as a unique representation - icon - string: URL of the application icon, must be in PNG, ICO, etc. SVG icons are not supported. SVG icons are not supported. It is best to pass a url pointing to a 180x180px PNG icon. - actionsConfiguration - object - modals - ('before' | 'success' | 'error')[] | 'all' The modes of displaying alerts during transaction, defaults to 'before'. - returnStrategy -string 'none' | `${string}://${string}`; for app wallet, specify the return strategy of the deep link when the user signs/rejects the request, in case of telegram, you can configure tg://resolve - uiPreferences -object - theme - Theme can be: THEME.DARK, THEME.LIGHT, 'SYSTEM'. - language - 'en_US' | 'ru_RU' | 'zh_CN' | 'ar_AE' | 'cs_CZ' | 'de_DE' | 'es_ES' | 'es_LAT' | 'fr_FR' | 'id_ID' | 'it_IT' | 'nl_NL' | 'pl_PL' | 'pt_BR' | 'pt_PT' | 'ro_RO' | 'tr_TR' | 'uk_UA' | 'vi_VN'. , defaults to en_US **Return value** - OKXUniversalConnectUI **Examples** ```typescript import { OKXUniversalConnectUI } from '@okxconnect/ui'; const okxUniversalConnectUI = await OKXUniversalConnectUI.init({ dappMetaData: { icon: 'https://static.okx.com/cdn/assets/imgs/247/58E63FEA47A2B7D7.png', name: 'OKX Connect Demo' }, actionsConfiguration: { returnStrategy: 'tg://resolve', modals: 'all', { modals: 'all', tmaReturnUrl:'back' }, language: 'en_US', uiPreferences: { theme: THEME.LIGHT }, } }) // Switching the plugin to connect to the wallet fires this event; okxUniversalConnectUI.on('accountChanged', (session) => { if (session){ console.log(`accountChanged `, JSON.stringify(session)); } }); ``` ## Connect to the wallet Connects to the wallet to get the wallet address as an identifier and the necessary parameters for signing the transaction. ``okxUniversalConnectUI.openModal(connectParams: ConnectParams);`` **Request Parameterseters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace ; Necessary information for the requested connection, the key for the Sui line is 'sui'. If any of the requested chains are not supported by the wallet, the wallet will reject the connection; - chains: string[]; information about the chain ids, the name of the chain, the name of the wallet, and the name of the wallet. - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information of the requested connection, the key of EVM system is 'eip155', the key of Sui system is 'sui'. If the corresponding chain information is not supported by the wallet, the connection can still be made; - chains: string[]; chain id information, if the corresponding chain is not supported by the wallet. - sessionConfig: object - redirect: string Jump parameter after successful connection, if it is a Mini App in Telegram, here you can set it to Telegram's deeplink: 'tg://resolve' **Return Value** - Promise `` - topic: string; The session identifier; - namespaces: `Record`; namespace information for a successful connection; - chains: string[]; Chain information for the connection; - accounts: string[]; accounts information for the connection; - methods: string[]; Methods supported by the wallet in the current namespace; - defaultChain?: string; The default chain for the current session. - sessionConfig?: SessionConfig - dappInfo: object DApp information; - name: string - icon:string **Example** ```typescript var session = await okxUniversalConnectUI.openModal({ namespaces: { sui: { chains: ['sui:mainnet'] } } }) ``` ## Connect to wallet and sign Connect to the wallet to get the wallet address and sign the data; the result will be called back in the event 'connect_signResponse'; ``` await universalUi.openModalAndSign(connectParams: ConnectParams,signRequest: RequestParams[]); ``` **Request Parameters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace ; information necessary to request a connection, the key for Sui is 'sui' If any of the requested chains are not supported by the wallet, the wallet will reject the connection; - chains: string[]; information about the chain ids, the name of the chain, the name of the wallet, and the name of the wallet. - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information of the requested connection, the key of Sui is 'sui' If the corresponding chain information is not supported by the wallet, the connection can still be made; - chains: string[]; Chain id information, if the corresponding chain is not supported by the wallet, it can still be connected. - sessionConfig: object - redirect: string Jump parameter after successful connection, if it is a Mini App in Telegram, here you can set it to Telegram's deeplink: 'tg://resolve'. - signRequest - RequestParams[]; the method to request the connection and sign the request, at most one method can be supported at the same time; - method: string; the name of the requested method, Sui supports methods such as 'sui_signMessage' and 'sui_signPersonalMessage'; - chainId: string; the ID of the chain where the method is executed, the chainId must be included in the namespaces above; - params: unknown[] | Record`` | object | undefined; Parameters corresponding to the requested method; **ReturnValue** - Promise``; the parameters corresponding to the requested method. - topic: string; The session identifier; - namespaces: `Record`; namespace information for a successful connection; - chains: string[]; Chain information for the connection; - accounts: string[]; accounts information for the connection; - methods: string[]; Methods supported by the wallet in the current namespace; - defaultChain?: string; The default chain for the current session. - sessionConfig?: SessionConfig - dappInfo: object DApp information; - name: string - icon:string **Example** ```typescript // Add the signature result listener first okxUniversalConnectUI.on('connect_signResponse', (signResponse) => { console.log(signResponse); }); let suiData = [ 76, 111, 103, 105, 110, 32, 119, 105, 116, 104, 32, 66, 108, 117, 101. 109, 111, 118, 101, ]; let uint8Array = new Uint8Array(suiData); var session = await okxUniversalConnectUI.openModalAndSign({ namespaces: { sui: { chains: ['sui:mainnet'] } }, sessionConfig: { redirect: 'tg://resolve' } }, [ { chainId: 'sui:mainnet', method: 'sui_signMessage', params: { message: uint8Array, } } ] ) ``` ## Determine if the wallet is connected Gets whether the wallet is currently connected or not; ** Return Value** - boolean **example** ```typescript okxUniversalConnectUI.connected(); ``` ## Disconnect Disconnect the connected wallet and delete the current session, if you want to switch the connected wallet, please disconnect the current wallet first. **Example** ```typescript okxUniversalConnectUI.disconnect(); ``` ## Prepare a transaction Methods to send messages to the wallet, support signature, transaction; when the wallet confirmation method is needed, it will pop up a prompt page; First create an OKXSuiProvider object, pass okxUniversalConnectUI into the constructor. ```typescript import { OKXSuiProvider } from '@okxconnect/sui-provider' let suiProvider = new OKXSuiProvider(okxUniversalConnectUI) ``` ## Get account information `suiProvider.getAccount();` ***Returns the value***. - Object - address: string wallet address - publicKey: string public key (requires App 6.92.0 or later) ***Example*** ```typescript let result = suiProvider.getAccount() // Return structure { "address": “0x7995ca23961fe06d8cea7da58ca751567ce820d7cba77b4a373249034eecca4a”, "publicKey": “tUvCYrG22rHKR0c306MxgnhXOSf16Ot6H3GMO7btwDI=”, } ``` ## Signature Message ```typescript suiProvider.signMessage(input: SuiSignMessageInput); ``` ***Request Parameterseters*** - SuiSignMessageInput - object - message: Uint8Array ***Return value*** - Promise - object - messageBytes: string - signature: string ## Signature PersonalMessage ```typescript suiProvider.signPersonalMessage(input: SuiSignMessageInput); ``` ***Request Parameterseters*** - SuiSignMessageInput - object - message: Uint8Array ***Return value*** - Promise - object - bytes: string - signature: string **Example** ```typescript const data = [76, 111, 103, 105, 110, 32, 119, 105, 116, 104, 32, 66, 108, 117, 101, 109, 111, 118, 101]; const uint8Array = new Uint8Array(data); let input = { message: uint8Array } let signResult1 = await suiProvider.signMessage(input) let signResult2 = await suiProvider.signPersonalMessage(input) ``` ## Sign the deal ## ```typescript suiProvider.signTransaction(input); ``` *** request parameters *** ```typescript // txBytes and txSerialize for serialisation of transactionBlock // and transactionBlock can be passed in one way without passing in both. interface SuiSignTransactionBlockInput { transactionBlock: TransactionBlock; chain: IdentifierString; } chain: IdentifierString; txBytes: string? txSerialize: string? } ``` ***Return Value*** - Promise - object - signature: string, - transactionBlockBytes: string ## Sign the transaction and broadcast it up the chain ```typescript suiProvider.signAndExecuteTransaction(input); ``` ***Request Parameters ```typescript // txBytes with txSerialize for transactionBlock serialisation // and transactionBlock can be passed in one way without passing in both. interface SuiSignTransactionBlockInput { transactionBlock: TransactionBlock; chain: IdentifierString; txBytes: string?; txSerialize: string?; } ``` ***Return Value*** - Promise - object - confirmedLocalExecution: bool, - digest: string, - txBytes: string **Example** ```typescript // Define the amount to be transferred and the destination address. const amount = 109; // Amount to be transferred const recipientAddress = '0x'; // destination address /// Construct a transaction to transfer const tx = new Transaction(); const [coin] = tx.splitCoins(tx.gas, [amount]); tx.transferObjects([coin], recipientAddress) const input = { transactionBlock: tx, chain: 'sui:mainnet', options: { showEffects: true, } } let signResult1 = await suiProvider.signTransaction(input) let signResult2 = await suiProvider.signAndExecuteTransaction(input) ``` ## Event event [Same details as EVM compatibility chain](https://web3.okx.com/zh-hans/web3/build/docs/sdks/app-connect-evm-ui#event%E4%BA%8B%E4%BB%B6) ## Error code [Same details as EVM compatibility chain](https://web3.okx.com/zh-hans/web3/build/docs/sdks/app-connect-evm-sdk#%E9%94%99%E8%AF%AF%E7%A0%81) - [Aptos/Movement](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-aptos.md) # Aptos/Movement Aptos is a layer 1 public blockchain project that aims to develop a safe, scalable, and upgradeable Web3 infrastructure. Developed by former engineers from the Facebook crypto project Diem (formerly Libra), Aptos contracts are written using Move. Common Aptos-compatible networks include Movement.
  • If connecting via SDK, add a "Connect OKX Wallet" button within the DApp. Clicking this button will launch the mobile App Wallet and enable interaction with the OKX Wallet, such as retrieving addresses, initiating wallet signatures, and other functions.
  • In addition to SDK, we also provide a UI interface.
- [SDK](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-aptos-sdk.md) # SDK ## Installation and Initialization Make sure to update to version 6.92.0 or later to get started with access: integrating OKX Connect into your DApp can be done using npm: ``` npm install @okxconnect/aptos-provider ``` Before connecting to a wallet, you need to create an object that will be used to connect to the wallet, send transactions and so on. ``` OKXUniversalProvider.init({dappMetaData: {name, icon}}) ``` **Request Parameterseters** - dappMetaData - object - name - string: the name of the app, will not be used as a unique representation - icon - string: URL of the application icon, must be in PNG, ICO, etc. SVG icons are not supported. SVG icons are not supported. It is better to pass a url pointing to a 180x180px PNG icon. **Return Value** - OKXUniversalProvider **Examples** ```typescript import { OKXUniversalProvider } from "@okxconnect/universal-provider"; const okxUniversalProvider = await OKXUniversalProvider.init({ dappMetaData: { name: "application name", icon: "application icon url" }, }) ``` ## Connecting to a wallet Connect to the wallet to get the wallet address as an identifier and the necessary parameters for signing the transaction; ``` okxUniversalProvider.connect(connectParams: ConnectParams); ``` **Request Parameterseters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace ; information necessary to request a connection, the key is 'eip155' for EVM and 'aptos' for Aptos. If any of the requested chains are not supported by the wallet, the wallet will reject the connection - chains: string[]; chain id information - defaultChain?: string; default chain - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information for requesting a connection, the key is 'eip155' for EVM and 'aptos' for Aptos. If the corresponding chain information is not supported by the wallet, the connection can still be made; - chains: string[]; Chain id information, if the corresponding chain information is not supported by the wallet, it can still be connected. - defaultChain?: string; default chain - sessionConfig: object - redirect: string Jump parameter after successful connection, if it is Mini App in Telegram, here can be set to Telegram's deeplink: 'tg://resolve' **Return value** - Promise `` - topic: string; the session identifier; - namespaces: `Record`; namespace information for a successful connection; - chains: string[]; Chain information for the connection - accounts: string[]; accounts information for the connection - methods: string[]; methods supported by the wallet under the current namespace - defaultChain?: string; The default chain for the current session - sessionConfig?: SessionConfig - dappInfo: object DApp information - name:string - icon:string - redirect?: string, the redirect parameter after successful connection **Example** ```typescript var session = await okxUniversalProvider.connect({ namespaces: { aptos: { chains: ["aptos:mainnet", // aptos mainnet // "movement:mainnet",// movement mainnet // "movement:testnet",// movement testnet ], } }, sessionConfig: { redirect: "tg://resolve" } }) ``` ## Determine if the wallet is connected Get whether the wallet is currently connected **Return Value** - boolean **Example** ```typescript okxUniversalProvider.connected(); ``` ## Prepare the transaction First create an OKXAptosProvider object, with the constructor passing in OKXUniversalProvider ```typescript import { OKXAptosProvider } from '@okxconnect/aptos-provider'; let okxAptosProvider = new OKXAptosProvider(okxUniversalProvider) ``` ***Get the wallet address and publicKey*** ``` okxAptosProvider.getAccount(chain); ``` **Request Parameters** - chain: string, get the chain id of the wallet address, if not passed then the first connected aptos system address will be taken by default. **Return Value** - Object - address: string The address of the wallet. - publicKey: string Public Key ## Signature ``` okxAptosProvider.signMessage(message, chain) ``` **Request Parameterseters** - message - object - address?: boolean; // Should we include the address of the account in the message? - application?: boolean; // Should we include the domain of the DApp - chainId?: boolean; // Should we include the current chain id the wallet is connected to? - message: string; // The message to be signed and displayed to the user - nonce: string; // A nonce the DApp should generate - chain: string, the chain to be signed, recommended; mandatory when connecting multiple chains; **Return value** - Promise - object - address: string; - application: string; - chainId: number; - fullMessage: string; // The message that was generated to sign - message: string; // The message passed in by the user - nonce: string; - prefix: string; // Should always be APTOS - signature: string; // The signed full message ## sign single transaction ``` okxAptosProvider.signTransaction(transaction, chain) ``` **Request Parameters** - transaction - object | SimpleTransaction transaction data object - chain: string, the chain for which the signature execution is requested, this parameter is recommended; mandatory when connecting multiple chains; **Return Value** - Promise - Buffer signed result. ## Sign transaction and broadcast on chain ``` okxAptosProvider.signAndSubmitTransaction(transaction, chain) ``` **Request Parameters** - transaction - object | SimpleTransaction transaction data object - chain: string, the chain for which the signature execution is requested, this parameter is recommended; mandatory when connecting multiple chains; **Return Value** - Promise - string transaction hash. **Example** ```typescript // Signature message let data = { address:true, application:true, chainId:true, message:"Hello OKX", nonce:"1234" } let provider = new OKXAptosProvider(okxUniversalConnectUI) let message = await provider.signMessage(data, "aptos:mainnet") //return value {'address': '0x2acddad65c27c6e5b568b398f0d1d01ebb8b55466461bbd51c1e42763a92fdfe', 'application': 'http://192.168.101.13',"' chainId": “aptos:mainnet”, “fullMessage”: 'APTOS\naddress: 0x2acddad65c27c6e5b568b398f0d1d01ebb8b55466461bbd51c1e42763a92fdfe\ napplication: http://192.168.101.13\nchainId: aptos:mainnet\nmessage: 123 Signature Test! \nnonce: 1234', “message”: '123 Signature test!' , 'nonce': '1234', 'prefix': 'APTOS', 'signature':' 0xef4e587f537b80a2f4e424079984b80e130c92d939a92225764be00ed36486521e8857b8a222de4023c5f4d2e9fd2f62c26ca8a43694660583c8a5d4328da303 ', 'verified':true} // Sign the transaction and upload it const config = new AptosConfig({ network: Network.MAINNET }); const aptos = new Aptos(config); // Support for transactions created via @aptos-labs/ts-sdk const transaction = await aptos.transaction.build.simple({ sender: "0x07897a0496703c27954fa3cc8310f134dd1f7621edf5e88b5bf436e4af70cfc6", data: { function: "0x80273859084bc47f92a6c2d3e9257ebb2349668a1b0fb3db1d759a04c7628855::router::swap_exact_coin_for_coin_x1", typeArguments: ["0x1::aptos_coin::AptosCoin", "0x111ae3e5bc816a5e63c2da97d0aa3886519e0cd5e4b046659fa35796bd11542a::stapt_token::StakedApt", "0x0163df34fccbf003ce219d3f1d9e70d140b60622cb9dd47599c25fb2f797ba6e::curves::Uncorrelated", "0x80273859084bc47f92a6c2d3e9257ebb2349668a1b0fb3db1d759a04c7628855::router::BinStepV0V05"], functionArguments: ["10000", ["9104"], ["5"], ["true"]], }, }); let result1 = await provider.signAndSubmitTransaction(transaction, "aptos:mainnet") //Support transactions in the following data formats at the same time let transactionData = { "arguments": ["100000",["0","0","10533"],["10","5","5"],["false","false","true"]], "function": "0x80273859084bc47f92a6c2d3e9257ebb2349668a1b0fb3db1d759a04c7628855::router::swap_exact_coin_for_coin_x3", "type": "entry_function_payload", "type_arguments": ["0x1::aptos_coin::AptosCoin","0x73eb84966be67e4697fc5ae75173ca6c35089e802650f75422ab49a8729704ec::coin::DooDoo","0x53a30a6e5936c0a4c5140daed34de39d17ca7fcae08f947c02e979cef98a3719::coin::LSD","0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDC","0x80273859084bc47f92a6c2d3e9257ebb2349668a1b0fb3db1d759a04c7628855::router::CurveV1","0x0163df34fccbf003ce219d3f1d9e70d140b60622cb9dd47599c25fb2f797ba6e::curves::Uncorrelated","0x0163df34fccbf003ce219d3f1d9e70d140b60622cb9dd47599c25fb2f797ba6e::curves::Uncorrelated","0x54cb0bb2c18564b86e34539b9f89cfe1186e39d89fce54e1cd007b8e61673a85::bin_steps::X80","0x80273859084bc47f92a6c2d3e9257ebb2349668a1b0fb3db1d759a04c7628855::router::BinStepV0V05","0x80273859084bc47f92a6c2d3e9257ebb2349668a1b0fb3db1d759a04c7628855::router::BinStepV0V05"] } let result2 = await provider.signAndSubmitTransaction(transactionData, "movement:testnet") ``` ## Disconnect wallet Disconnect the connected wallet and delete the current session. If you want to switch the connected wallet, please disconnect the current wallet first. ```typescript okxUniversalProvider.disconnect(); ``` ## Event ```typescript // Generate universalLink okxUniversalProvider.on('display_uri', (uri) => { console.log(uri); }); // Session information changes will trigger this event; okxUniversalProvider.on('session_update', (session) => { console.log(JSON.stringify(session)); // Session information changes (e.g., adding a custom chain). }); // Disconnecting triggers this event; okxUniversalProvider.on('session_delete', ({topic}) => { console.log(topic); }); ``` ## Error codes Exceptions that may be thrown during connection, transaction, and disconnection. **Exception** | Error Code | Description | |----------------------------------------------|-------------------------| | OKX_CONNECT_ERROR_CODES.UNKNOWN_ERROR | Unknown Error | | OKX_CONNECT_ERROR_CODES.ALREADY_CONNECTED_ERROR | Wallet Already Connected | | OKX_CONNECT_ERROR_CODES.NOT_CONNECTED_ERROR | Wallet Not Connected | | OKX_CONNECT_ERROR_CODES.USER_REJECTS_ERROR | User Rejected | | OKX_CONNECT_ERROR_CODES.METHOD_NOT_SUPPORTED | Method Not Supported | | OKX_CONNECT_ERROR_CODES.CHAIN_NOT_SUPPORTED | Chain Not Supported | | OKX_CONNECT_ERROR_CODES.WALLET_NOT_SUPPORTED | Wallet Not Supported | | OKX_CONNECT_ERROR_CODES.CONNECTION_ERROR | Connection Error | ```typescript export enum OKX_CONNECT_ERROR_CODES { UNKNOWN_ERROR = 0, ALREADY_CONNECTED_ERROR = 11, NOT_CONNECTED_ERROR = 12, USER_REJECTS_ERROR = 300, METHOD_NOT_SUPPORTED = 400, CHAIN_NOT_SUPPORTED = 500, WALLET_NOT_SUPPORTED = 600, CONNECTION_ERROR = 700 } ``` - [UI](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-aptos-ui.md) # UI ## Installation and Initialization Make sure to update the OKX App to version 6.92.0 or later to begin access: To integrate OKX Connect into your DApp, you can use npm: ``` npm install @okxconnect/ui npm install @okxconnect/aptos-provider ``` Before connecting to the wallet, you need to create an object that can provide a UI interface for subsequent operations such as connecting to the wallet and sending transactions. ``` OKXUniversalConnectUI.init(dappMetaData, actionsConfiguration, uiPreferences, language) ``` **Request Parameterseters** - dappMetaData - object - name - string: The name of the application, will not be used as a unique representation. - icon - string: URL of the application icon, must be in PNG, ICO, etc. SVG icons are not supported. SVG icons are not supported. It is best to pass a url pointing to a 180x180px PNG icon. - actionsConfiguration - object - modals - ('before' | 'success' | 'error')[] | 'all' The modes of displaying alerts during transaction, defaults to 'before'. - returnStrategy -string 'none' | `${string}://${string}`; for app wallet, specify the return strategy for the deep link when the user signs/rejects the request, if it is in telegram, you can configure tg://resolve - uiPreferences -object - theme - Theme can be: THEME.DARK, THEME.LIGHT, 'SYSTEM'. - language - 'en_US' | 'ru_RU' | 'zh_CN' | 'ar_AE' | 'cs_CZ' | 'de_DE' | 'es_ES' | 'es_LAT' | 'fr_FR' | 'id_ID' | 'it_IT' | 'nl_NL' | 'pl_PL' | 'pt_BR' | 'pt_PT' | 'ro_RO' | 'tr_TR' | 'uk_UA' | 'vi_VN'. , defaults to en_US **Return value** - OKXUniversalConnectUI **Examples** ```typescript import { OKXUniversalConnectUI } from "@okxconnect/ui"; const okxUniversalConnectUI = await OKXUniversalConnectUI.init({ dappMetaData: { icon: "https://static.okx.com/cdn/assets/imgs/247/58E63FEA47A2B7D7.png", name: "OKX Connect Demo" }, actionsConfiguration: { returnStrategy: 'tg://resolve', modals:"all" }, language: "en_US", uiPreferences: { theme: THEME.LIGHT }, }); ``` ## Connecting to a wallet Connecting to a wallet goes to get the wallet address as an identifier and the necessary parameters used to sign the transaction. ``` okxUniversalConnectUI.openModal(connectParams: ConnectParams); ``` **Request Parameterseters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace ; Necessary information for the requested connection, the key is 'eip155' for EVM systems and 'aptos' for Aptos systems. If any of the requested chains are not supported by the wallet, the wallet will reject the connection - chains: string[]; chain id information - defaultChain?: string; default chain - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information for requesting a connection, the key for EVM is 'eip155' and for Aptos is 'aptos'. If the corresponding chain information is not supported by the wallet, the connection can still be made - chains: string[]; Chain id information - defaultChain?: string; default chain - sessionConfig: object - redirect: string Jump parameter after successful connection, if it is Mini App in Telegram, here can be set to Telegram's deeplink: 'tg://resolve' **Return value** - Promise `` - topic: string; the session identifier; - namespaces: `Record`; namespace information for a successful connection; - chains: string[]; Chain information for the connection - accounts: string[]; accounts information for the connection - methods: string[]; methods supported by the wallet under the current namespace - defaultChain?: string; The default chain for the current session. - sessionConfig?: SessionConfig - dappInfo: object DApp information - name:string - icon:string - redirect?: string, the redirect parameter after successful connection **Example** ```typescript var session = await okxUniversalConnectUI.openModal({ namespaces: { aptos: { chains: ["aptos:mainnet", // aptos mainnet // "movement:mainnet",// movement mainnet // "movement:testnet",// movement testnet ], } }, sessionConfig: { redirect: "tg://resolve" } }) ``` ## Connect to wallet and sign Connect to the wallet to get the wallet address and sign the data; the result will be called back in the event 'connect_signResponse' ``` await okxUniversalConnectUI.openModalAndSign(connectParams: ConnectParams, signRequest: RequestParams[]); ``` **Request Parameters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace ; information necessary to request a connection, the key for Aptos is 'aptos'. If any of the requested chains are not supported by the wallet, the wallet will reject the connection - chains: string[]; chain id information - defaultChain?: string; default chain - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information about the requested connection, the key for Aptos is 'aptos'. If the corresponding chain information is not supported by the wallet, the connection can still be made - chains: string[]; chain id information - defaultChain?: string; default chain - sessionConfig: object - redirect: string Jump parameter after successful connection, if it is a Mini App in Telegram, here can be set to Telegram's deeplink: 'tg://resolve' - signRequest - RequestParams[]; the method to request the connection and sign the request, at most one method can be supported at the same time; - method: string; the name of the requested method, Aptos supports the method: 'aptos_signMessage' - chainId: string; the ID of the chain in which the method is executed, this chainId must be included in the namespaces above - params: unknown[] | Record`` | object | undefined; Parameters corresponding to the requested method **Return Value** - Promise `` - topic: string; the session identifier - namespaces: `Record`; namespace information for a successful connection - chains: string[]; Chain information for the connection - accounts: string[]; accounts information for the connection - methods: string[]; Methods supported by the wallet in the current namespace - defaultChain?: string; The default chain for the current session - sessionConfig?: SessionConfig - dappInfo: object DApp information; - name: string - icon:string **Example** ```typescript // Add the signature result monitor first okxUniversalConnectUI.on("connect_signResponse", (signResponse) => { console.log(signResponse); }); var session = await okxUniversalConnectUI.openModalAndSign({ namespaces: { aptos: { chains: ["aptos:mainnet", // aptos mainnet // "movement:testnet",// movement testnet ], } }, sessionConfig: { redirect: "tg://resolve" } }, [ { chainId: "aptos:mainnet", method: "aptos_signMessage", params: { address: true, application: true, chainId: true, message: "Hello Aptos", nonce: "1234" } } ]) ``` ## Determine if the wallet is connected Check if wallet is connected **Return Value** - boolean **Example** ```typescript okxUniversalConnectUI.connected(); ``` ## Prepare the transaction First create an OKXAptosProvider object, with the constructor passing in OKXUniversalProvider ```typescript import { OKXAptosProvider } from '@okxconnect/aptos-provider' ; let okxAptosProvider = new OKXAptosProvider(okxUniversalConnectUI) ``` ***Get the wallet address and publicKey*** ``` okxAptosProvider.getAccount(chain); ``` **Request Parameters** - chain: string, the id of the chain to get the wallet address, if you don't pass it, it will take the first connected aptos system address. **Return Value** - Object - address: string The address of the wallet. - publicKey: string Public key ## Signature ``` okxAptosProvider.signMessage(message, chain); ``` **Request Parameterseters** - message - object - address?: boolean; // Should we include the address of the account in the message - application?: boolean; // Should we include the domain of the DApp - chainId?: boolean; // Should we include the current chain id the wallet is connected to - message: string; // The message to be signed and displayed to the user - nonce: string; // A nonce the DApp should generate - chain: string, the chain to be executed by the request signature, it is recommended to pass this parameter; it is mandatory to pass this parameter when connecting multiple chains; **Return value** - Promise - object - address: string; - application: string; - chainId: number; - fullMessage: string; // The message that was generated to sign - message: string; // The message passed in by the user - nonce: string; - prefix: string; // Should always be APTOS - signature: string; // The signed full message ## sign single transaction ``` okxAptosProvider.signTransaction(transaction, chain); ``` **Request Parameters** - transaction - object | SimpleTransaction transaction data object - chain: string, the chain for which the signature execution is requested, this parameter is recommended; mandatory when connecting multiple chains; **Return Value** - Promise - Buffer signed result. ## Sign transaction and broadcast on chain `okxAptosProvider.signAndSubmitTransaction(transaction, chain);` **Request Parameters** - transaction - object | SimpleTransaction transaction data object - chain: string, the chain for which the signature execution is requested, this parameter is recommended; mandatory when connecting multiple chains; **Return Value** - Promise - string transaction hash. **Example** ```typescript // Signature message let data = { address:true, application:true, chainId:true, message:"Hello OKX", nonce:"1234" } let provider = new OKXAptosProvider(okxUniversalConnectUI) let message = await provider.signMessage(data, "aptos:mainnet") //return value {'address': '0x2acddad65c27c6e5b568b398f0d1d01ebb8b55466461bbd51c1e42763a92fdfe', 'application': 'http://192.168.101.13',"' chainId": “aptos:mainnet”, “fullMessage”: 'APTOS\naddress: 0x2acddad65c27c6e5b568b398f0d1d01ebb8b55466461bbd51c1e42763a92fdfe\ napplication: http://192.168.101.13\nchainId: aptos:mainnet\nmessage: 123 Signature Test! \nnonce: 1234', “message”: '123 Signature test!' , 'nonce': '1234', 'prefix': 'APTOS', 'signature':' 0xef4e587f537b80a2f4e424079984b80e130c92d939a92225764be00ed36486521e8857b8a222de4023c5f4d2e9fd2f62c26ca8a43694660583c8a5d4328da303 ', 'verified':true} // Sign the transaction and upload it const config = new AptosConfig({ network: Network.MAINNET }); const aptos = new Aptos(config); // Support for transactions created via @aptos-labs/ts-sdk const transaction = await aptos.transaction.build.simple({ sender: '0x07897a0496703c27954fa3cc8310f134dd1f7621edf5e88b5bf436e4af70cfc6', data: { function: '0x80273859084bc47f92a6c2d3e9257ebb2349668a1b0fb3db1d759a04c7628855::router::swap_exact_coin_for_coin_x1', typeArguments: ['0x1::aptos_coin::AptosCoin', '0x111ae3e5bc816a5e63c2da97d0aa3886519e0cd5e4b046659fa35796bd11542a::stapt_token:. StakedApt', '0x0163df34fccbf003ce219d3f1d9e70d140b60622cb9dd47599c25fb2f797ba6e::curves::Uncorrelated', ' 0x80273859084bc47f92a6c2d3e9257ebb2349668a1b0fb3db1d759a04c7628855::router::BinStepV0V05'], functionArguments: ['10000', ['9104'], ['5'], ['true']], } }); let result1 = await provider.signAndSubmitTransaction(transaction, 'aptos:mainnet'); // Transactions that also support the following data formats let transactionData = { "arguments": ["100000",["0","0","10533"],["10","5","5"],["false","false","true"]], "function": "0x80273859084bc47f92a6c2d3e9257ebb2349668a1b0fb3db1d759a04c7628855::router::swap_exact_coin_for_coin_x3", "type": "entry_function_payload", "type_arguments": ["0x1::aptos_coin::AptosCoin","0x73eb84966be67e4697fc5ae75173ca6c35089e802650f75422ab49a8729704ec::coin::DooDoo","0x53a30a6e5936c0a4c5140daed34de39d17ca7fcae08f947c02e979cef98a3719::coin::LSD","0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDC","0x80273859084bc47f92a6c2d3e9257ebb2349668a1b0fb3db1d759a04c7628855::router::CurveV1","0x0163df34fccbf003ce219d3f1d9e70d140b60622cb9dd47599c25fb2f797ba6e::curves::Uncorrelated","0x0163df34fccbf003ce219d3f1d9e70d140b60622cb9dd47599c25fb2f797ba6e::curves::Uncorrelated","0x54cb0bb2c18564b86e34539b9f89cfe1186e39d89fce54e1cd007b8e61673a85::bin_steps::X80","0x80273859084bc47f92a6c2d3e9257ebb2349668a1b0fb3db1d759a04c7628855::router::BinStepV0V05","0x80273859084bc47f92a6c2d3e9257ebb2349668a1b0fb3db1d759a04c7628855::router::BinStepV0V05"] } let result2 = await provider.signAndSubmitTransaction(transactionData, "movement:testnet") ``` ## Disconnect wallet Disconnect the connected wallet and delete the current session. If you want to switch the connected wallet, please disconnect the current wallet first. ```typescript okxUniversalConnectUI.disconnect(); ``` ## Event ```typescript // Generate universalLink okxUniversalConnectUI.on("display_uri", (uri) => { console.log(uri); }); // Session information changes will trigger this event; okxUniversalConnectUI.on("session_update", (session) => { console.log(JSON.stringify(session)); }); // Disconnecting triggers this event; okxUniversalConnectUI.on("session_delete", ({topic}) => { console.log(topic); }); // This event is triggered when a connection is made and the signature is signed. okxUniversalConnectUI.on("connect_signResponse", (signResponse) => { console.log(signResponse); }); ``` ## Error codes Exceptions that may be thrown during connection, transaction, and disconnection. **Exception** | Error Code | Description | |----------------------------------------------|-------------------------| | OKX_CONNECT_ERROR_CODES.UNKNOWN_ERROR | Unknown Error | | OKX_CONNECT_ERROR_CODES.ALREADY_CONNECTED_ERROR | Wallet Already Connected | | OKX_CONNECT_ERROR_CODES.NOT_CONNECTED_ERROR | Wallet Not Connected | | OKX_CONNECT_ERROR_CODES.USER_REJECTS_ERROR | User Rejected | | OKX_CONNECT_ERROR_CODES.METHOD_NOT_SUPPORTED | Method Not Supported | | OKX_CONNECT_ERROR_CODES.CHAIN_NOT_SUPPORTED | Chain Not Supported | | OKX_CONNECT_ERROR_CODES.WALLET_NOT_SUPPORTED | Wallet Not Supported | | OKX_CONNECT_ERROR_CODES.CONNECTION_ERROR | Connection Error | ```typescript export enum OKX_CONNECT_ERROR_CODES { UNKNOWN_ERROR = 0, ALREADY_CONNECTED_ERROR = 11, NOT_CONNECTED_ERROR = 12, USER_REJECTS_ERROR = 300, METHOD_NOT_SUPPORTED = 400, CHAIN_NOT_SUPPORTED = 500, WALLET_NOT_SUPPORTED = 600, CONNECTION_ERROR = 700 } ``` - [Cosmos/Sei](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-cosmos.md) # Cosmos/Sei The Cosmos network consists of many independent, parallel blockchains, called zones, each powered by classical Byzantine fault-tolerant (BFT) consensus protocols like Tendermint (already used by platforms like ErisDB). Some zones act as hubs with respect to other zones, allowing many zones to interoperate through a shared hub. The architecture is a more general application of the Bitcoin sidechains concept, using classic BFT and Proof-of-Stake algorithms, instead of Proof-of-Work. Cosmos can interoperate with multiple other applications and cryptocurrencies, something other blockchains can't do well. By creating a new zone, you can plug any blockchain system into the Cosmos hub and pass tokens back and forth between those zones, without the need for an intermediary.
  • If connecting via SDK, add a "Connect OKX Wallet" button within the DApp. Clicking this button will launch the mobile App Wallet and enable interaction with the OKX Wallet, such as retrieving addresses, initiating wallet signatures, and other functions.
  • In addition to SDK, we also provide a UI interface.
- [SDK](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-cosmos-sdk.md) # SDK ## Installation and Initialization Make sure to update to version 6.94.0 or later to start integrating OKX Connect into your DApp can be done using npm: ``` npm install @okxconnect/universal-provider ``` Before connecting to a wallet, you need to create an object for subsequent operations such as connecting to the wallet and sending transactions. ``` OKXUniversalProvider.init({dappMetaData: {name, icon}}) ``` **Request Parameters** - dappMetaData - object - name - string: The name of the application, will not be used as a unique representation. - icon - string: URL of the application icon, must be in PNG, ICO, etc. SVG icons are not supported. SVG icons are not supported. It is better to pass a url pointing to a 180x180px PNG icon. **Returns Value** - OKXUniversalProvider **Examples** ```typescript import { OKXUniversalProvider } from "@okxconnect/universal-provider"; const okxUniversalProvider = await OKXUniversalProvider.init({ dappMetaData: { name: "application name", icon: "application icon url" }, }) ``` ## Connecting to a wallet Connect to the wallet to get the wallet address as an identifier and the necessary parameters for signing transactions. ``` okxUniversalProvider.connect(connectParams: ConnectParams); ``` **Request Parameters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace ; Optional information about the requested connection, the key of the COSMOS system is 'cosmos', the wallet will reject the connection if any of the requested chains are not supported by the wallet; - chains: string[]; chain id information - defaultChain?: string; defaultChain - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information of the requested connection, the key of COSMOS is 'cosmos', if the corresponding chain is not supported by the wallet, it can still be connected; - chains: string[]; chain id information - defaultChain?: string; default chain - sessionConfig: object - redirect: string The jump parameter after successful connection, if it is Mini App in Telegram, here can be set to Telegram's deeplink: 'tg://resolve' **Returns Value** - Promise `` - topic: string; Session identifier; - namespaces: `Record`; namespace information for a successful connection; - chains: string[]; Chain information for the connection; - accounts: string[]; accounts information for the connection; - methods: string[]; Methods supported by the wallet in the current namespace; - defaultChain?: string; The default chain for the current session. - sessionConfig?: SessionConfig - dappInfo: object DApp information; - name: string - icon:string - redirect?: string, the redirect parameter after successful connection; **Example** ```typescript var session = await okxUniversalProvider.connect({ namespaces: { cosmos: { chains: [ "cosmos:cosmoshub-4", // "cosmos:osmosis-1" ], } }, sessionConfig: { redirect: "tg://resolve" } }) ``` ## Determine if the wallet is connected Gets whether the wallet is currently connected. **Return Value** - boolean **Example** ```typescript okxUniversalProvider.connected(); ``` ## Prepare the transaction First create an OKXCosmosProvider object and pass OKXUniversalProvider into the constructor. ```typescript import { OKXCosmosProvider } from "@okxconnect/universal-provider"; let okxCosmosProvider = new OKXCosmosProvider(okxUniversalProvider) ``` ## Get account information ``` okxCosmosProvider.getAccount(chainId); ``` ***Request Parameterseters*** - chainId: the requested chain, e.g. cosmos:cosmoshub-4, cosmos:osmosis-1 ***Return Value*** - Object - algo: 'secp256k1', - address: string wallet-address, bech32Address: string wallet-address, bech32Address - bech32Address: string walletAddress, pubKey: Uint8Address, pubKey: Uint8Address - pubKey: Uint8Array publicKey, pubKey: Uint8Array publicKey, pubKey: Uint8Array publicKey ***Example*** ```typescript let result = okxCosmosProvider.getAccount("cosmos:cosmoshub-4") //Return structure { "algo": "secp256k1", "address": "cosmos1u6lts9ng4etxj0zdaxsada6zgl8dudpg3ygvjw", "bech32Address": "cosmos1u6lts9ng4etxj0zdaxsada6zgl8dudpg3ygvjw", "pubKey": { "0": 2, "1": 68, "2": 110, ... "32": 144 } } ``` ## Sign the message ``` okxCosmosProvider.signArbitrary(chain, signerAddress, message); ``` ***Request Parameters*** - chain - string, chain of requested execution methods - signerAddress - string The address of the signature wallet. - message - string The message to be signed. ***Return Value*** - Promise - object - pub_key : object - type:string Public key type - value: string Public key - signature: string Signature result ***Example*** ```ts let chain = "cosmos:cosmoshub-4" let signStr = "data need to sign ..." let result = okxCosmosProvider.signArbitrary(chain, signStr) //Return structure: {"pub_key":{"type":"tendermint/PubKeySecp256k1","value":"AkRuGelKwOg+qJbScSUHV36zn73S1q6fD8C5dZ8furqQ"},"signature":"YSyndEFlHYTWpSXsn28oolZpKim/BnmCVD0hZfvPQHQV3Bc0B0EU77CKE6LpV+PUJn19d1skAQy/bXyzppnuxw=="} ``` ## SignAmino ``` okxCosmosProvider.signAmino(chainId: string, signerAddress: string, signDoc: StdSignDoc, signOptions?: object); ``` ***Request Parameters*** - chainId - string, the chain for which the signature execution is requested, mandatory parameter - signerAddress - string, the address of the wallet. - signDoc - object, the transaction information to be signed in a fixed format, similar to cosmjs OfflineSigner signAmino method, the parameters are objects, signDoc is a fixed format. ***signDoc is a fixed format. - Promise - Object - signed - object,transaction information - signature -object, the result of the signature. ***Example*** ```ts let signDoc = { "chain_id": "osmosis-1", "account_number": "630104", "sequence": "480", "fee": {"gas": "683300", "amount": [{"denom": "uosmo", "amount": "2818"}]}, "msgs": [{ "type": "osmosis/poolmanager/swap-exact-amount-in", "value": { "sender": "osmo1u6lts9ng4etxj0zdaxsada6zgl8dudpgelmuyu", "routes": [{ "pool_id": "1096", "token_out_denom": "ibc/987C17B11ABC2B20019178ACE62929FE9840202CE79498E29FE8E5CB02B7C0A4" }, { "pool_id": "611", "token_out_denom": "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2" }], "token_in": {"denom": "uosmo", "amount": "100"}, "token_out_min_amount": "8" } }], "memo": "FE", "timeout_height": "23603788", "signOptions": { "useOneClickTrading": false, "preferNoSetFee": true, "fee": {"gas": "683300", "amount": [{"denom": "uosmo", "amount": "2818"}]} } } let res = await provider.signAmino("cosmos:osmosis-1", provider.getAccount("cosmos:osmosis-1").address, signDoc) /** Return structure: { "signed": { "chain_id": "osmosis-1", "account_number": "630104", "sequence": "480", "fee": { "amount": [ { "amount": "12500", "denom": "uosmo" } ], "gas": "500000" }, "msgs": [ { "type": "osmosis/poolmanager/swap-exact-amount-in", "value": { "sender": "osmo1u6lts9ng4etxj0zdaxsada6zgl8dudpgelmuyu", "routes": [ { "pool_id": "1096", "token_out_denom": "ibc/987C17B11ABC2B20019178ACE62929FE9840202CE79498E29FE8E5CB02B7C0A4" }, { "pool_id": "611", "token_out_denom": "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2" } ], "token_in": { "denom": "uosmo", "amount": "100" }, "token_out_min_amount": "8" } } ], "memo": "FE", "timeout_height": "23603788", "signOptions": { "useOneClickTrading": false, "preferNoSetFee": true, "fee": { "gas": "683300", "amount": [ { "denom": "uosmo", "amount": "2818" } ] } } }, "signature": { "pub_key": { "type": "tendermint/PubKeySecp256k1", "value": "AkRuGelKwOg+qJbScSUHV36zn73S1q6fD8C5dZ8furqQ" }, "signature": "2Brt/w+1U3C+tIbsI//pv9zTYca9WlBd1eKm/Gde5MFaRagmxtsn6h2beP7+4R4MDav7r1G+0Nxd5arB0qVfUw==" } } */ ``` ## SignDirect ``` okxCosmosProvider.signDirect(chainId, signerAddress, signDoc, signOptions?); ``` ***Request Parameters*** - chainId - string, the chain where the signature execution is requested, mandatory parameter. - signerAddress - string, wallet address - signDoc - object transaction data - bodyBytes ,Uint8Array - authInfoBytes, Uint8Array - chainId, string - accountNumber, string ***Return Value*** - Promise - Object - signed - object,transaction information - signature -object, the result of the signature. ***Example*** ```ts let signDoc = { "bodyBytes": Uint8Array, "authInfoBytes": Uint8Array, "chainId": "osmosis-1", "accountNumber": "630104", } let res = await provider.signDirect("cosmos:osmosis-1", provider.getAccount("cosmos:osmosis-1").address, signDoc) /** The return structure is the same as { "signed": { "bodyBytes": { "type": "Buffer", "data": [ 10, 193, 1, 10, 41, ...] }, "authInfoBytes": { "0": 10, "1": 81, ... }, "chainId": "osmosis-1", "accountNumber": "630104" }, "signature": { "pub_key": { "type": "tendermint/PubKeySecp256k1", "value": "AkRuGelKwOg+qJbScSUHV36zn73S1q6fD8C5dZ8furqQ" }, "signature": "YpX2kGmbZYVxUqK8y9OCweJNgZkS4WaS79nBDfOJaTgowPfY0gSbXSQeRLlif2SIkBqcwTNSItBqb5M7a6K30g==" } } */ ``` ## Disconnect wallet Disconnect the connected wallet and delete the current session. If you want to switch the connected wallet, please disconnect the current wallet first. ```typescript okxUniversalProvider.disconnect(); ``` ## Event ```typescript // Generate universalLink okxUniversalProvider.on('display_uri', (uri) => { console.log(uri); }); // Session information changes will trigger this event; okxUniversalProvider.on('session_update', (session) => { console.log(JSON.stringify(session)); // Session information changes (e.g., adding a custom chain). }); // Disconnecting triggers this event; okxUniversalProvider.on('session_delete', ({topic}) => { console.log(topic); }); ``` ## Error codes Exceptions that may be thrown during connection, transaction, and disconnection. **Exception** | Error Code | Description | |----------------------------------------------|-------------------------| | OKX_CONNECT_ERROR_CODES.UNKNOWN_ERROR | Unknown Error | | OKX_CONNECT_ERROR_CODES.ALREADY_CONNECTED_ERROR | Wallet Already Connected | | OKX_CONNECT_ERROR_CODES.NOT_CONNECTED_ERROR | Wallet Not Connected | | OKX_CONNECT_ERROR_CODES.USER_REJECTS_ERROR | User Rejected | | OKX_CONNECT_ERROR_CODES.METHOD_NOT_SUPPORTED | Method Not Supported | | OKX_CONNECT_ERROR_CODES.CHAIN_NOT_SUPPORTED | Chain Not Supported | | OKX_CONNECT_ERROR_CODES.WALLET_NOT_SUPPORTED | Wallet Not Supported | | OKX_CONNECT_ERROR_CODES.CONNECTION_ERROR | Connection Error | ```typescript export enum OKX_CONNECT_ERROR_CODES { UNKNOWN_ERROR = 0, ALREADY_CONNECTED_ERROR = 11, NOT_CONNECTED_ERROR = 12, USER_REJECTS_ERROR = 300, METHOD_NOT_SUPPORTED = 400, CHAIN_NOT_SUPPORTED = 500, WALLET_NOT_SUPPORTED = 600, CONNECTION_ERROR = 700 } ``` - [UI](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-cosmos-ui.md) # UI ## Installation and Initialization Make sure to update the OKX App to version 6.94.0 or later to start integrating OKX Connect into your DApp can be done using npm: ``` npm install @okxconnect/ui npm install @okxconnect/universal-provider ``` Before connecting to a wallet, you need to create an object that can provide a UI interface for subsequent operations such as connecting to the wallet and sending transactions. ``` OKXUniversalConnectUI.init(dappMetaData, actionsConfiguration, uiPreferences, language) ``` **Request Parameterseters** - dappMetaData - object - name - string: The name of the application, will not be used as a unique representation. - icon - string: URL of the application icon, must be in PNG, ICO, etc. SVG icons are not supported. SVG icons are not supported. It is best to pass a url pointing to a 180x180px PNG icon. - actionsConfiguration - object - modals - ('before' | 'success' | 'error')[] | 'all' The modes of displaying alerts during transaction, defaults to 'before'. - returnStrategy -string 'none' | `${string}://${string}`; for app wallet, specify the return strategy for the deep link when the user signs/rejects the request, if it is in telegram, you can configure tg://resolve - uiPreferences -object - theme - Theme can be: THEME.DARK, THEME.LIGHT, 'SYSTEM'. - language - 'en_US' | 'ru_RU' | 'zh_CN' | 'ar_AE' | 'cs_CZ' | 'de_DE' | 'es_ES' | 'es_LAT' | 'fr_FR' | 'id_ID' | 'it_IT' | 'nl_NL' | 'pl_PL' | 'pt_BR' | 'pt_PT' | 'ro_RO' | 'tr_TR' | 'uk_UA' | 'vi_VN'. , defaults to en_US **Return value** - OKXUniversalConnectUI **Example** ```typescript import { OKXUniversalConnectUI } from "@okxconnect/ui"; const okxUniversalConnectUI = await OKXUniversalConnectUI.init({ dappMetaData: { icon: "https://static.okx.com/cdn/assets/imgs/247/58E63FEA47A2B7D7.png", name: "OKX Connect Demo" }, actionsConfiguration: { returnStrategy: 'tg://resolve', modals:"all", tmaReturnUrl:'back' }, language: "en_US", uiPreferences: { theme: THEME.LIGHT }, }); ``` ## Connect to a wallet Connect to the wallet to get the wallet address as an identifier and the necessary parameters for signing transactions. ``` okxUniversalConnectUI.connect(connectParams: ConnectParams); ``` **Request Parameters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace ; Optional information about the requested connection, the key is 'eip155' for EVM, 'cosmos' for COSMOS, if any of the requested chain is not supported by the wallet, the wallet will reject the connection; - chains: string[]; chain id information - defaultChain?: string; defaultChain - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information of the requested connection, the key of EVM is 'eip155', the key of COSMOS is 'cosmos', if the corresponding chain information is not supported by the wallet, it can still be connected; - chains: string[]; chain id information - defaultChain?: string; default chain - sessionConfig: object - redirect: string Jump parameter after successful connection, if it is a Mini App in Telegram, you can set it to deeplink of Telegram: 'tg://resolve'. **Return Value** - Promise `` - topic: string; The session identifier; - namespaces: `Record`; namespace information for a successful connection; - chains: string[]; Chain information for the connection; - accounts: string[]; accounts information for the connection; - methods: string[]; Methods supported by the wallet in the current namespace; - defaultChain?: string; The default chain for the current session. - sessionConfig?: SessionConfig - dappInfo: object DApp information; - name: string - icon:string - redirect?: string, the redirect parameter after successful connection; **Example** ```typescript var session = await okxUniversalConnectUI.connect({ namespaces: { cosmos: { chains: [ "cosmos:cosmoshub-4", // "cosmos:osmosis-1" ], } }, sessionConfig: { redirect: "tg://resolve" } }) ``` ## Connect to wallet and sign Connect to the wallet to get the wallet address and sign the data; the result will be called back in the event 'connect_signResponse'; ``` await okxUniversalConnectUI.openModalAndSign(connectParams: ConnectParams, signRequest: RequestParams[]); ``` **Request Parameters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace ; Optional information about the requested connection, the key of COSMOS system is 'cosmos', if any of the requested chain is not supported by the wallet, the wallet will reject the connection - chains: string[]; chain id information - defaultChain?: string; defaultChain - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information of the requested connection, the key of COSMOS is 'cosmos', if the corresponding chain information is not supported by the wallet, it can still be connected - chains: string[]; chain id information - defaultChain?: string; default chain - sessionConfig: object - redirect: string The jump parameter after successful connection, if it is Mini App in Telegram, here can be set to Telegram's deeplink: 'tg://resolve' - signRequest - RequestParams[]; the method to request the connection and sign the request, at most one method can be supported at the same time - method: string; the name of the requested method, COSMOS supports the following methods: 'cosmos_signArbitrary' - chainId: string; the ID of the chain where the method is executed, the chainId must be included in the namespaces above - params: unknown[] | Record`` | object | undefined; Parameters corresponding to the requested method **Return Value** - Promise `` - topic: string; the session identifier; - namespaces: `Record`; namespace information for a successful connection; - chains: string[]; Chain information for the connection; - accounts: string[]; accounts information for the connection; - methods: string[]; Methods supported by the wallet in the current namespace; - defaultChain?: string; The default chain for the current session. - sessionConfig?: SessionConfig - dappInfo: object DApp information; - name: string - icon:string **Example** ```typescript // Add the signature result minitor first okxUniversalConnectUI.on("connect_signResponse", (signResponse) => { console.log(signResponse); }); var session = await okxUniversalConnectUI.openModalAndSign({ namespaces: { cosmos: { chains: [ "cosmos:cosmoshub-4", // "cosmos:osmosis-1" ], } }, sessionConfig: { redirect: "tg://resolve" } }, [ { chainId: "cosmos:cosmoshub-4", method: "cosmos_signArbitrary", params: { message: "Hello Cosmos" } } ]) ``` ## Determine if the wallet is connected Gets whether the wallet is currently connected. **Return Value** - boolean **Example** ```typescript okxUniversalConnectUI.connected(); ``` ## Prepare the transaction First create an OKXCosmosProvider object, with the constructor passing in OKXUniversalConnectUI ``` Type script import { OKXCosmosProvider } from '@okxconnect/universal-provider'; let okxCosmosProvider = new OKXCosmosProvider(okxUniversalConnectUI) ``` ## Get account information ``` okxCosmosProvider.getAccount(chainId) ``` ***Request Parameterseters*** - chainId: the requested chain, e.g. cosmos:cosmoshub-4, cosmos:osmosis-1 ***Return Value*** - Object - algo: 'secp256k1', - address: string wallet-address, bech32Address: string wallet-address, bech32Address - bech32Address: string walletAddress, pubKey: Uint8Address, pubKey: Uint8Address - pubKey: Uint8Array publicKey, pubKey: Uint8Array publicKey, pubKey: Uint8Array publicKey ***Example*** ```typescript let result = okxCosmosProvider.getAccount("cosmos:cosmoshub-4") //Return structure { "algo": "secp256k1", "address": "cosmos1u6lts9ng4etxj0zdaxsada6zgl8dudpg3ygvjw", "bech32Address": "cosmos1u6lts9ng4etxj0zdaxsada6zgl8dudpg3ygvjw", "pubKey": Unit8Aray, } ``` ## Sign the message ``` okxCosmosProvider.signArbitrary(chain, signerAddress, message) ``` ***Request Parameters*** - chain - string, chain of requested execution methods - signerAddress - string The address of the signature wallet. - message - string The message to be signed. ***Return Value*** - Promise - object - pub_key : object - type:string Public key type - value: string Public key - signature: string Signature result ***Example*** ```ts let chain = "cosmos:cosmoshub-4" let signStr = "data need to sign ..." let result = okxCosmosProvider.signArbitrary(chain, signStr) //Return structure: {"pub_key":{"type":"tendermint/PubKeySecp256k1","value":"AkRuGelKwOg+qJbScSUHV36zn73S1q6fD8C5dZ8furqQ"},"signature":"YSyndEFlHYTWpSXsn28oolZpKim/BnmCVD0hZfvPQHQV3Bc0B0EU77CKE6LpV+PUJn19d1skAQy/bXyzppnuxw=="} ``` ## SignAmino ``` okxCosmosProvider.signAmino(chainId: string, signerAddress: string, signDoc: StdSignDoc, signOptions?: object) ``` ***Request Parameters*** - chainId - string, the chain for which the signature execution is requested, mandatory parameter - signerAddress - string, the address of the wallet. - signDoc - object, the transaction information to be signed in a fixed format, similar to cosmjs OfflineSigner signAmino method, the parameter is the object, signDoc is a fixed format. ***signDoc is a fixed format. - Promise - Object - signed - object,transaction information - signature -object, the result of the signature. ***Example*** ```ts let signDoc = { "chain_id": "osmosis-1", "account_number": "630104", "sequence": "480", "fee": {"gas": "683300", "amount": [{"denom": "uosmo", "amount": "2818"}]}, "msgs": [{ "type": "osmosis/poolmanager/swap-exact-amount-in", "value": { "sender": "osmo1u6lts9ng4etxj0zdaxsada6zgl8dudpgelmuyu", "routes": [{ "pool_id": "1096", "token_out_denom": "ibc/987C17B11ABC2B20019178ACE62929FE9840202CE79498E29FE8E5CB02B7C0A4" }, { "pool_id": "611", "token_out_denom": "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2" }], "token_in": {"denom": "uosmo", "amount": "100"}, "token_out_min_amount": "8" } }], "memo": "FE", "timeout_height": "23603788", "signOptions": { "useOneClickTrading": false, "preferNoSetFee": true, "fee": {"gas": "683300", "amount": [{"denom": "uosmo", "amount": "2818"}]} } } let res = await provider.signAmino("cosmos:osmosis-1", provider.getAccount("cosmos:osmosis-1").address, signDoc) /** Return structure: { "signed": { "chain_id": "osmosis-1", "account_number": "630104", "sequence": "480", "fee": { "amount": [ { "amount": "12500", "denom": "uosmo" } ], "gas": "500000" }, "msgs": [ { "type": "osmosis/poolmanager/swap-exact-amount-in", "value": { "sender": "osmo1u6lts9ng4etxj0zdaxsada6zgl8dudpgelmuyu", "routes": [ { "pool_id": "1096", "token_out_denom": "ibc/987C17B11ABC2B20019178ACE62929FE9840202CE79498E29FE8E5CB02B7C0A4" }, { "pool_id": "611", "token_out_denom": "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2" } ], "token_in": { "denom": "uosmo", "amount": "100" }, "token_out_min_amount": "8" } } ], "memo": "FE", "timeout_height": "23603788", "signOptions": { "useOneClickTrading": false, "preferNoSetFee": true, "fee": { "gas": "683300", "amount": [ { "denom": "uosmo", "amount": "2818" } ] } } }, "signature": { "pub_key": { "type": "tendermint/PubKeySecp256k1", "value": "AkRuGelKwOg+qJbScSUHV36zn73S1q6fD8C5dZ8furqQ" }, "signature": "2Brt/w+1U3C+tIbsI//pv9zTYca9WlBd1eKm/Gde5MFaRagmxtsn6h2beP7+4R4MDav7r1G+0Nxd5arB0qVfUw==" } } */ ``` ## SignDirect ``` okxCosmosProvider.signDirect(chainId, signerAddress, signDoc, signOptions?) ``` ***Request Parameters*** - chainId - string, the chain where the signature execution is requested, mandatory parameter. - signerAddress - string, wallet address - signDoc - object transaction data - bodyBytes ,Uint8Array - authInfoBytes, Uint8Array - chainId, string - accountNumber, string ***Return Value*** - Promise - Object - signed - object,transaction information - signature -object, the result of the signature. ***Example*** ```ts let signDoc = { "bodyBytes": Uint8Array, "authInfoBytes": Uint8Array, "chainId": "osmosis-1", "accountNumber": "630104", } let res = await provider.signDirect("cosmos:osmosis-1", provider.getAccount("cosmos:osmosis-1").address, signDoc) /** { "signed": { "bodyBytes": Uint8Array, "authInfoBytes":Uint8Array , "chainId": "osmosis-1", "accountNumber": "630104" }, "signature": { "pub_key": { "type": "tendermint/PubKeySecp256k1", "value": "AkRuGelKwOg+qJbScSUHV36zn73S1q6fD8C5dZ8furqQ" }, "signature": "YpX2kGmbZYVxUqK8y9OCweJNgZkS4WaS79nBDfOJaTgowPfY0gSbXSQeRLlif2SIkBqcwTNSItBqb5M7a6K30g==" } } */ ``` ## Disconnect wallet Disconnect the connected wallet and delete the current session. If you want to switch the connected wallet, please disconnect the current wallet first. ```typescript okxUniversalConnectUI.disconnect(); ``` ## Event ```typescript // Generate universalLink okxUniversalConnectUI.on("display_uri", (uri) => { console.log(uri); }); // Session information changes will trigger this event; okxUniversalConnectUI.on("session_update", (session) => { console.log(JSON.stringify(session)); }); // Disconnecting triggers this event; okxUniversalConnectUI.on("session_delete", ({topic}) => { console.log(topic); }); // This event is triggered when a connection is made and the signature is signed. okxUniversalConnectUI.on("connect_signResponse", (signResponse) => { console.log(signResponse); }); ``` ## Error codes Exceptions that may be thrown during connection, transaction, and disconnection. **Exception** | Error Code | Description | |----------------------------------------------|-------------------------| | OKX_CONNECT_ERROR_CODES.UNKNOWN_ERROR | Unknown Error | | OKX_CONNECT_ERROR_CODES.ALREADY_CONNECTED_ERROR | Wallet Already Connected | | OKX_CONNECT_ERROR_CODES.NOT_CONNECTED_ERROR | Wallet Not Connected | | OKX_CONNECT_ERROR_CODES.USER_REJECTS_ERROR | User Rejected | | OKX_CONNECT_ERROR_CODES.METHOD_NOT_SUPPORTED | Method Not Supported | | OKX_CONNECT_ERROR_CODES.CHAIN_NOT_SUPPORTED | Chain Not Supported | | OKX_CONNECT_ERROR_CODES.WALLET_NOT_SUPPORTED | Wallet Not Supported | | OKX_CONNECT_ERROR_CODES.CONNECTION_ERROR | Connection Error | ```typescript export enum OKX_CONNECT_ERROR_CODES { UNKNOWN_ERROR = 0, ALREADY_CONNECTED_ERROR = 11, NOT_CONNECTED_ERROR = 12, USER_REJECTS_ERROR = 300, METHOD_NOT_SUPPORTED = 400, CHAIN_NOT_SUPPORTED = 500, WALLET_NOT_SUPPORTED = 600, CONNECTION_ERROR = 700 } ``` - [Tron](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-tron.md) # Tron Tron aims to build a decentralized content entertainment ecosystem. The Tron network employs a Delegated Proof of Stake (DPoS) consensus mechanism, which allows it to achieve high throughput and low transaction fees. As a smart contract platform, Tron is fully compatible with the Ethereum Virtual Machine (EVM), enabling developers to easily migrate decentralized applications (DApps) from Ethereum to the Tron network. Tron's native token is TRX, which is used for network governance, transaction fee payment, and value transfer. The platform focuses particularly on applications in the digital content, entertainment, and social media sectors, aiming to create an intermediary-free content distribution system. With its efficient performance and active developer community, Tron has become an important platform for decentralized finance (DeFi), non-fungible tokens (NFTs), and decentralized applications.
  • If connecting via SDK, add a "Connect OKX Wallet" button within the DApp. Clicking this button will launch the mobile App Wallet and enable interaction with the OKX Wallet, such as retrieving addresses, initiating wallet signatures, and other functions.
  • In addition to SDK, we also provide a UI interface.
- [SDK](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-tron-sdk.md) # SDK ## Installation and Initialization Make sure to update to version 6.96.0 or later to start integrating OKX Connect into your DApp can be done using npm: ``` npm install @okxconnect/universal-provider ``` Before connecting to a wallet, you need to create an object for subsequent operations such as connecting to the wallet and sending transactions. ``` OKXUniversalProvider.init({dappMetaData: {name, icon}}) ``` **Request Parameterseters** - dappMetaData - object - name - string: The name of the application, will not be used as a unique representation. - icon - string: URL of the application icon, must be in PNG, ICO, etc. SVG icons are not supported. SVG icons are not supported. It is better to pass a url pointing to a 180x180px PNG icon. **Return Value** - OKXUniversalProvider **Example** ```typescript import { OKXUniversalProvider } from "@okxconnect/universal-provider"; const okxUniversalProvider = await OKXUniversalProvider.init({ dappMetaData: { name: "application name", icon: "application icon url" }, }) ``` ## Connecting to a wallet Connect to the wallet to get the wallet address as an identifier and the necessary parameters for signing transactions. ``` okxUniversalProvider.connect(connectParams: ConnectParams); ``` **Request Parameters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace ; Optional information about the requested connection, TRON's key is "tron", if any of the requested chains is not supported by the chain wallet, the wallet will reject the connection; - chains: string[]; chain id information - defaultChain?: string; default chain - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information about the requested connection, TRON key is "tron", if the corresponding chain is not supported by the wallet, it can still be connected; - chains: string[]; chain id information - defaultChain?: string; default chain - sessionConfig: object - redirect: string The jump parameter after successful connection, if it is Mini App in Telegram, here you can set it to Telegram's deeplink: "tg://resolve" **Return value** - Promise `` - topic: string; the session identifier; - namespaces: `Record`; namespace information for a successful connection - chains: string[]; Chain information for the connection - accounts: string[]; accounts information for the connection - methods: string[]; Methods supported by the wallet in the current namespace - defaultChain?: string; The default chain for the current session - sessionConfig?: SessionConfig - dappInfo: object DApp information; - name: string - icon:string - redirect?: string, the redirect parameter after successful connection **Example** ```typescript var session = await okxUniversalProvider.connect({ namespaces: { tron: { chains: [ "tron:mainnet", ], } }, sessionConfig: { redirect: "tg://resolve" } }) ``` ## Prepare the transaction First create an OKXTronProvider object, with the constructor passing in OKXUniversalProvider ```typescript import { OKXTronProvider } from "@okxconnect/universal-provider" ; let okxTronProvider = new OKXTronProvider(okxUniversalProvider) ``` ## Get account information ``` okxTronProvider.getAccount(chainId?) ``` ***Request Parameterseters*** - chainId: the requested chain, e.g. tron:mainnet ***Return value*** - Object - address: string wallet address, ****Return Value ***Example*** ```typescript let result = okxTronProvider.getAccount("tron:mainnet") // Return structure { "address": "THyDJCGXYnwCSYNQeGYW98pptEVSHwaYx7" } ``` ## Sign the message ``` okxTronProvider.signMessage(message, chainId?) ``` ***Request Parameters*** - message - string, the message to be signed. - chainId? - string, the chain of the requested execution method, e.g. tron:mainnet ***Return Value*** - Promise - string The result of the signature. ***Example*** ```ts let chainId = "tron:mainnet" let signStr = "data need to sign ..." let result = okxTronProvider.signMessage(signStr, chainId) //返回:0xfc9003b1c8e68fdc93409aad911af274de1987130a36516f1c7c9353716463bf42bb400e0d6bffd4adface92dd3a01079ba32f8aebe3db1d5914f084b9f802711c ``` ## Signed message V2 ``` okxTronProvider.signMessageV2(message, chainId?) ``` ***Request Parameters*** - message - string, the message to be signed. - chainId - string, the chain of the requested execution method, e.g. tron:mainnet ***Return Value*** - Promise - string The result of the signature. ***Example*** ```ts let chainId = "tron:mainnet" let signStr = "data need to sign ..." let result = okxTronProvider.signMessageV2(signStr, chainId) //Return:0xfc9003b1c8e68fdc93409aad911af274de1987130a36516f1c7c9353716463bf42bb400e0d6bffd4adface92dd3a01079ba32f8aebe3db1d5914f084b9f802711c ``` ## SignTransaction ``` okxTronProvider.signTransaction(transaction: any, chainId?: string) ``` ***Request Parameterseters*** - transaction - object, transaction information, signed in a fixed format, can be generated by TronWeb.transactionBuilder. - chainId? - string, the chain in which the request signature is executed, not mandatory, e.g. tron:mainnet ***Return Value*** - Promise - Object signed transaction ***Example*** ```ts let tronWeb = new TronWeb({ "fullHost": 'https://api.trongrid.io', "headers": {}, "privateKey": '' }) let address = okxTronProvider.getAccount("tron:mainnet").address const transaction = await tronWeb.transactionBuilder.sendTrx("TGBcVLMnVtvJzjPWZpPiYBgwwb7th1w3BF", 1000, address); let res = await okxTronProvider.signTransaction(transaction,"tron:mainnet") /**Return results { "visible": true, "txID": "cf93bbfb0152d832fcdb1c65cb12a979eab5a631de1b3d7d6437757e1b16ed40", "raw_data": { "contract": [{ "parameter": { "type_url": "type.googleapis.com/protocol.TransferContract", "value": { "amount": 1000, "contract_address": "", "owner_address": "THyDJCGXYnwCSYNQeGYW98pptEVSHwaYx7", "to_address": "TGBcVLMnVtvJzjPWZpPiYBgwwb7th1w3BF" } }, "type": "TransferContract" }], "expiration": 1732073850000, "ref_block_bytes": "7ecf", "ref_block_hash": "7b3a6bc87d9edb9e", "timestamp": 1732073790000 }, "raw_data_hex": "0a027ecf22087b3a6bc87d9edb9e40908996bdb4325a66080112620a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412310a154157c140be01fa2bbabf7f055ab879d0c05725293c12154144295a45f811a9d595562562a2e27685291a715818e80770b0b492bdb432", "signature": ["239b402a7605199c6969f6f4da37a355452bd942c222adfc625721d18a1fff3223f92c1d8eaf5856c0e41ce80761fd2adb80d026276d6710ad183a713af7a78d00"] } */ ``` ## SignAndSendTransaction ``` okxTronProvider.signAndSendTransaction(transaction, chainId?) ``` ***Request Parameterseters*** - transaction - object, transaction information, signed in a fixed format, can be generated by TronWeb.transactionBuilder. - chainId - string,the chain in which the request signature is executed, not mandatory, e.g. tron:mainnet ***Return Value*** - Promise - string Transaction hash ***Example*** ```ts let tronWeb = new TronWeb({ "fullHost": 'https://api.trongrid.io', "headers": {}, "privateKey": '' }) let address = okxTronProvider.getAccount("tron:mainnet").address const transaction = await tronWeb.transactionBuilder.sendTrx("TGBcVLMnVtvJzjPWZpPiYBgwwb7th1w3BF", 1000, address); //转账TRX let res = await okxTronProvider.signAndSendTransaction(transaction, "tron:mainnet") //Return Value:50a47e450024c079510a39433e28de0bcac8406d731aadab7d772998dfce2aab ``` ## Disconnect wallet Disconnect the connected wallet and delete the current session. If you want to switch the connected wallet, please disconnect the current wallet first. ```typescript okxUniversalProvider.disconnect() ``` ## Event ```typescript // Generate universalLink okxUniversalProvider.on('display_uri', (uri) => { console.log(uri); }); // Session information changes will trigger this event; okxUniversalProvider.on('session_update', (session) => { console.log(JSON.stringify(session)); // Session information changes (e.g., adding a custom chain). }); // Disconnecting triggers this event; okxUniversalProvider.on('session_delete', ({topic}) => { console.log(topic); }); ``` ## Error codes Exceptions that may be thrown during connection, transaction, and disconnection. **Exception** | Error Code | Description | |----------------------------------------------|-------------------------| | OKX_CONNECT_ERROR_CODES.UNKNOWN_ERROR | Unknown Error | | OKX_CONNECT_ERROR_CODES.ALREADY_CONNECTED_ERROR | Wallet Already Connected | | OKX_CONNECT_ERROR_CODES.NOT_CONNECTED_ERROR | Wallet Not Connected | | OKX_CONNECT_ERROR_CODES.USER_REJECTS_ERROR | User Rejected | | OKX_CONNECT_ERROR_CODES.METHOD_NOT_SUPPORTED | Method Not Supported | | OKX_CONNECT_ERROR_CODES.CHAIN_NOT_SUPPORTED | Chain Not Supported | | OKX_CONNECT_ERROR_CODES.WALLET_NOT_SUPPORTED | Wallet Not Supported | | OKX_CONNECT_ERROR_CODES.CONNECTION_ERROR | Connection Error | ```typescript export enum OKX_CONNECT_ERROR_CODES { UNKNOWN_ERROR = 0, ALREADY_CONNECTED_ERROR = 11, NOT_CONNECTED_ERROR = 12, USER_REJECTS_ERROR = 300, METHOD_NOT_SUPPORTED = 400, CHAIN_NOT_SUPPORTED = 500, WALLET_NOT_SUPPORTED = 600, CONNECTION_ERROR = 700 } ``` - [UI](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-tron-ui.md) # UI ## Installation and Initialization Make sure to update the OKX App to version 6.96.0 or later to start integrating OKX Connect into your DApp can be done using npm: ``` npm install @okxconnect/ui npm install @okxconnect/universal-provider ``` Before connecting to a wallet, you need to create an object that can provide a UI interface for subsequent operations such as connecting to the wallet and sending transactions. ``` OKXUniversalConnectUI.init(dappMetaData, actionsConfiguration, uiPreferences, language) ``` **Request Parameterseters** - dappMetaData - object - name - string: The name of the application, will not be used as a unique representation. - icon - string: URL of the application icon, must be in PNG, ICO, etc. SVG icons are not supported. SVG icons are not supported. It is best to pass a url pointing to a 180x180px PNG icon. - actionsConfiguration - object - modals - ('before' | 'success' | 'error')[] | 'all' The modes of displaying alerts during transaction, defaults to 'before'. - returnStrategy -string 'none' | `${string}://${string}`; for app wallet, specify the return strategy for the deep link when the user signs/rejects the request, if it is in tg, you can configure tg://resolve - uiPreferences -object - theme - Theme can be: THEME.DARK, THEME.LIGHT, 'SYSTEM'. - language - 'en_US' | 'ru_RU' | 'zh_CN' | 'ar_AE' | 'cs_CZ' | 'de_DE' | 'es_ES' | 'es_LAT' | 'fr_FR' | 'id_ID' | 'it_IT' | 'nl_NL' | 'pl_PL' | 'pt_BR' | 'pt_PT' | 'ro_RO' | 'tr_TR' | 'uk_UA' | 'vi_VN'. , defaults to en_US **Return Value** - OKXUniversalConnectUI **Example** ```typescript import { OKXUniversalConnectUI } from "@okxconnect/ui"; const okxUniversalConnectUI = await OKXUniversalConnectUI.init({ dappMetaData: { icon: "https://static.okx.com/cdn/assets/imgs/247/58E63FEA47A2B7D7.png", name: "OKX Connect Demo" }, actionsConfiguration: { returnStrategy: 'tg://resolve', modals:"all", tmaReturnUrl:'back' }, language: "en_US", uiPreferences: { theme: THEME.LIGHT }, }); ``` ## Connecting to a wallet Connect to the wallet to get the wallet address as an identifier and the necessary parameters for signing transactions. ``` okxUniversalConnectUI.connect(connectParams: ConnectParams) ``` **Request Parameters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace ; Optional information about the requested connection, the key of TRON is 'tron', if any of the requested chains is not supported by the chain wallet, the wallet will reject the connection; - chains: string[]; chain id information - defaultChain?: string; default chain - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information about the requested connection, TRON key is 'tron', if the corresponding chain is not supported by the wallet, it can still be connected; - chains: string[]; chain id information - defaultChain?: string; default chain - sessionConfig: object - redirect: string The jump parameter after successful connection, if it is Mini App in Telegram, here you can set it to Telegram's deeplink: 'tg://resolve' **Return value** - Promise `` - topic: string; Session identifier - namespaces: `Record`; namespace information for a successful connection - chains: string[]; Chain information for the connection - accounts: string[]; accounts information for the connection - methods: string[]; Methods supported by the wallet in the current namespace - defaultChain?: string; The default chain for the current session - sessionConfig?: SessionConfig - dappInfo: object DApp information - name: string - icon:string - redirect?: string, the redirect parameter after successful connection **Example** ```typescript var session = await okxUniversalConnectUI.connect({ namespaces: { tron: { chains: [ "tron:mainnet" ], } }, sessionConfig: { redirect: "tg://resolve" } }) ``` ## Prepare the transaction First create an OKXTronProvider object, with the constructor passing in okxUniversalConnectUI ```typescript import { OKXTronProvider } from "@okxconnect/universal-provider"; let okxTronProvider = new OKXTronProvider(okxUniversalConnectUI) ``` ## Getting account information ``` okxTronProvider.getAccount(chainId?) ``` ***Request Parameterseters*** - chainId: the requested chain, e.g. tron:mainnet ***Return value*** - Object - address: string wallet address ***Example*** ```typescript let result = okxTronProvider.getAccount('tron:mainnet') //return structure { "address": "THyDJCGXYnwCSYNQeGYW98pptEVSHwaYx7" } ``` ## Sign the message ``` okxTronProvider.signMessage(message, chainId?) ``` ***Request Parameters*** - message - string, the message to be signed. - chainId? - string, the chain of the requested execution method, e.g. tron:mainnet ***Return Value*** - Promise - string The result of the signature. ***Example*** ```ts let chainId = "tron:mainnet" let signStr = "data need to sign ..." let result = okxTronProvider.signMessage(signStr, chainId) //Return: 0xfc9003b1c8e68fdc93409aad911af274de1987130a36516f1c7c9353716463bf42bb400e0d6bffd4adface92dd3a01079ba32f8aebe3db1d5914f084b9f802711c ``` ## Signed message V2 ``` okxTronProvider.signMessageV2(message, chainId?) ``` ***Request Parameters*** - message - string, the message to be signed. - chainId - string, the chain of the requested execution method, e.g. tron:mainnet ***Return Value*** - Promise - string The result of the signature. ***Example*** ```ts let chainId = "tron:mainnet" let signStr = "data need to sign ..." let result = okxTronProvider.signMessageV2(signStr, chainId) //Return: 0xfc9003b1c8e68fdc93409aad911af274de1987130a36516f1c7c9353716463bf42bb400e0d6bffd4adface92dd3a01079ba32f8aebe3db1d5914f084b9f802711c ``` ## SignTransaction ``` okxTronProvider.signTransaction(transaction: any, chainId?: string) ``` ***Request Parameterseters*** - transaction - object, transaction information Signed in a fixed format, can be generated by TronWeb.transactionBuilder - chainId? - string, the chain in which the request signature is executed, e.g. tron:mainnet ***Return Value*** - Promise - Object The signed transaction ***Example*** ```ts let tronWeb = new TronWeb({ "fullHost": 'https://api.trongrid.io', "headers": {}, "privateKey": '' }) let address = okxTronProvider.getAccount("tron:mainnet").address const transaction = await tronWeb.transactionBuilder.sendTrx("TGBcVLMnVtvJzjPWZpPiYBgwwb7th1w3BF", 1000, address); let res = await okxTronProvider.signTransaction(transaction,"tron:mainnet") /**Return results { "visible": true, "txID": "cf93bbfb0152d832fcdb1c65cb12a979eab5a631de1b3d7d6437757e1b16ed40", "raw_data": { "contract": [{ "parameter": { "type_url": "type.googleapis.com/protocol.TransferContract", "value": { "amount": 1000, "contract_address": "", "owner_address": "THyDJCGXYnwCSYNQeGYW98pptEVSHwaYx7", "to_address": "TGBcVLMnVtvJzjPWZpPiYBgwwb7th1w3BF" } }, "type": "TransferContract" }], "expiration": 1732073850000, "ref_block_bytes": "7ecf", "ref_block_hash": "7b3a6bc87d9edb9e", "timestamp": 1732073790000 }, "raw_data_hex": "0a027ecf22087b3a6bc87d9edb9e40908996bdb4325a66080112620a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412310a154157c140be01fa2bbabf7f055ab879d0c05725293c12154144295a45f811a9d595562562a2e27685291a715818e80770b0b492bdb432", "signature": ["239b402a7605199c6969f6f4da37a355452bd942c222adfc625721d18a1fff3223f92c1d8eaf5856c0e41ce80761fd2adb80d026276d6710ad183a713af7a78d00"] } */ ``` ## SignAndSendTransaction ``` okxTronProvider.signAndSendTransaction(transaction, chainId?) ``` ***Request Parameterseters*** - transaction - object, transaction information Signed in a fixed format, can be generated by TronWeb.transactionBuilder - chainId - string, the chain in which the request signature is executed, e.g. tron:mainnet ***Return Value*** - Promise - string Transaction hash ***Example*** ```ts let tronWeb = new TronWeb({ "fullHost": 'https://api.trongrid.io', "headers": {}, "privateKey": '' }) let address = okxTronProvider.getAccount("tron:mainnet").address const transaction = await tronWeb.transactionBuilder.sendTrx("TGBcVLMnVtvJzjPWZpPiYBgwwb7th1w3BF", 1000, address); //转账TRX let res = await okxTronProvider.signAndSendTransaction(transaction, "tron:mainnet") //return value:50a47e450024c079510a39433e28de0bcac8406d731aadab7d772998dfce2aab ``` ## Disconnect wallet Disconnect the connected wallet and delete the current session. If you want to switch the connected wallet, please disconnect the current wallet first. ```typescript okxUniversalConnectUI.disconnect() ``` ## Event ```typescript // Generate universalLink okxUniversalConnectUI.on("display_uri", (uri) => { console.log(uri); }); // Session information changes will trigger this event; okxUniversalConnectUI.on("session_update", (session) => { console.log(JSON.stringify(session)); }); // Disconnecting triggers this event; okxUniversalConnectUI.on("session_delete", ({topic}) => { console.log(topic); }); // This event is triggered when a connection is made and the signature is signed. okxUniversalConnectUI.on("connect_signResponse", (signResponse) => { console.log(signResponse); }); ``` ## Error codes Exceptions that may be thrown during connection, transaction, and disconnection. **Exception** | Error Code | Description | |----------------------------------------------|-------------------------| | OKX_CONNECT_ERROR_CODES.UNKNOWN_ERROR | Unknown Error | | OKX_CONNECT_ERROR_CODES.ALREADY_CONNECTED_ERROR | Wallet Already Connected | | OKX_CONNECT_ERROR_CODES.NOT_CONNECTED_ERROR | Wallet Not Connected | | OKX_CONNECT_ERROR_CODES.USER_REJECTS_ERROR | User Rejected | | OKX_CONNECT_ERROR_CODES.METHOD_NOT_SUPPORTED | Method Not Supported | | OKX_CONNECT_ERROR_CODES.CHAIN_NOT_SUPPORTED | Chain Not Supported | | OKX_CONNECT_ERROR_CODES.WALLET_NOT_SUPPORTED | Wallet Not Supported | | OKX_CONNECT_ERROR_CODES.CONNECTION_ERROR | Connection Error | ```typescript export enum OKX_CONNECT_ERROR_CODES { UNKNOWN_ERROR = 0, ALREADY_CONNECTED_ERROR = 11, NOT_CONNECTED_ERROR = 12, USER_REJECTS_ERROR = 300, METHOD_NOT_SUPPORTED = 400, CHAIN_NOT_SUPPORTED = 500, WALLET_NOT_SUPPORTED = 600, CONNECTION_ERROR = 700 } ``` - [Starknet](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-starknet.md) # Starknet Starknet is a Validity-Rollup (aka ZK-Rollup) Layer 2 network that operates on top of Ethereum, enabling dApps to massively scale without compromising on security. It achieves this by bundling transactions into an off-chain computed STARK proof. This proof is then submitted to Ethereum as a single transaction, resulting in significantly higher throughput, faster processing times, and much lower costs, all while retaining the robust security of the Ethereum settlement layer.
  • If connecting via SDK, add a "Connect OKX Wallet" button within the DApp. Clicking this button will launch the mobile App Wallet and enable interaction with the OKX Wallet, such as retrieving addresses, initiating wallet signatures, and other functions.
  • In addition to SDK, we also provide a UI interface.
- [SDK](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-starknet-sdk.md) # SDK ## Installation and Initialization Make sure to update to version 6.98.0 or later to start integrating OKX Connect into your DApp can be done using npm: ``` npm install @okxconnect/universal-provider ``` Before connecting to a wallet, you need to create an object for subsequent operations such as connecting to the wallet and sending transactions. ``` OKXUniversalProvider.init({dappMetaData: {name, icon}}) ``` **Request Parameterseters** - dappMetaData - object - name - string: The name of the application, will not be used as a unique representation. - icon - string: URL of the application icon, must be in PNG, ICO, etc. SVG icons are not supported. SVG icons are not supported. It is better to pass a url pointing to a 180x180px PNG icon. **Returns a value** - OKXUniversalProvider **Examples** ```typescript import { OKXUniversalProvider } from "@okxconnect/universal-provider"; const okxUniversalProvider = await OKXUniversalProvider.init({ dappMetaData: { name: "application name", icon: "application icon url" }, }) ``` ## Connecting to a wallet Connect to the wallet to get the wallet address as an identifier and the necessary parameters for signing transactions. ``` okxUniversalProvider.connect(connectParams: ConnectParams) ``` **Request Parameters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace ; Optional information for the requested connection, the key for the starknet family is 'starknet', currently only starknet:mainnet is supported, if any of the requested chain is not supported by the current wallet, the If any of the requested chains is not supported by the current wallet, the wallet will reject the connection; - chains: string[]; chain id information - defaultChain?: string; default chain - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information of the requested connection, the key of the starknet system is 'starknet', currently only starknet:mainnet is supported, if the requested chain is not supported by the current wallet, it can still be connected. If the requested chain is not supported by the current wallet, it can still be connected; - chains: string[]; chain id information - defaultChain?: string; default chain - sessionConfig: object - redirect: string Jump parameter after successful connection, if it is a Mini App in Telegram, here can be set to Telegram's deeplink: 'tg://resolve' **Return value** - Promise `` - topic: string; the session identifier - namespaces: `Record`; namespace information for a successful connection - chains: string[]; Chain information for the connection - accounts: string[]; accounts information for the connection - methods: string[]; Methods supported by the wallet in the current namespace - defaultChain?: string; The default chain for the current session - sessionConfig?: SessionConfig - dappInfo: object DApp information - name: string - icon:string - redirect?: string, the redirect parameter after a successful connection **Example** ```typescript var session = await okxUniversalProvider.connect({ namespaces: { starknet: { chains: [ "starknet:mainnet", ], } }, sessionConfig: { redirect: "tg://resolve" } }) ``` ## Prepare the transaction First create an OKXStarknetProvider object, with the constructor passing in OKXUniversalProvider ```typescript import { OKXStarknetProvider } from '@okxconnect/universal-provider' ; let okxStarknetProvider = new OKXStarknetProvider(okxUniversalProvider) ``` ## Get account information ``` okxStarknetProvider.getAccount(chainId) ``` ***Request Parameterseters*** - chainId: the requested chain, e.g. starknet:mainnet ***Return value*** - Object - address: string wallet address - pubKey: string public key ***Example*** ```typescript let result = okxStarknetProvider.getAccount("starknet:mainnet") // Return structure { address:"0x0667ae9b1c3d3ab1dacffd8b23269e9fedf2f8de5c57a35fe0a55f209db59179", pubKey:"07c26f0fd90a6847d3de5ce7002dcd9454b45a78d5592ee369c4d7561fa5e5ee" } ``` ## Sign the message ``` okxStarknetProvider.signMessage(signerAddress, typedData, chain) ``` ***Request Parameterseters*** - signerAddress - string, wallet address - typedData - object The message to be signed, in a fixed format. - chain? - string, chain of requested execution methods ***Return Value*** - Promise - [string, string] Signature result r, v ***Example*** ```ts let chain = "starknet:mainnet" let address = okxStarknetProvider.getAccount("starknet:mainnet").address const signData = { "domain": { "chainId": "0x534e5f4d41494e", "name": "STRKFarm", "version": "1" }, "message": { "document": "app.strkfarm.xyz/tnc/v1", "message": "Read and Agree T&C" }, "primaryType": "Tnc", "types": { "StarkNetDomain": [ { "name": "name", "type": "felt" }, { "name": "version", "type": "felt" }, { "name": "chainId", "type": "felt" } ], "Tnc": [ { "name": "message", "type": "felt" }, { "name": "document", "type": "felt" } ] } } let result = okxStarknetProvider.signMessage(address, signData ,chain) //Return Value:0x07fcd65fded07c7daaa79a818a39c5236562914a5d48fa7fad268fac609faa9a,0x0324c3bafc4d0e7e04a3a0b805bf8438f5111e308c4d596daa46fc213b37ebf1 ``` ## SendTransaction ``` okxStarknetProvider.sendTransaction(signerAddress, transaction, chainId?) ``` ***Request Parameters*** - signerAddress - string,wallet address - transaction - object, the transaction information to be signed in a fixed format - chainId? - string, the chain for which the signature is requested. ***Return Value*** - Promise - string, transaction hash ***Example*** ```ts let val = uint256.bnToUint256(120000000000000000) const transferCalldata = CallData.compile({ to: "0x00b909cefa36ab6bc26f5887a867e46ef162238f0a171b1c2974b665afd4237f", value: val }) const DAITokenAddress = "0x00da114221cb83fa859dbdb4c44beeaa0bb37c7537ad5ae66fe5e0efd20e6eb3" const invokeParams = { calls: [ { contract_address: DAITokenAddress, entry_point: "transfer", calldata: transferCalldata } ], } let okxStarknetProvider = new OKXStarknetProvider(window.provider) let address = okxStarknetProvider.getAccount("starknet:mainnet").address let res = await provider.sendTransaction( this.address, invokeParams, "starknet:mainnet") //Return Value:0x515d9de049c43477cee7eaea987ab04995d8dc2a7b3d7a184dca4bcd7224ec2 ``` ## Disconnect wallet Disconnect the connected wallet and delete the current session, if you want to switch wallets, please disconnect the current wallet and reconnect it first. ```typescript okxUniversalProvider.disconnect() ``` ## Event ```typescript // Generate universalLink okxUniversalProvider.on('display_uri', (uri) => { console.log(uri); }); // Session information changes will trigger this event; okxUniversalProvider.on('session_update', (session) => { console.log(JSON.stringify(session)); // Session information changes (e.g., adding a custom chain). }); // Disconnecting triggers this event; okxUniversalProvider.on('session_delete', ({topic}) => { console.log(topic); }); ``` ## Error codes Exceptions that may be thrown during connection, transaction, and disconnection. **Exception** | Error Code | Description | |----------------------------------------------|-------------------------| | OKX_CONNECT_ERROR_CODES.UNKNOWN_ERROR | Unknown Error | | OKX_CONNECT_ERROR_CODES.ALREADY_CONNECTED_ERROR | Wallet Already Connected | | OKX_CONNECT_ERROR_CODES.NOT_CONNECTED_ERROR | Wallet Not Connected | | OKX_CONNECT_ERROR_CODES.USER_REJECTS_ERROR | User Rejected | | OKX_CONNECT_ERROR_CODES.METHOD_NOT_SUPPORTED | Method Not Supported | | OKX_CONNECT_ERROR_CODES.CHAIN_NOT_SUPPORTED | Chain Not Supported | | OKX_CONNECT_ERROR_CODES.WALLET_NOT_SUPPORTED | Wallet Not Supported | | OKX_CONNECT_ERROR_CODES.CONNECTION_ERROR | Connection Error | ```typescript export enum OKX_CONNECT_ERROR_CODES { UNKNOWN_ERROR = 0, ALREADY_CONNECTED_ERROR = 11, NOT_CONNECTED_ERROR = 12, USER_REJECTS_ERROR = 300, METHOD_NOT_SUPPORTED = 400, CHAIN_NOT_SUPPORTED = 500, WALLET_NOT_SUPPORTED = 600, CONNECTION_ERROR = 700 } ``` - [UI](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-starknet-ui.md) # UI ## Installation and Initialization Make sure to update the OKX App to version 6.98.0 or later to start integrating OKX Connect into your DApp can be done using npm: ``` npm install @okxconnect/ui npm install @okxconnect/universal-provider ``` Before connecting to a wallet, you need to create an object that can provide a UI interface for subsequent operations such as connecting to the wallet and sending transactions. ``` OKXUniversalConnectUI.init(dappMetaData, actionsConfiguration, uiPreferences, language) ``` **Request Parameterseters** - dappMetaData - object - name - string: The name of the application, will not be used as a unique representation. - icon - string: URL of the application icon, must be in PNG, ICO, etc. SVG icons are not supported. SVG icons are not supported. It is best to pass a url pointing to a 180x180px PNG icon. - actionsConfiguration - object - modals - ('before' | 'success' | 'error')[] | 'all' The modes of displaying alerts during transaction, defaults to 'before'. - returnStrategy -string 'none' | `${string}://${string}`; for app wallet, specify the return strategy for the deep link when the user signs/rejects the request, if it is in tg, you can configure tg://resolve - uiPreferences -object - theme - Theme can be: THEME.DARK, THEME.LIGHT, 'SYSTEM'. - language - 'en_US' | 'ru_RU' | 'zh_CN' | 'ar_AE' | 'cs_CZ' | 'de_DE' | 'es_ES' | 'es_LAT' | 'fr_FR' | 'id_ID' | 'it_IT' | 'nl_NL' | 'pl_PL' | 'pt_BR' | 'pt_PT' | 'ro_RO' | 'tr_TR' | 'uk_UA' | 'vi_VN'. , defaults to en_US **Return value** - OKXUniversalConnectUI **Examples** ```typescript import { OKXUniversalConnectUI } from "@okxconnect/ui"; const okxUniversalConnectUI = await OKXUniversalConnectUI.init({ dappMetaData: { icon: "https://static.okx.com/cdn/assets/imgs/247/58E63FEA47A2B7D7.png", name: "OKX Connect Demo" }, actionsConfiguration: { returnStrategy: 'tg://resolve', modals:"all", tmaReturnUrl:'back' }, language: "en_US", uiPreferences: { theme: THEME.LIGHT }, }); ``` ## Connecting to a wallet Connect to the wallet to get the wallet address as an identifier and the necessary parameters for signing transactions. ``` okxUniversalConnectUI.connect(connectParams: ConnectParams) ``` **Request Parameters** - connectParams - ConnectParams - namespaces - [namespace: string]: ConnectNamespace ; Optional information for the requested connection, the key for the starknet family is 'starknet', currently only starknet:mainnet is supported, if any of the requested chains is not supported by the chain wallet, the wallet will If any of the requested chains is not supported by any of the chain wallets, the wallet will reject the connection; - chains: string[]; chain id information - defaultChain?: string; default chain - optionalNamespaces - [namespace: string]: ConnectNamespace; optional information of the requested connection, the key of the starknet system is 'starknet', currently only starknet:mainnet is supported, if the requested chain is not supported by the current wallet, it can still be connected. If the requested chain is not supported by the current wallet, it can still be connected; - chains: string[]; chain id information - defaultChain?: string; default chain - sessionConfig: object - redirect: string Jump parameter after successful connection, if it is a Mini App in Telegram, here can be set to Telegram's deeplink: 'tg://resolve' **Return value** - Promise`` - topic: string; Session Logo; - namespaces: `Record`; The namespace information for a successful connection; - chains: string[]; Information about the connected chains - accounts: string[]; information about the connected accounts - methods: string[]; Methods supported by the wallet under the current namespace - defaultChain?: string; the default chain for the current session - sessionConfig?: SessionConfig - dappInfo: object DApp information - name:string - icon:string - redirect?:string, the redirect parameter after successful connection **Examples** ```typescript var session = await okxUniversalConnectUI.connect({ namespaces: { starknet: { chains: [ "starknet:mainnet" ], } }, sessionConfig: { redirect: "tg://resolve" } }) ``` ## Prepare the transaction First create an OKXStarknetProvider object and pass OKXUniversalProvider into the constructor. ```typescript import { OKXStarknetProvider } from "@okxconnect/universal-provider"; let okxStarknetProvider = new OKXStarknetProvider(okxUniversalProvider) ``` ## Get account information ``` okxStarknetProvider.getAccount(chainId) ``` ***Request Parameterseters*** - chainId: the requested chain, e.g. starknet:mainnet ***Return value*** - Object - address: string wallet address, - pubKey: string public key ***Example*** ```typescript let result = okxStarknetProvider.getAccount("starknet:mainnet") // Return structure { address: "0x0667ae9b1c3d3ab1dacffd8b23269e9fedf2f8de5c57a35fe0a55f209db59179", pubKey: "07c26f0fd90a6847d3de5ce7002dcd9454b45a78d5592ee369c4d7561fa5e5ee" } ``` ## Sign the message ``` okxStarknetProvider.signMessage(signerAddress, typedData, chain) ``` ***Request Parameterseters*** - signerAddress - string, wallet address - typedData - object The message to be signed, in a fixed format. - chain? - string, chain of requested execution methods ***Return value*** - Promise - [string, string] Signature result r, v ***Example*** ```ts let chain = "starknet:mainnet" let address = okxStarknetProvider.getAccount("starknet:mainnet").address const signData = { "domain": { "chainId": "0x534e5f4d41494e", "name": "STRKFarm", "version": "1" }, "message": { "document": "app.strkfarm.xyz/tnc/v1", "message": "Read and Agree T&C" }, "primaryType": "Tnc", "types": { "StarkNetDomain": [ { "name": "name", "type": "felt" }, { "name": "version", "type": "felt" }, { "name": "chainId", "type": "felt" } ], "Tnc": [ { "name": "message", "type": "felt" }, { "name": "document", "type": "felt" } ] } } let result = okxStarknetProvider.signMessage(address, signData,chain) //返回:0x07fcd65fded07c7daaa79a818a39c5236562914a5d48fa7fad268fac609faa9a,0x0324c3bafc4d0e7e04a3a0b805bf8438f5111e308c4d596daa46fc213b37ebf1 ``` ## SendTransaction ``` okxStarknetProvider.sendTransaction(signerAddress, transaction, chainId?) ``` ***Request Parameters*** - signerAddress - string,wallet address - transaction - object, the transaction information to be signed in a fixed format - chainId? - string, the chain for which the signature is requested. ***Return Value*** - Promise - string, transaction hash ***Example*** ```ts let val = uint256.bnToUint256(120000000000000000) const transferCalldata = CallData.compile({ to: "0x00b909cefa36ab6bc26f5887a867e46ef162238f0a171b1c2974b665afd4237f", value: val }) const DAITokenAddress = "0x00da114221cb83fa859dbdb4c44beeaa0bb37c7537ad5ae66fe5e0efd20e6eb3" const invokeParams = { calls: [ { contract_address: DAITokenAddress, entry_point: "transfer", calldata: transferCalldata } ], } let okxStarknetProvider = new OKXStarknetProvider(window.provider) let address = okxStarknetProvider.getAccount("starknet:mainnet").address let res = await provider.sendTransaction( this.address, invokeParams, "starknet:mainnet") //Return Value:0x515d9de049c43477cee7eaea987ab04995d8dc2a7b3d7a184dca4bcd7224ec2 ``` ## Disconnect wallet Disconnect the connected wallet and delete the current session. If you want to switch the connected wallet, please disconnect the current wallet first. ```typescript okxUniversalProvider.disconnect() ``` ## Event ```typescript // Generate universalLink universalUi.on("display_uri", (uri) => { console.log(uri); }); // Session information changes will trigger this event; universalUi.on("session_update", (session) => { console.log(JSON.stringify(session)); }); // Disconnecting triggers this event; universalUi.on("session_delete", ({topic}) => { console.log(topic); }); // This event is triggered when a connection is made and the signature is signed. universalUi.on("connect_signResponse", (signResponse) => { console.log(signResponse); }); ``` ## Error codes Exceptions that may be thrown during connection, transaction, and disconnection. **Exception** | Error Code | Description | |----------------------------------------------|-------------------------| | OKX_CONNECT_ERROR_CODES.UNKNOWN_ERROR | Unknown Error | | OKX_CONNECT_ERROR_CODES.ALREADY_CONNECTED_ERROR | Wallet Already Connected | | OKX_CONNECT_ERROR_CODES.NOT_CONNECTED_ERROR | Wallet Not Connected | | OKX_CONNECT_ERROR_CODES.USER_REJECTS_ERROR | User Rejected | | OKX_CONNECT_ERROR_CODES.METHOD_NOT_SUPPORTED | Method Not Supported | | OKX_CONNECT_ERROR_CODES.CHAIN_NOT_SUPPORTED | Chain Not Supported | | OKX_CONNECT_ERROR_CODES.WALLET_NOT_SUPPORTED | Wallet Not Supported | | OKX_CONNECT_ERROR_CODES.CONNECTION_ERROR | Connection Error | ```typescript export enum OKX_CONNECT_ERROR_CODES { UNKNOWN_ERROR = 0, ALREADY_CONNECTED_ERROR = 11, NOT_CONNECTED_ERROR = 12, USER_REJECTS_ERROR = 300, METHOD_NOT_SUPPORTED = 400, CHAIN_NOT_SUPPORTED = 500, WALLET_NOT_SUPPORTED = 600, CONNECTION_ERROR = 700 } ``` - [Troubleshooting](https://web3.okx.com/onchainos/dev-docs/sdks/app-connect-faq.md) # Troubleshooting ### Using SDK access to jump apps on iOS may fail On iOS, the system restricts the asynchronous operation before calling the deeplink, and the jump must be triggered directly by the user's click behaviour, otherwise the corresponding deeplink may not be opened. Otherwise, the corresponding deeplink may not be opened. if you must use SDK instead of UI, in case you can't avoid the asynchronous operation, you can try to open a popup window first. The user clicks the button in the popup to trigger the request method again. ### Sending connection and signature messages at the same time, without opening the signature panel In non-TON chain, connection and signature are currently 2 messages, if the signature message occurs after opening the app, the web page may fail to send. Best practice is to connect to the wallet first. Connect successfully and then click the button to generate the signature request. Each time you need to wake up the app, it should be triggered by a separate user action. - [Preparation](https://web3.okx.com/onchainos/dev-docs/sdks/web-detect-okx-wallet.md) # Preparation If you haven't downloaded the OKX Plugin Wallet yet, please go to the download page: - [Chrome Plugin](https://chromewebstore.google.com/detail/%E6%AC%A7%E6%98%93-web3-%E9%92%B1%E5%8C%85/mcohilncbfahbmgdjkbpemcciiolgcge) - [Brave Plugin](https://chromewebstore.google.com/detail/%E6%AC%A7%E6%98%93-web3-%E9%92%B1%E5%8C%85/mcohilncbfahbmgdjkbpemcciiolgcge) - [Edge Plugin](https://microsoftedge.microsoft.com/addons/detail/%E6%AC%A7%E6%98%93-web3-%E9%92%B1%E5%8C%85/pbpjkcldjiffchgbbndmhojiacbgflha) - [Safari Plugin](https://apps.apple.com/app/okx-wallet/id6463797825) If you have already downloaded the plugin wallet, check if the plugin wallet is running normally in your browser by copying the following code into the browser's developer console: ```javascript if (typeof window.okxwallet !== 'undefined') { console.log('OKX is installed!'); } ``` - [EVM Compatible Chains](https://web3.okx.com/onchainos/dev-docs/sdks/chains/evm/introduce.md) # EVM Compatible Chains EVM compatible chains refer to blockchain networks that use Ethereum Virtual Machine (EVM) technology. These chains share the same smart contract execution environment as Ethereum, allowing developers to easily deploy Ethereum-based applications to these networks. This compatibility enables developers to use existing Ethereum tools and libraries, such as Solidity, Web3.js, and Truffle, to build and deploy decentralized applications (DApps). Common EVM compatible chains include Polygon, Avalanche, and Fantom. The emergence of these networks enriches the blockchain ecosystem, providing users with more options while also promoting cross-chain interoperability. - [Obtain wallet address](https://web3.okx.com/onchainos/dev-docs/sdks/chains/evm/web-access-user-accounts.md) # Obtain wallet address Wallet addresses are used in various scenarios, including as identifiers and for signing transactions. For example, in Ethereum, an Ethereum address is the unique public identifier of an account. Each account has a corresponding address, which is used for interactions and identification on the network. The account contains all state information and functions associated with that address. If a DApp wants to request a user's signature or have the user approve a transaction, it must use the `eth_requestAccounts` RPC method to access the user's account. ## Creating a Connection It is recommended to provide a button here that allows users to connect the OKX Web3 wallet to the DApp. Clicking this button will call the `eth_requestAccounts` method to access the user's account address. In the example project code below, the JavaScript code accesses the user's account address when the user clicks the connect button, and the HTML code displays the button and the current account address: ```html ``` ```javascript const connectEthereumButton = document.querySelector('.connectEthereumButton'); connectEthereumButton.addEventListener('click', () => { //Will Start the OKX extension okxwallet.request({ method: 'eth_requestAccounts' }); }); ``` ## Detect Account Address Changes You can also listen to the emitted events to get updates: ```typescript okxwallet.on('accountsChanged', handler: (accounts: Array) => void); ``` Whenever the return value of the eth_accounts RPC method changes, OKX will emit a corresponding event notification. eth_accounts will return an array that is either empty or contains a single account address. If an account address is present, it is the most recently used account address accessible to the caller. Since callers are identified by their URL origin, sites with the same origin will hold the same permissions. The accountsChanged event is emitted whenever the publicly available account address changes. ## Obtaining Account Addresses for More Chains Check out [injected providers](./provider) for account monitoring on other blockchains. - [Obtain chainId](https://web3.okx.com/onchainos/dev-docs/sdks/chains/evm/web-detect-user-network.md) # Obtain chainId For Ethereum chain development, it's important to keep track of a user's network chain ID, as all RPC requests are submitted to the currently connected network. Use the `eth_chainId` RPC method to detect the chain ID of a user's current network. Listen to the `chainChanged` provider event to detect when the user changes networks. As an example, the following code is used to detect a user's network and when the user changes networks: ```javascript const chainId = await window.ethereum.request({ method: 'eth_chainId' }); window.ethereum.on('chainChanged', handleChainChanged); function handleChainChanged(chainId) { // We recommend reloading the page, unless you must do otherwise. window.location.reload(); } ``` ### Chain IDs These are the IDs of the Ethereum chains that OKX Wallet supports by default. Consult [chainid.network](https://chainid.network) for more. | Hex | Decimal | Network | | ---- | ------- | ------------------------------- | | 0x1 | 1 | Ethereum Main Network (Mainnet) | | 0x2711 | 10001 | ETHW | | 0x38 | 56 | Binance Smart Chain Mainnet | | 0x89 | 137 | Matic Mainnet | | 0xa86a | 43114 | Avax Mainnet | | 0xfa | 250 | Fantom Mainnet | | 0xa4b1 | 42161 | Arbitrum Mainnet | | 0xa | 10 | Optimism Mainnet | | 0x19 | 25 | Cronos Mainnet | | 0x2019 | 8217 | Klaytn Mainnet | | 0x141 | 321 | KCC Mainnet | | 0x440 | 1088 | Metis Mainnet | | 0x120 | 288 | Boba Mainnet | | 0x64 | 100 | Gnosis Mainnet | | 0x505 | 1285 | Moonriver Mainnet | | 0x504 | 1284 | Moonbeam Mainnet | | 0x406 | 1030 | Conflux eSpace | - [Display tokens](https://web3.okx.com/onchainos/dev-docs/sdks/chains/evm/web-display-tokens.md) # Display tokens When users open OKX Wallet, they're shown a variety of assets, including tokens. By default, OKX Wallet detects mainstream tokens and displays them. However, for most tokens, users will need to add the tokens themselves. While this is possible using our UI with the `Add Token` button, it can be cumbersome, and more prone to error since it involves the process of users interacting with contract addresses. It can greatly improve security and user experience for adding tokens to OKX Wallet by taking advantage of the `wallet_watchAsset` API as defined in [EIP-747](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-747.md). ### Example If you'd like to integrate token suggestions into your own web app, you can follow this code snippet: ```javascript const tokenAddress = '0xd00981105e61274c8a5cd5a88fe7e037d935b513'; const tokenSymbol = 'TUT'; const tokenDecimals = 18; const tokenImage = 'http://placekitten.com/200/300'; try { // wasAdded is a boolean. Like any RPC method, an error may be thrown. const wasAdded = await okxwallet.request({ method: 'wallet_watchAsset', params: { type: 'ERC20', // Initially only supports ERC20, but eventually more! options: { address: tokenAddress, // The address that the token is at. symbol: tokenSymbol, // A ticker symbol or shorthand, up to 5 chars. decimals: tokenDecimals, // The number of decimals in the token image: tokenImage, // A string url of the token logo }, }, }); if (wasAdded) { console.log('Thanks for your interest!'); } else { console.log('Your loss!'); } } catch (error) { console.log(error); } ``` Here are a couple live web applications that let you enter token details, and then share them with a simple web link: - [Watch Token](https://vittominacori.github.io/watch-token/create/) - [Send transactions](https://web3.okx.com/onchainos/dev-docs/sdks/chains/evm/web-send-transaction.md) # Send transactions `eth_sendTransaction` ## Description Transactions are formal actions on a blockchain. They're always initiated in OKX Wallet by calling `eth_sendTransaction` method. They include simply sending Ether, sending tokens, creating new smart contract, or changing the state of on the blockchain in any way. They're always initiated by a signature from an external account, or a simple key pair. In the OKX Web3 Wallet, you can use the `okxwallet.request` method to initiate a transaction. ## Parameters This section mainly introduces the transaction parameters covered in this document. Most of the transaction parameters mentioned here will be handled by the OKX Web3 Wallet. Transactions are categorized into legacy transactions and EIP-1559 transactions, which will be discussed in order. ### Legacy Transactions ```javascript const transactionParameters = { gasPrice: '0x09184e72a000', // customizable by user during OKX confirmation. gas: '0x2710', // customizable by user during OKX confirmation. to: '0x0000000000000000000000000000000000000000', // Required except during contract publications. from: okxwallet.selectedAddress, // must match user's active address. value: '0x00', // Only required to send ether to the recipient from the initiating external account. data: '0x7f7465737432000000000000000000000000000000000000000000000000000000600057', // Optional, but used for defining smart contract creation and interaction. chainId: '0x3', // Used to prevent transaction reuse across blockchains. Auto-filled by OKX. }; ``` **Gas price [optional]** Optional parameter - best used on private blockchains In Ethereum, every transaction specifies a price for the gas it'll consume. To maximize their profit, block producers will pick pending transactions with higher gas prices first when creating the next block. This means that a high gas price will usually cause your transaction to be processed faster at the cost of higher transaction fees. Note that this may not be true for Layer 2 networks which may have a fixed gas price or no gas price at all. In other words, while you can ignore this parameter on OKX Wallet's default networks, you may want to include it in situations where your application knows more about the target network than we do. On our default networks, OKX Wallet allows you to choose between "slow," "medium," and "fast" options for your gas price. **Gas Limit [optional]** Optional parameter. Rarely useful to DApp developers. Gas limit is a highly optional parameter, and we automatically calculate a reasonable price for it. You'll probably know if, for some reason, your smart contract benefits from a custom gas limit. **To [optional]** A hex-encoded Ethereum address. Required for transactions with a recipient (all transactions except for contract creation). Contract creation occurs when there's no `to` value but there's a `data` value. **Value [optional]** Hex-encoded value of the network's native currency to be sent. On the main Ethereum network, that currency is Ether, denominated in Wei which is 1e-18 Ether. Note that these numbers frequently used in Ethereum are far more precise than native JavaScript numbers, and can cause unpredictable behaviors if they're not anticipated. For this reason, we highly recommend using BN.js when manipulating values intended for blockchain. Hex-encoded value of the network's native currency to send. On the Main Ethereum network, this is [ether](https://www.ethereum.org/eth), which is denominated in _wei_, which is `1e-18` ether. Please note that these numbers often used in Ethereum are far higher precision than native JavaScript numbers, and can cause unpredictable behavior if not anticipated. For this reason, we highly recommend using [BN.js](https://github.com/indutny/bn.js/) when manipulating values intended for the blockchain. **Data [optional]** Required for smart contract creation. This field is also used for specifying contract methods and their parameters. You can learn more about how that data is encoded on [the solidity ABI spec](https://solidity.readthedocs.io/en/develop/abi-spec.html). **Chain ID [currently ignored]** Chain ID is currently derived from the user's selected network at `okxwallet.networkVersion`. **Return value** DATA, 32 bytes - transaction hash. If the transaction is not available yet, it is a zero hash. When you create a contract, after the transaction is mined, use [eth_getTransactionReceipt](https://ethereum.org/zh/developers/docs/apis/json-rpc/#eth_gettransactionreceipt) to get the contract address. ### EIP-1559 Transactions ```javascript const transactionParameters = { maxPriorityFeePerGas: "0x0", // Maximum fee, in wei, the sender is willing to pay per gas above the base fee. maxFeePerGas: "0x6f4d3132b", // Maximum total fee (base fee + priority fee), in wei, the sender is willing to pay per gas. gas: '0x2710', // customizable by user during OKX confirmation. to: '0x0000000000000000000000000000000000000000', // Required except during contract publications. from: okxwallet.selectedAddress, // must match user's active address. value: '0x00', // Only required to send ether to the recipient from the initiating external account. data: '0x7f7465737432000000000000000000000000000000000000000000000000000000600057', // Optional, but used for defining smart contract creation and interaction. chainId: '0x3', // Used to prevent transaction reuse across blockchains. Auto-filled by OKX. }; ``` For [EIP-1559](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md) transactions, the key difference from legacy transactions is the use of `maxPriorityFeePerGas` and `maxFeePerGas` instead of `gasPrice` . **maxPriorityFeePerGas [Optional]** The additional tip the user is willing to pay to the miner/validator for prioritizing the transaction. **maxFeePerGas [Optional]** The maximum total amount the user is willing to pay per unit of gas, including both the base fee and the priority fee. ## Example Open in [codeopen](https://codepen.io/okxwallet/pen/VwGeGQb). ```html ``` ```javascript const ethereumButton = document.querySelector('.connectEthereumButton'); const signTransactionButton = document.querySelector('.signTransactionButton'); let accounts = []; signTransactionButton.addEventListener('click', () => { okxwallet .request({ method: 'eth_sendTransaction', params: [ { from: accounts[0], to: '0x2f318C334780961FB129D2a6c30D0763d9a5C970', value: '0x29a2241af62c0000', gasPrice: '0x09184e72a000', gas: '0x2710', }, ], }) .then((txHash) => console.log(txHash)) .catch((error) => console.error); }); ethereumButton.addEventListener('click', () => { getAccount(); }); async function getAccount() { try{ accounts = await okxwallet.request({ method: 'eth_requestAccounts' }); }catch(error){ console.log(error); } } ``` - [Interact with smart contracts](https://web3.okx.com/onchainos/dev-docs/sdks/chains/evm/web-interact-with-smart-contracts.md) # Interact with smart contracts To interact with a smart contract, your DApp needs the contract's: - [Network](#Contract-network) - [Address](#Contract-address) - [ABI](#Contract-ABI) - [Bytecode](#Contract-bytecode) - [Source code](#Contract-source-code) ## Contract network If you're not connected to the right network, you can't send transactions to your contract. Many DApp developers deploy their contracts to a testnet first, in order to avoid potentially disastrous fees if something goes wrong during development and testing on Mainnet. Regardless of which network you deploy your final DApp on, your users must be able to access it. Take Ethereum as an example. You can use the [``wallet_addEthereumChain``](https://ethereum-magicians.org/t/eip-3085-wallet-addethereumchain/5469) and [``wallet_switchEthereumChain``](./web-add-network) RPC methods to prompt the user to add a chain that you suggest, and switch to it using a confirmation dialogue. ## Contract address Every account has an address, whether an external key-pair account or a smart contract. For any smart contract library to communicate with your contracts, a smart contract must know the exact address. ## Contract ABI Take Ethereum as an example, the [ABI specification](https://solidity.readthedocs.io/en/develop/abi-spec.html) is a way to encode the interface of a smart contract that's comprehensible to your user interface. The ABI is an array of method-describing objects, and when you feed this and the address into a contract-abstraction library, the ABI tells those libraries about what methods to provide, and how to compose transactions to call those methods. Example libraries include: - [Ethers](https://www.npmjs.com/package/ethers) - [web3.js](https://www.npmjs.com/package/web3) - [Embark](https://github.com/embarklabs) - [ethjs](https://www.npmjs.com/package/ethjs) - [Truffle](https://trufflesuite.com/). ## Contract bytecode If your DApp publishes a new pre-compiled smart contract, it might need to include some bytecode. You don't know the contract address in advance; you must publish the contract, watch for the transaction to be processed, and then extract the final contract's address from the completed transaction. If you publish a contract from bytecode, you still need an [ABI](#Contract-ABI) to interact with it. The bytecode doesn't describe how to interact with the final contract. ## Contract source code If your DApp allows users to edit smart contract source code and compile it, similar to Remix, you can import a whole compiler. You derive your bytecode and ABI from that source code, and eventually derive the contract's address from the completed transaction, where that bytecode is published. - [Switch network](https://web3.okx.com/onchainos/dev-docs/sdks/chains/evm/web-add-network.md) # Switch network ### Chain switch `wallet_switchEthereumChain` This method is detailed in [EIP-3326](https://ethereum-magicians.org/t/eip-3326-wallet-switchethereumchain). **Description** This request asks the user if they are switching to a chain with a specified `chainId` and returns a value of confirmation. As with any method that returns a confirmation, `wallet_switchEthereumChain` should **only** be called in response to a direct user action, such as a button click. OKX will automatically reject the request under the following circumstances: - If the chain ID is incorrectly formatted; - If the chain with the specified chain ID has not been added to OKX. We recommend that you use [` wallet_addEthereumChain `](https://ethereum-magicians.org/t/eip-3085-wallet-addethereumchain/5469) together with it. ```javascript try { await okxwallet.request({ method: 'wallet_switchEthereumChain', params: [{ chainId: '0xf00' }], }); } catch (switchError) { // This error code indicates that the chain has not been added to OKX. if (switchError.code === 4902) { try { await okxwallet.request({ method: 'wallet_addEthereumChain', params: [ { chainId: '0xf00', chainName: '...', rpcUrls: ['https://...'] /* ... */, }, ], }); } catch (addError) { // handle "add" error } } // handle other "switch" errors } ``` **Parameters** - `Array` 0. `SwitchEthereumChainParameter` - The metadata of the chain that OKX will switch to. ```typescript interface SwitchEthereumChainParameter { chainId: string; // A 0x-prefixed hexadecimal string } ``` **Chain IDs** These are the IDs of the Ethereum chains that OKX Wallet supports by default. Consult [chainid.network](https://chainid.network) for more. | Hex | Decimal | Network | | ---- | ------- | ------------------------------- | | 0x1 | 1 | Ethereum Main Network (Mainnet) | | 0x2711 | 10001 | ETHW | | 0x42 | 66 | OKT Chain Mainnet | | 0x38 | 56 | Binance Smart Chain Mainnet | | 0x89 | 137 | Matic Mainnet | | 0xa86a | 43114 | Avax Mainnet | | 0xfa | 250 | Fantom Mainnet | | 0xa4b1 | 42161 | Arbitrum Mainnet | | 0xa | 10 | Optimism Mainnet | | 0x19 | 25 | Cronos Mainnet | | 0x2019 | 8217 | Klaytn Mainnet | | 0x141 | 321 | KCC Mainnet | | 0x440 | 1088 | Metis Mainnet | | 0x120 | 288 | Boba Mainnet | | 0x64 | 100 | Gnosis Mainnet | | 0x505 | 1285 | Moonriver Mainnet | | 0x504 | 1284 | Moonbeam Mainnet | | 0x406 | 1030 | Conflux eSpace | **Return value** `null` - The method returns `null` if the request was successful; otherwise, it will return an error. If the error code (`error.code`) is `4902`, then the requested chain has not been added by OKX, and you have to request to add it via `wallet_addEthereumChain`. **Example** Open in [codeopen](https://codepen.io/okxwallet/pen/yLxeRON). ```html ``` ```javascript const connectEthereumButton = document.querySelector('.connectEthereumButton'); const switchChainButton = document.querySelector('.switchChainButton'); let accounts = []; //Sending Ethereum to an address switchChainButton.addEventListener('click', () => { try { const chainId = okxwallet.chainId === "0x42" ? "0x38" : "0x42"; await okxwallet.request({ method: "wallet_switchEthereumChain", params: [{ chainId: chainId }] }); } catch (switchError) { // This error code indicates that the chain has not been added to OKX Wallet. if (error.code === 4902) { try { await okxwallet.request({ method: "wallet_addEthereumChain", params: [{ chainId: "0xf00", rpcUrl: "https://..." /* ... */ }] }); } catch (addError) { // handle "add" error } } // handle other "switch" errors } }); connectEthereumButton.addEventListener('click', () => { getAccount(); }); async function getAccount() { try{ accounts = await okxwallet.request({ method: 'eth_requestAccounts' }); }catch(error){ console.log(error); } } ``` - [Provider API](https://web3.okx.com/onchainos/dev-docs/sdks/chains/evm/provider.md) # Provider API ## What is injected provider API? The OKX injected provider API is a JavaScript API that OKX injects into websites visited by our users. Your DApp can use this API to request users' accounts, read data from blockchains users are connected to, and help users sign messages and transactions. ## Connecting to your wallet `eth_requestAccounts` This method is detailed in [EIP-1102](https://eips.ethereum.org/EIPS/eip-1102). Under the hood, it calls [`wallet_requestPermissions`](#wallet-requestpermissions) to gain the `eth_accounts` permission. Since `eth_accounts` is currently the only permission, this method is all you need for now. **Description** This request asks the target user to provide an Ethereum address to be identified by. The return value would be a Promise which could be parsed as an array of a single Ethereum address string. If the user denies the request, the Promise will be rejected, returning `4001` error. The request will cause an OKX popup to appear. You should only request the user's account in response to a direct user action, such as a button click. You should always disable the button that dispatches this request while the previous request is still pending. If you can't retrieve the user's account(s), you should encourage the user to initiate an account request. **Return value** `string[]` - An array of a single, hexadecimal Ethereum address string. **Example** Open in [codeopen](https://codepen.io/okxwallet/pen/WNgrgLP). ```html ``` ```javascript const connectEthereumButton = document.querySelector('.connectEthereumButton'); connectEthereumButton.addEventListener('click', () => { //Will Start the OKX extension okxwallet.request({ method: 'eth_requestAccounts' }); }); ``` ## Adding token **Note**: This function is only supported on the OKX browser extension. ## `wallet_watchAsset` This method is specified in [EIP-747](https://eips.ethereum.org/EIPS/eip-747). **Description** This requests the user to track a token in OKX Wallet. It'll return a `boolean` indicating if the token was successfully added. Most Ethereum wallets support a certain set of tokens, which usually comes from a centrally curated registry of tokens. `wallet_watchAsset` enables Web3 application developers to ask their users to track tokens in their wallets at runtime. Once added, the token is indistinguishable from those added via legacy methods, such as a centralized registry. **Parameters** - `WatchAssetParams` - The metadata of the asset to watch. ```typescript interface WatchAssetParams { type: 'ERC20'; // In the future, other standards will be supported options: { address: string; // The address of the token contract 'symbol': string; // A ticker symbol or shorthand, up to 11 characters decimals: number; // The number of token decimals image: string; // A string url of the token logo }; } ``` **Return value** `boolean` - `true` if the token was added, otherwise, `false`. **Example** Open in [codeopen](https://codepen.io/okxwallet/pen/NWLxegB). ```html ``` ```javascript const ethereumButton = document.querySelector('.connectEthereumButton'); const addTokenButton = document.querySelector('.addTokenButton'); addTokenButton.addEventListener('click', async () => { await okxwallet.request({ method: 'wallet_switchEthereumChain', params: [{ chainId: '0x1' }] }); okxwallet .request({ method: 'wallet_watchAsset', params: { type: 'ERC20', options: { address: '0xdac17f958d2ee523a2206206994597c13d831ec7', symbol: 'USDT', decimals: 6, image: 'https://foo.io/token-image.svg', }, }, }) .then((success) => { if (success) { console.log('USDT successfully added to wallet!'); } else { throw new Error('Something went wrong.'); } }) .catch(console.error); }); ethereumButton.addEventListener('click', () => { getAccount(); }); function getAccount() { okxwallet.request({ method: 'eth_requestAccounts' }).catch((error)=>{ console.log(error); }); } ``` ## EIP-5792 Support The wallet supports batch sending multiple calls and querying transaction results. Defined by the [EIP-5792](https://eips.ethereum.org/EIPS/eip-5792) specification. ### wallet_sendCalls Request the wallet to batch send multiple calls. **Parameters** ```ts type Capability = { [key: string]: unknown; optional?: boolean; } type SendCallsParams = { version: string; id?: string; from?: `0x${string}`; chainId: `0x${string}`; atomicRequired: boolean; calls: { to?: `0x${string}`; data?: `0x${string}`; value?: `0x${string}`; capabilities?: Record; }[]; capabilities?: Record; }; ``` * `version`: Fixed value, "2.0.0" * `id`: Optional, unique identifier for the request. If not provided, the wallet will automatically generate an id * `from`: Optional, the wallet address initiating the request. If not provided, it will be the currently connected wallet * `chainId`: The chain id for initiating the transaction * `atomicRequired`: Whether it must be an atomic transaction. Currently, all transactions sent through OKX are atomic transactions * `calls`: List of batch calls * `to`: The contract address to call * `data`: Transaction data * `value`: Amount of main currency to transfer * `capabilities`: Not currently supported * `capabilities`: Not currently supported **Return Value** ```ts type SendCallsResult = { id: string; capabilities?: Record; }; ``` **Usage Example** ```js window.okxwallet.request({ "method": "wallet_sendCalls", "params": [ { version: "2.0.0", from: "0x819d3f4c17d50004c165d06f22418c4f28010eda", chainId: "0x1", atomicRequired: true, calls: [ { to: "0x54f1C1965B355e1AB9ec3465616136be35bb5Ff7", value: "0x0" }, { to: "0x2D48e6f5Ae053e4E918d2be53570961D880905F2", value: "0x0" } ], } ], }) ``` ### wallet_getCallsStatus Get the status of transactions previously sent via `wallet_sendCalls`. **Parameters** ```ts // Parameters type GetCallsParams = [string]; ``` Query transaction by `id`. **Return Value** ```ts type GetCallsResult = { version: string; id: `0x${string}`; chainId: `0x${string}`; status: number; atomic: boolean; receipts?: { logs: { address: `0x${string}`; data: `0x${string}`; topics: `0x${string}`[]; }[]; status: `0x${string}`; blockHash: `0x${string}`; blockNumber: `0x${string}`; gasUsed: `0x${string}`; transactionHash: `0x${string}`; }[]; capabilities?: Record; }; ``` * `version`: Version of the sent transaction * `id`: Unique identifier * `chainId`: Chain id where the transaction was initiated * `status`: Transaction status, * `100`: Confirming * `200`: Confirmed * `400`: Off-chain failure * `500`: Rejected * `receipts`: Detailed transaction information * `capabilities`: Not currently supported **Usage Example** ```js window.okxwallet.request({ "method": "wallet_getCallsStatus", "params": [ "0x123456" ], }) ``` ### wallet_getCapabilities Returns the wallet's support information for the corresponding atomic functionality. **Parameters** ```ts type GetCapabilitiesParams = [`0x${string}`, [`0x${string}`]]; ``` * The first parameter is the address to query * The second parameter is the list of chains to query **Return Value** ```ts type GetCapabilitiesResult = Record<`0x${string}`, >; ``` If a chain does not support sending batch transactions, it will not appear in the query results. **Usage Example** ```js window.okxwallet.request({ "method": "wallet_getCapabilities", "params": [ "0x00b909cefa36ab6bc26f5887a867e46ef162238f0a171b1c2974b665afd4237f", [ "0x1", "0xaa36a7" ] ], }); // Response example { "0x1": { "atomic": { "status": "supported" } }, "0xaa36a7": { "atomic": { "status": "ready" } } } ``` ## Events OKX's providers have implemented the [Node.js `EventEmitter`](https://nodejs.org/api/events.html) API. This section details the events emitted via that API. There are innumerable `EventEmitter` guides on the internet, but for this documentation, you can listen to events such as: ```javascript okxwallet.on('accountsChanged', (accounts) => { // Handle the new accounts, or lack thereof. // "accounts" will always be an array, but it can be empty. }); okxwallet.on('chainChanged', (chainId) => { // Handle the new chain. // Correctly handling chain changes can be complicated. // We recommend reloading the page unless you have a very good reason not to. window.location.reload(); }); ``` Also, don't forget to remove listeners once you are done listening to them (for example, when unmounting a component in React): ```javascript function handleAccountsChanged(accounts) { // ... } okxwallet.on('accountsChanged', handleAccountsChanged); // Later okxwallet.removeListener('accountsChanged', handleAccountsChanged); ``` The first argument of the `okxwallet.removeListener` is the event name and the second argument is the reference to the same function, which has passed to `okxwallet.on` for the event name mentioned in the first argument. **connect** ```typescript interface ConnectInfo { chainId: string; } okxwallet.on('connect', handler: (connectInfo: ConnectInfo) => void); ``` OKX's providers will emit this event when they can submit RPC requests to the chain for the first time. We recommend using a `connect` event handler and `okxwallet.isConnected()` to confirm if OKX Wallet is connected. **disconnect** ```typescript okxwallet.on('disconnect', handler: (error: ProviderRpcError) => void); ``` OKX's providers will emit this event if they can't submit RPC requests to the chain. Usually, this only occurs in the case of network connection issues or certain other unforeseeable error states. Once `disconnect` has been emitted, the provider won't accept any new requests until the connection to the chain has been re-established, which requires reloading the page. You can also use `okxwallet.isConnected()` to confirm if OKX Wallet is disconnected. **accountsChanged** ```typescript okxwallet.on('accountsChanged', handler: (accounts: Array) => void); ``` OKX's providers will emit this event whenever the return value of the `eth_accounts` RPC changes. `eth_accounts` returns an array that either is empty or contains a single account address. The returned address, if any, is the address of the most recently used account that the caller is permitted to access. Callers are identified by their URL _origin_, which means that all sites with the same origin share the same permissions. This also means that `accountsChanged` will be emitted whenever the user's exposed account address changes. We plan to allow the `eth_accounts` array to be able to contain multiple addresses in the near future. **chainChanged** See the [Chain IDs section](#chain-ids) for OKX's default chains and their chain IDs. OKX's providers will emit this event when the currently connected chain changes. All RPC requests are submitted to the currently connected chain. Therefore, it's critical to keep track of the current chain ID by listening to this event. We _strongly_ recommend reloading the page on chain changes, unless you have good reasons not to. ```javascript okxwallet.on('chainChanged', (_chainId) => window.location.reload()); ``` **message** ```typescript interface ProviderMessage { type: string; data: unknown; } okxwallet.on('message', handler: (message: ProviderMessage) => void); ``` OKX's providers will emit this event when there are messages that users should be notified of. The type of message is identified by the `type` string. RPC subscription updates are a common use case for the `message` event. For example, if you create a subscription using `eth_subscribe`, each subscription update will be emitted as a `message` event with a `type` of `eth_subscription`. **Example** Open in [codeopen](https://codepen.io/okxwallet/pen/jOvqBjR). ```html ``` ```javascript const ethereumButton = document.querySelector(".connectEthereumButton"); const switchChainButton = document.querySelector(".switchChainButton"); window.okxwallet.on("chainChanged", (_chainId) => { console.log(`on chainChanged, current chainId: ${_chainId}`); }); switchChainButton.addEventListener("click", async () => { try { await okxwallet.request({ method: "wallet_switchEthereumChain", params: [{ chainId: okxwallet.chainId === "0x42" ? "0x38" : "0x42" }] }); } catch (error) { // handle other "switch" errors console.log(error); } }); ethereumButton.addEventListener("click", () => { getAccount(); }); async function getAccount() { await okxwallet.request({ method: "eth_requestAccounts" }); } ``` - [Bitcoin-Compatible Chains](https://web3.okx.com/onchainos/dev-docs/sdks/chains/bitcoin/introduce.md) # Bitcoin-Compatible Chains The Bitcoin network is a peer-to-peer electronic cash system that uses blockchain technology to record all transactions without relying on a central authority or intermediary. It is maintained by thousands of nodes around the world, working together to uphold a public distributed ledger. Key features of Bitcoin and similar blockchains (such as Fractal Bitcoin) include a fixed supply, transparent transaction records, anonymity (or pseudonymity), and a tamper-resistant design. These chains typically employ Proof of Work (PoW) or other consensus mechanisms (like Proof of Stake) to ensure the security and consistency of the network. As the first successful cryptocurrency, Bitcoin pioneered a new category of digital assets and laid the foundation for subsequent blockchain projects and decentralized systems. Emerging chains like Fractal Bitcoin build on Bitcoin's foundation, aiming to improve transaction efficiency, scalability, and community governance, advancing the development of the digital currency ecosystem. - [Provider API](https://web3.okx.com/onchainos/dev-docs/sdks/chains/bitcoin/provider.md) # Provider API ## What is injected provider API? The OKX Injected Providers API is based on a JavaScript model and is embedded by OKX into the websites users access. DApps projects can utilize this API to request user account information, retrieve data from the connected blockchain, and assist users in signing messages and transactions. ## connect `okxwallet.bitcoin.connect()` **Description** Connect wallet **Parameters** None **Return value** - Promise - object - address - string: address of current account - publicKey - string: public key of current account **Example** ```typescript const result = await okxwallet.bitcoin.connect() // example { address: 'bc1pwqye6x35g2n6xpwalywhpsvsu39k3l6086cvdgqazlw9mz2meansz9knaq', publicKey: '4a627f388196639041ce226c0229560127ef9a5a39d4885123cd82dc82d8b497' } ``` ## requestAccounts **Description** `okxwallet.bitcoin.requestAccounts()` Connect the current account **Parameters** None **Return value** - Promise - string[]: address of current account **Example** ```typescript try { let accounts = await okxwallet.bitcoin.requestAccounts(); console.log('connect success', accounts); } catch (e) { console.log('connect failed'); } // example ['tb1qrn7tvhdf6wnh790384ahj56u0xaa0kqgautnnz']; ``` ## getAccounts `okxwallet.bitcoin.getAccounts()` **Description** Get the address of current account **Parameters** None **Return value** - Promise - string[]: address of current account **Example** ```typescript try { let res = await okxwallet.bitcoin.getAccounts(); console.log(res); } catch (e) { console.log(e); } // example ['tb1qrn7tvhdf6wnh790384ahj56u0xaa0kqgautnnz']; ``` ## getNetwork - Don't support Testnet. - This field is only available for extension version 2.77.1 or above. `okxwallet.bitcoin.getNetwork()` **Description** Get network **Parameters** None **Return value** - Promise - string: the network **Example** ```typescript try { let res = await okxwallet.bitcoin.getNetwork(); console.log(res); } catch (e) { console.log(e); } // example livenet; ``` ## getPublicKey `okxwallet.bitcoin.getPublicKey()` **Description** Get the public key of current account **Parameters** None **Return value** - Promise - string: public key **Example** ```typescript try { let res = await okxwallet.bitcoin.getPublicKey(); console.log(res) } catch (e) { console.log(e); } // example 03cbaedc26f03fd3ba02fc936f338e980c9e2172c5e23128877ed46827e935296f ``` ## getBalance `okxwallet.bitcoin.getBalance()` **Description** Get BTC balance **Parameters** None **Return value** - Promise - object - confirmed - number: the confirmed satoshis - unconfirmed - number: the unconfirmed satoshis - total - number: the total satoshis **Example** ```typescript try { let res = await okxwallet.bitcoin.getBalance(); console.log(res) } catch (e) { console.log(e); } // example { "confirmed":0, "unconfirmed":100000, "total":100000 } ``` ## getInscriptions `okxwallet.bitcoin.getInscriptions()` **Description** List inscriptions of current account **Parameters** - cursor - number: (optional) offset, starting from 0. The default value is 0. - size - number: (optional) number per page. The default value is 20. **Return value** - Promise - object - total - number: the total count - list - object[]: - inscriptionId - string: the ID of inscription - inscriptionNumber - string: the number of inscription - address - string: the address of inscription - outputValue - string: the output value of inscription - contentLength - string: the content length of inscription - contentType - number: the content type of the inscription - timestamp - number: the block time of the inscription - offset - number: the offset of inscription - output - string: the identification of the utxo where the current inscription is located - genesisTransaction - string: the transaction ID of the genesis transaction - location - string: the txid and vout of current location **Example** ```typescript try { let res = await okxwallet.bitcoin.getInscriptions(0, 20); console.log(res) } catch (e) { console.log(e); } // example { "total":10, "list":[ { inscriptionId: '6037b17df2f48cf87f6b6e6ff89af416f6f21dd3d3bc9f1832fb1ff560037531i0', inscriptionNumber: 55878989, address: 'bc1q8h8s4zd9y0lkrx334aqnj4ykqs220ss735a3gh', outputValue: 546, contentLength: 53, contentType: 'text/plain', timestamp: 1705406294, location: '6037b17df2f48cf87f6b6e6ff89af416f6f21dd3d3bc9f1832fb1ff560037531:0:0', output: '6037b17df2f48cf87f6b6e6ff89af416f6f21dd3d3bc9f1832fb1ff560037531:0', offset: 0, genesisTransaction: '02c9eae52923fdb21fe16ee9eb873c7d66fe412a61b75147451d8a47d089def4' } ] } ``` ## sendBitcoin `okxwallet.bitcoin.sendBitcoin(toAddress, satoshis, options)` **Description** Send BTC **Parameters** - toAddress - string: the address to send - satoshis - number: the satoshis to send - options - object: (optional) - feeRate - number: the network fee rate **Return value** - Promise - string: transaction hash **Example** ```typescript try { let txid = await okxwallet.bitcoin.sendBitcoin( 'tb1qrn7tvhdf6wnh790384ahj56u0xaa0kqgautnnz', 1000 ); console.log(txid); } catch (e) { console.log(e); } ``` ## send `okxwallet.bitcoin.send({ from, to, value, satBytes })` **Description** Send BTC (supports memo parameter) **Parameters** - from - string: the BTC address of the currently connected wallet - to - string: addresses that accept BTC - value - string: amount of BTC sent - satBytes - string (optional): custom rate - memo - string: (optional) specify the content of outputs OP_RETURN. [Example](https://mempool.space/tx/0cd710b0e2f6364bd7c0a4edfe27f592cabe48904c92e4913ee95421e1519320) - memoPos - number: (optional) specify the output position of outputs OP_RETURN. If a memo is provided, the memoPos must be specified, otherwise the memo will not take effect. **Return value** - Promise - object - txhash: transaction hash **Example** ```typescript const result = await window.okxwallet.bitcoin.send({ from: 'bc1p4k9ghlrynzuum080a4zk6e2my8kjzfhptr5747afzrn7xmmdtj6sgrhd0m', to: 'bc1plklsxq4wtv44dv8nm49fj0gh0zm9zxewm6ayzahrxc8yqtennc2s9udmcd', value: '0.000012', }); // example { txhash: 'd153136cd74512b69d24c68b2d2c715c3629e607540c3f6cd3acc1140ca9bf57'; } ``` ## sendInscription `okxwallet.bitcoin.sendInscription(address, inscriptionId, options)` **Description** Send inscription **Parameters** - address - string: the receiver address - inscriptionId - string: Inscriptions ID + protocol, default is Ordinals NFT if no transmission protocol, currently only support Ordinals and Atomicals Association | Protocol | Description | | ---- | -------------------------------------------------------- | | Ordinals | Ordinals Protocol | | Atomicals | Atomicals Protocol | - options - object: (optional) - feeRate - number: the network fee rate **Return value** - Promise - string: transaction hash **Example** ```typescript // send Ordinals NFT try { let txid = await okxwallet.bitcoin.sendInscription( 'tb1q8h8s4zd9y0lkrx334aqnj4ykqs220ss7mjxzny', 'e9b86a063d78cc8a1ed17d291703bcc95bcd521e087ab0c7f1621c9c607def1ai0', { feeRate: 15 } ); console.log( 'send Ordinal NFT to tb1q8h8s4zd9y0lkrx334aqnj4ykqs220ss7mjxzny', { txid } ); } catch (e) { console.log(e); } ``` ```typescript // send Atomicals NFT try { let txid = await okxwallet.bitcoin.sendInscription( 'tb1q8h8s4zd9y0lkrx334aqnj4ykqs220ss7mjxzny', 'ab12349dca49643fcc55c8e6a685ad0481047139c5b1af5af85387973fc7ceafi0-Atomicals', { feeRate: 15 } ); console.log( 'send Atomicals NFT to tb1q8h8s4zd9y0lkrx334aqnj4ykqs220ss7mjxzny', { txid } ); } catch (e) { console.log(e); } ``` ## transferNft `okxwallet.bitcoin.transferNft({ from, to, data })` **Description** Send inscription The `transferNft` method supports batch transfers, while the `sendInscription` method only supports individual transfers **Parameters** - from - string: the BTC address of the currently connected wallet - to - string: addresses that accept NFTs or BRC-20 tokens - data-string | string[]: indicates the sent NFT tokenId + protocol. If the NFT is an array, multiple NFT are transferred in batches. If no transmission protocol is used, the default NFT is Ordinals NFT. Currently, only Ordinals and Atomicals are supported | Protocol | Description | | ---- | -------------------------------------------------------- | | Ordinals | Ordinals Protocol | | Atomicals | Atomicals Protocol | **Return value** - Promise - object - txhash - string: transaction hash **Example** ```typescript // send Ordinals NFT try { let res = await window.okxwallet.bitcoin.transferNft({ from: 'bc1p8qfrmxdlmynr076uu28vlszxavwujwe7dus0r8y9thrnp5lgfh6qu2ctrr', to: 'bc1p8qfrmxdlmynr076uu28vlszxavwujwe7dus0r8y9thrnp5lgfh6qu2ctrr', data: [ '2f285ba4c457c98c35dcb008114b96cee7c957f00a6993690efb231f91ccc2d9i0-Ordinals', '2f2532f59d6e46931bc84e496cc6b45f87966b149b85ed3199265cb845550d58i0-Ordinals', ], }); console.log(res); } catch (e) { console.log(e); } // example { txhash: 'df409c3ce3c4d7d840b681fab8a3a5b8e32b1600636cc5409d84d2c06365a5fc'; } ``` ```typescript // send Atomicals NFT try { let res = await window.okxwallet.bitcoin.transferNft({ from: 'bc1p8qfrmxdlmynr076uu28vlszxavwujwe7dus0r8y9thrnp5lgfh6qu2ctrr', to: 'bc1p8qfrmxdlmynr076uu28vlszxavwujwe7dus0r8y9thrnp5lgfh6qu2ctrr', data: [ 'ab12349dca49643fcc55c8e6a685ad0481047139c5b1af5af85387973fc7ceafi0-Atomicals', ], }); console.log(res); } catch (e) { console.log(e); } // example { txhash: 'df409c3ce3c4d7d840b681fab8a3a5b8e32b1600636cc5409d84d2c06365a5fc'; } ``` ## signMessage `okxwallet.bitcoin.signMessage(signStr[, type])` **Description** Sign message **Parameters** - signStr - string: requires signed data - type - string: (optional) "ecdsa" | "bip322-simple". The default value is "ecdsa". (Note: For app versions below 6.51.0, only “ecdsa” is available. For app versions equal to or above 6.51.0, all parameter types are available.) **Return value** - Promise - string: the signing result **Example** ```typescript const signStr = 'need sign string'; const result = await window.okxwallet.bitcoin.signMessage(signStr, 'ecdsa') // example INg2ZeG8b6GsiYLiWeQQpvmfFHqCt3zC6ocdlN9ZRQLhSFZdGhgYWF8ipar1wqJtYufxzSYiZm5kdlAcnxgZWQU= ``` ## pushTx `okxwallet.bitcoin.pushTx(rawTx)` **Description** Push transaction **Parameters** - rawTx - string: rawtx to push **Return value** - Promise - string: transaction hash **Example** ```typescript try { let txid = await okxwallet.bitcoin.pushTx('0200000000010135bd7d...'); console.log(txid); } catch (e) { console.log(e); } ``` ## splitUtxo `okxwallet.bitcoin.splitUtxo({ from, amount })` **Description** Spliting UTXO and initializing OKX Wallet Splitting is required by the [signature algorithm](https://github.com/magicoss/msigner/blob/main/README.md) split utxo **Parameters** - object - from - string: the BTC address of the currently connected wallet - amount - number: (optional) the amount of splits. The default value is 2. **Return value** - Promise - `{utxos: array}`: UTXOs and signatures **Example** ```typescript try { let { utxos } = await window.okxwallet.bitcoin.splitUtxo({ from: 'bc1pkrym02ck30phct287l0rktjjjnapavkl2qhsy78aeeeuk3qaaulqh90v6s', }); console.log(utxos); } catch (e) { console.log(e); } // example { utxos: [ { txId: '1e0f92720ef34ab75eefc5d691b551fb2f783eac61503a69cdf63eb7305d2306', vOut: 0, amount: 546, rawTransaction: 'xxxx', }, { txId: '1e0f92720ef34ab75eefc5d691b551fb2f783eac61503a69cdf63eb7305d2306', vOut: 1, amount: 546, rawTransaction: 'xxxx', }, ]; } ``` ## inscribe `okxwallet.bitcoin.inscribe({ type, from, tick, tid })` **Description** Inscribe transferable BRC-20 **Parameters** - type - number: transaction types. Details are shown in the table below. | Type | Description | | ---- | ------------------------------------------------ | | 51 | Default value. Inscription of a BRC-20 transfer | - from - string: the BTC address of the currently connected wallet - tick - string: BRC-20 token name (from on-chain) **Return value** - Promise - string: transaction hash that reveals the transaction **Example** ```typescript try { let txid = await okxwallet.bitcoin.inscribe({ from: 'bc1pkrym02ck30phct287l0rktjjjnapavkl2qhsy78aeeeuk3qaaulqh90v6s', tick: 'ordi', }); console.log(txid); } catch (e) { console.log(e); } ``` ## mint `okxwallet.bitcoin.mint({ type, from, inscriptions })` **Description** Universal inscriptions that support the Ordinal protocol This method supports batch inscribing **Parameters** - type - number: the type of inscribed transaction to be sent. Please refer to the table below for details. | Type | Description | | ---- | --------------------------------------------------------------------------------------------------------------------- | | 60 | BRC-20 deploy inscription | | 50 | BRC-20 mint inscription | | 51 | BRC-20 transfer inscription | | 62 | Image inscription. The image needs to be converted into a hexadecimal string representation of the image byte stream. | | 61 | Plain text | - from - string: the BTC address of the currently connected wallet - inscriptions - object[]: the array of inscriptions where each array item is an object type with its respective fields and meanings as shown in the table below: | Field | Type | Default | Description | | ----------- | ------ | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | contentType | string | "text/plain;charset=utf-8" | The type of content to be inscribed, represented by a MIME type value. As for the Ordinals protocol specifications, please refer to: https://docs.ordinals.com/inscriptions.html for details. | | body | string | No | The content being inscribed | the contentType and body parameters passed in for different inscription types: | Inscription Type | Content Type | Body | | ----------------- | ----------------------------- | ------------------------------------------------------------------------------------------------- | | image inscription | eg. "image/png", "image/jpeg" | The image needs to be converted into a hexadecimal string representation of the image byte stream | | BRC-20 | "text/plain;charset=utf-8" | Simply convert it to a string using JSON.stringify | | plain text | "text/plain;charset=utf-8" | Directly pass in plain text | **Return value** - Promise - object: tts fields and their meanings are shown below: - commitTx - string: the hash value of the commit transaction during inscription - revealTxs - string[]: the hash value of the reveal transaction during inscription. For batch inscriptions, it corresponds to the hash value of each reveal transaction separately. - commitTxFee - number: the network fee spent on the commit transaction - revealTxFees - number[]: the network fee spent on the reveal transaction. If it's a batch inscription, it corresponds to the network fee of each reveal transaction separately. - commitAddrs - string[]: the "to" address of the commit transaction, i.e., the delegate address - feeRate - number: network fee rate - size - number: the size of the inscription **Example** ```typescript okxwallet.bitcoin.mint({ type: 61, from: 'bc1p4k9ghlrynzuum080a4zk6e2my8kjzfhptr5747afzrn7xmmdtj6sgrhd0m', inscriptions: [{ contentType: 'text/plain;charset=utf-8', body: 'hello' }, { contentType: 'text/plain;charset=utf-8', body: 'world' }] }) // response { "commitAddrs": [ "bc1p9trqtf68gfeq3f3hlktaapp0eapufh02ly8dr6swfwffflvncncqwvtuen", "bc1p5ttl7q2mpvfhjq3wqffka4c05sv5jcfphcl5qeuj0pmsx7evfhcqhm60rk" ], "commitTx": "453e126346bbaaef0aaaa208acd3426cd14a39f825bd76cb8d9892957e2a5bda", "revealTxs": [ "526ff04e4ba34617ee28826412bdc8e22484890635320f880c5ec50f10d6b189", "0f65f79456a59b3e0cd4ef00e279d0d6da57582e114eafbada95b51759a845b2" ], "commitTxFee": 1379, "revealTxFees": [ 973, 973 ], feeRate: 80, size: 546, } ``` ## signPsbt `okxwallet.bitcoin.signPsbt(psbtHex[, options])` **Description** Signing psbt: this will traverse all inputs that match the current address to sign. **Parameters** - psbtHex - string: hexadecimal string representation of the partially signed bitcoin transaction (PSBT) that needs to be signed. When you generate the psbt (string) to be signed, you need to add a public key for every input of the psbt if the input uses a Taproot address. Example: Refer to txInput and publicKey below. ```typescript const txInputs: utxoInput[] = []; txInputs.push({ txId: "1e0f92720ef34ab75eefc5d691b551fb2f783eac61503a69cdf63eb7305d2306", vOut: 2, amount: 341474, address: "tb1q8h8....mjxzny", privateKey: "0s79......ldjejke", publicKey: "tb1q8h8....mjxzny", bip32Derivation: [ { "masterFingerprint": "a22e8e32", "pubkey": "tb1q8h8....mjxzny", "path": "m/49'/0'/0'/0/0", }, ], }); ``` - options - autoFinalized - boolean: whether to finalize psbt after signing — the default is true - toSignInputs - array: - index - number: which input to sign - address - string: (at least specify either an address or a public key) which corresponding private key to use for signing - publicKey - string: (at least specify either an address or a public key) which corresponding private key to use for signing - sighashTypes - number[]: (optional) sighashTypes - disableTweakSigner - boolean :(optional) when signing and unlocking Taproot addresses, the tweakSigner is used by default for signature generation. Enabling this allows for signing with the original private key. - For app versions below 6.51.0 and extension versions below 2.77.1, the options feature isn’t available, and autoFinalized is defaulted as false. - For app version 6.51.0 or above and extension version 2.77.1 or above, the options feature is available, and autoFinalizedis a boolean, defaulted as true. **Return value** - Promise - string: the hex string of the signed psbt **Example** ```typescript try { let res = await okxwallet.bitcoin.signPsbt('70736274ff01007d....', { autoFinalized: false, toSignInputs: [ { index: 0, address: 'tb1q8h8....mjxzny', }, { index: 1, publicKey: 'tb1q8h8....mjxzny', sighashTypes: [1], }, { index: 2, publicKey: '02062...8779693f', }, ], }); console.log(res); } catch (e) { console.log(e); } okxwallet.bitcoin.signPsbt('xxxxxxxx', { toSignInputs: [{ index: 0, publicKey: 'xxxxxx', disableTweakSigner: true }], autoFinalized: false, }); ``` ## signPsbts `okxwallet.bitcoin.signPsbts(psbtHexs[, options])` **Description** Signing psbts: this will traverse all inputs that match the current address to sign. **Parameters** - psbtHexs - string[]: the hex strings of psbts to sign When you generate the psbt (string) to be signed, you need to add a public key for every input of the psbt if the input uses a Taproot address. Example: Refer to txInput and publicKey below. ```typescript const txInputs: utxoInput[] = []; txInputs.push({ txId: "1e0f92720ef34ab75eefc5d691b551fb2f783eac61503a69cdf63eb7305d2306", vOut: 2, amount: 341474, address: "tb1q8h8....mjxzny", privateKey: "0s79......ldjejke", publicKey: "tb1q8h8....mjxzny", bip32Derivation: [ { "masterFingerprint": "a22e8e32", "pubkey": "tb1q8h8....mjxzny", "path": "m/49'/0'/0'/0/0", }, ], }); ``` - options - object[]: the options of signing psbts - autoFinalized - boolean: whether to finalize psbts after signing — the default is true - toSignInputs - array: - index - number: which input to sign - address - string: (at least specify either an address or a public key) which corresponding private key to use for signing - publicKey - string: (at least specify either an address or a public key) which corresponding private key to use for signing - sighashTypes - number[]: (optional) sighashTypes **Return value** - Promise - string[]: the hex strings of the signed psbts **Example** ```typescript try { let res = await okxwallet.bitcoin.signPsbts([ '70736274ff01007d...', '70736274ff01007d...', ]); console.log(res); } catch (e) { console.log(e); } ``` ## pushPsbt `okxwallet.bitcoin.pushPsbt(psbtHex)` **Description** Push psbt transaction **Parameters** - psbtHex - string: the hex string of psbt to push **Return value** - Promise - string: transaction hash **Example** ```typescript try { let res = await okxwallet.bitcoin.pushPsbt('70736274ff01007d....'); console.log(res); } catch (e) { console.log(e); } ``` ## sendPsbt `okxwallet.bitcoin.sendPsbt(txs, from)` **Description** Push psbt transaction 1. The `sendPsbt` method supports batch on-chain transactions, while the `pushPsbt` method only supports individual on-chain transactions. 2. The `sendPsbt` method supports the inclusion of the `type` parameter, providing more accurate representation of transaction history within the wallet. On the other hand, transactions pushed to the chain via the `pushPsbt` method may have a simpler representation in the transaction history. **Parameters** - txs - array: tx of psbts to publish - from - string: the BTC address of the currently connected wallet | Type | Description | | ---- | ------------ | | 52 | Send BRC-20 | | 20 | Send NFT | **Return value** - Promise - array: transaction hash **Example** ```typescript okxwallet.bitcoin.sendPsbt( [ { itemId: 'xxxxx0', //Batch unique identification, no duplicates within multiple transactions signedTx: '70736274ff01007d....', // Signature string type: 52, // BRC-20 52 or NFT 20 extJson: { //Split utxo transactions, not transmitted // NFTID inscription: '885441055c7bb5d1c54863e33f5c3a06e5a14cc4749cb61a9b3ff1dbe52a5bbbi0', }, }, { itemId: 'xxxxx1', //Batch unique identifier signedTx: '70736274ff01007d....', // Signature string or PSBT to be linked type: 52, // BRC-20 52 or NFT 20 dependItemId: ['xxxxx0 '], //The dependent transaction itemId. If there is no dependency, this field may not be passed extJson: { // NFTID inscription: '885441055c7bb5d1c54863e33f5c3a06e5a14cc4749cb61a9b3ff1dbe52a5bbbi0', }, }, ], from )[ // response ({ xxxxx0: 'txId1' }, { xxxxx1: 'txId2' }) //Failure txId returns null ]; ``` ## accountChanged **Description** OKX Wallet allows you to seamlessly manage multiple accounts from a single extension or mobile application. Whenever you switch accounts, OKX Wallet will send an `accountChanged` event. If you switch accounts while still connected to the application, and if the new account has placed the application on the allowlist, you will remain connected and OKX Wallet will pass the public key of the new account: **Usage** ```typescript window.okxwallet.bitcoin.on('accountChanged', (addressInfo) => { console.log(addressInfo); // example { "address": "bc1pwqye6x35g2n6xpwalywhpsvsu39k3l6086cvdgqazlw9mz2meansz9knaq", "publicKey": "4a627f388196639041ce226c0229560127ef9a5a39d4885123cd82dc82d8b497", "compressedPublicKey": "034a627f388196639041ce226c0229560127ef9a5a39d4885123cd82dc82d8b497" } }); ``` ## accountsChanged **Description** The accountsChanged will be emitted whenever the user's exposed account address changes. **Usage** ```typescript window.okxwallet.bitcoin.on('accountsChanged', (accounts) => { console.log(accounts)[ // example 'tb1qrn7tvhdf6wnh790384ahj56u0xaa0kqgautnnz' ]; }); ``` - [Provider API (Fractal Bitcoin)](https://web3.okx.com/onchainos/dev-docs/sdks/chains/bitcoin/provider-fractal.md) # Provider API (Fractal Bitcoin) ## What is Injected Provider API (Fractal Bitcoin)? OKX Injected Providers API (Fractal Bitcoin) is based on a JavaScript model and is embedded by OKX into websites visited by users. DApp projects can call this API to request user account information, read data from the blockchain the user is connected to, and assist the user in signing messages and transactions. ## connect **Description** Connects the wallet `okxwallet.fractalBitcoin.connect()` **Parameters** None **Return Value** - Promise - object - address - string: The current account's address - publicKey - string: The public key of the current account **Example** ```typescript const result = await okxwallet.fractalBitcoin.connect() // example { address: 'bc1pwqye6x35g2n6xpwalywhpsvsu39k3l6086cvdgqazlw9mz2meansz9knaq', publicKey: '4a627f388196639041ce226c0229560127ef9a5a39d4885123cd82dc82d8b497', compressedPublicKey:'034a627f388196639041ce226c0229560127ef9a5a39d4885123cd82dc82d8b497', } ``` ## requestAccounts `okxwallet.fractalBitcoin.requestAccounts()` **Description** Requests to connect the current account **Parameters** None **Return Value** Promise - string[]: The current account's address **Example** ```typescript try { let accounts = await okxwallet.fractalBitcoin.requestAccounts(); console.log('connect success', accounts); } catch (e) { console.log('connect failed'); } // example ['tb1qrn7tvhdf6wnh790384ahj56u0xaa0kqgautnnz']; ``` ## getAccounts `okxwallet.fractalBitcoin.getAccounts()` **Description** Retrieves the current account address **Parameters** None **Return Value** Promise - string[]: The current account address **Example** ```typescript try { let res = await okxwallet.fractalBitcoin.getAccounts(); console.log(res); } catch (e) { console.log(e); } // example ['tb1qrn7tvhdf6wnh790384ahj56u0xaa0kqgautnnz']; ``` ## getPublicKey `okxwallet.fractalBitcoin.getPublicKey()` **Description** Retrieves the public key of the current account **Parameters** None **Return Value** Promise - string: Public key **Example** ```typescript try { let res = await okxwallet.fractalBitcoin.getPublicKey(); console.log(res) } catch (e) { console.log(e); } // example 03cbaedc26f03fd3ba02fc936f338e980c9e2172c5e23128877ed46827e935296f ``` ## getBalance `okxwallet.fractalBitcoin.getBalance()` **Description** Retrieves the BTC balance **Parameters** None **Return Value** - Promise - object: - confirmed - number: Amount of confirmed satoshis - unconfirmed - number: Amount of unconfirmed satoshis - total - number: Total amount of satoshis **Example** ```typescript try { let res = await okxwallet.fractalBitcoin.getBalance(); console.log(res) } catch (e) { console.log(e); } // example { "confirmed":0, "unconfirmed":100000, "total":100000 } ``` ## signMessage `okxwallet.fractalBitcoin.signMessage(signStr[, type])` **Description** Signs a message **Parameters** - signStr - string: The data to be signed - type - string: (Optional) "ecdsa" | "bip322-simple", default is "ecdsa". (Note: Versions below 6.51.0 only support "ecdsa" signing algorithm, while versions 6.51.0 or higher support all signature types.) **Return Value** - Promise - string: Signed result **Example** ```typescript const signStr = 'need sign string'; const result = await window.okxwallet.fractalBitcoin.signMessage(signStr, 'ecdsa') // example INg2ZeG8b6GsiYLiWeQQpvmfFHqCt3zC6ocdlN9ZRQLhSFZdGhgYWF8ipar1wqJtYufxzSYiZm5kdlAcnxgZWQU= ``` ## signPsbt `okxwallet.fractalBitcoin.signPsbt(psbtHex[, options])` **Description** Signs a psbt, this method will sign all inputs matching the current address **Parameters** - psbtHex - string: Hexadecimal string of the psbt to be signed **Example: Refer to the txInput and publicKey below** ```typescript const txInputs: utxoInput[] = []; txInputs.push({ txId: "1e0f92720ef34ab75eefc5d691b551fb2f783eac61503a69cdf63eb7305d2306", vOut: 2, amount: 341474, address: "tb1q8h8....mjxzny", privateKey: "0s79......ldjejke", publicKey: "tb1q8h8....mjxzny", bip32Derivation: [{"masterFingerprint": "a22e8e32","pubkey": "tb1q8h8....mjxzny","path": "m/49'/0'/0'/0/0",},],}); - options - autoFinalized - boolean: Whether the psbt is finalized after signing, default is true - toSignInputs - array: - index - number: Input to be signed - address - string: Address corresponding to the private key used for signing - publicKey - string: Public key corresponding to the private key used for signing - sighashTypes - number[]: (Optional) sighashTypes - disableTweakSigner - boolean: (Optional) When signing and unlocking Taproot addresses, tweakSigner is used by default to generate signatures. Enabling this option allows signing with the raw private key. ``` **Return Value** - Promise - string: Hexadecimal string of the signed psbt **Example** ```typescript try {let res = await okxwallet.fractalBitcoin.signPsbt('70736274ff01007d....', { autoFinalized: false, toSignInputs: [{ index: 0, address: 'tb1q8h8....mjxzny',},{ index: 1, publicKey: 'tb1q8h8....mjxzny', sighashTypes: [1],},{ index: 2, publicKey: '02062...8779693f',},],});console.log(res);} catch (e) {console.log(e);} okxwallet.fractalBitcoin.signPsbt('xxxxxxxx', { toSignInputs: [{ index: 0, publicKey: 'xxxxxx', disableTweakSigner: true }], autoFinalized: false,}); ``` ## signPsbts `okxwallet.fractalBitcoin.signPsbts(psbtHexs[, options])` **Description** Signs multiple PSBTs. This method will iterate through all inputs that match the current address for signing. **Parameters** - psbtHexs - string[]: The hexadecimal strings of the PSBTs to be signed. **Example: You can refer to the following txInput and publicKey** ```typescript const txInputs: utxoInput[] = []; txInputs.push({ txId: "1e0f92720ef34ab75eefc5d691b551fb2f783eac61503a69cdf63eb7305d2306", vOut: 2, amount: 341474, address: "tb1q8h8....mjxzny", privateKey: "0s79......ldjejke", publicKey: "tb1q8h8....mjxzny", bip32Derivation: [{"masterFingerprint": "a22e8e32","pubkey": "tb1q8h8....mjxzny","path": "m/49'/0'/0'/0/0",},],}); - options - object[]: Options for signing the PSBT. - autoFinalized - boolean: Whether to finalize the PSBT after signing, default is true. - toSignInputs - array: - index - number: The input to be signed. - address - string: The address corresponding to the private key used for signing. - publicKey - string: The public key corresponding to the private key used for signing. - sighashTypes - number[]: (Optional) sighashTypes. ``` **Return Value** - Promise - string[]: The hexadecimal strings of the signed PSBTs. **Example** ```typescript try { let res = await okxwallet.fractalBitcoin.signPsbts([ '70736274ff01007d...', '70736274ff01007d...', ]); console.log(res); } catch (e) { console.log(e); } ``` ## pushPsbt `okxwallet.fractalBitcoin.pushPsbt(psbtHex)` **Description** ## Broadcasts a PSBT transaction. **Parameters** - psbtHex - string: The hexadecimal string of the PSBT to be pushed. **Return Value** - Promise - string: The transaction hash. **Example** ```typescript try { let res = await okxwallet.fractalBitcoin.pushPsbt('70736274ff01007d....'); console.log(res); } catch (e) { console.log(e); } ``` ## pushTx `okxwallet.fractalBitcoin.pushTx(rawTx)` **Description** Pushes a transaction. **Parameters** - rawTx - string: The raw transaction to be pushed on-chain. **Return Value** - Promise - string: The transaction hash. **Example** ```typescript try { let txid = await okxwallet.fractalBitcoin.pushTx('0200000000010135bd7d...'); console.log(txid); } catch (e) { console.log(e); } ``` - [Provider API (Testnet)](https://web3.okx.com/onchainos/dev-docs/sdks/chains/bitcoin/provider-testnet.md) # Provider API (Testnet) ## What is injected provider API (Testnet) ? The OKX Injected Providers API (Testnet) is based on a JavaScript model embedded by OKX into user-accessed websites. DApp projects can use this API to request your account information, read data from the blockchain to which you are connected, and help you in signing messages and transactions. ## connect `okxwallet.bitcoinTestnet.connect()` **Description** Connect wallet **Parameters** none **Return value** - Promise - object - address - string: address of current account - publicKey - string: public key of current account **Example** ```typescript const result = await okxwallet.bitcoinTestnet.connect() // example { address: 'bc1pwqye6x35g2n6xpwalywhpsvsu39k3l6086cvdgqazlw9mz2meansz9knaq', publicKey: '4a627f388196639041ce226c0229560127ef9a5a39d4885123cd82dc82d8b497' } ``` ## signMessage `okxwallet.bitcoinTestnet.signMessage(signStr[, type])` **Description** Sign message **Parameters** - signStr - string: requires signed data - type - string: (optional) “ecdsa” | “bip322-simple”. The default value is “ecdsa” **Return value** - Promise - string: the signing result **Example** ```typescript const signStr = 'need sign string'; const result = await window.okxwallet.bitcoinTestnet.signMessage(signStr, 'ecdsa') // example INg2ZeG8b6GsiYLiWeQQpvmfFHqCt3zC6ocdlN9ZRQLhSFZdGhgYWF8ipar1wqJtYufxzSYiZm5kdlAcnxgZWQU= ``` ## signPsbt `okxwallet.bitcoinTestnet.signPsbt(psbtHex[, options])` **Description** Signing psbt: this will traverse all inputs that match the current address to sign. **Parameters** - psbtHex - string: hexadecimal string representation of the partially signed bitcoin transaction (PSBT) that needs to be signed. When you generate the psbt (string) to be signed, you need to add a public key for every input of the psbt if the input uses a Taproot address. Example: Refer to txInput and publicKey below. ```typescript const txInputs: utxoInput[] = []; txInputs.push({ txId: "1e0f92720ef34ab75eefc5d691b551fb2f783eac61503a69cdf63eb7305d2306", vOut: 2, amount: 341474, address: "tb1q8h8....mjxzny", privateKey: "0s79......ldjejke", publicKey: "tb1q8h8....mjxzny", bip32Derivation: [ { "masterFingerprint": "a22e8e32", "pubkey": "tb1q8h8....mjxzny", "path": "m/49'/0'/0'/0/0", }, ], }); ``` - options - autoFinalized - boolean: whether to finalize psbt after signing — the default is true - toSignInputs - array: - index - number: which input to sign - address - string: (at least specify either an address or a public key) which corresponding private key to use for signing - publicKey - string: (at least specify either an address or a public key) which corresponding private key to use for signing - sighashTypes - number[]: (optional) sighashTypes - disableTweakSigner - boolean :(optional) when signing and unlocking Taproot addresses, the tweakSigner is used by default for signature generation. Enabling this allows for signing with the original private key. **Return value** - Promise - string: the hex string of the signed psbt **Example** ```typescript try { let res = await okxwallet.bitcoinTestnet.signPsbt('70736274ff01007d....', { autoFinalized: false, toSignInputs: [ { index: 0, address: 'tb1q8h8....mjxzny', }, { index: 1, publicKey: 'tb1q8h8....mjxzny', sighashTypes: [1], }, { index: 2, publicKey: '02062...8779693f', }, ], }); console.log(res); } catch (e) { console.log(e); } okxwallet.bitcoinTestnet.signPsbt('xxxxxxxx', { toSignInputs: [{ index: 0, publicKey: 'xxxxxx', disableTweakSigner: true }], autoFinalized: false, }); ``` ## signPsbts `okxwallet.bitcoinTestnet.signPsbts(psbtHexs[, options])` **Description** Signing psbts: this will traverse all inputs that match the current address to sign. **Parameters** - psbtHexs - string[]: the hex strings of psbts to sign When you generate the psbt (string) to be signed, you need to add a public key for every input of the psbt if the input uses a Taproot address. Example: Refer to txInput and publicKey below. ```typescript const txInputs: utxoInput[] = []; txInputs.push({ txId: "1e0f92720ef34ab75eefc5d691b551fb2f783eac61503a69cdf63eb7305d2306", vOut: 2, amount: 341475, address: "tb1q8h8....mjxzny", privateKey: "0s79......ldjejke", publicKey: "tb1q8h8....mjxzny", bip32Derivation: [ { "masterFingerprint": "a22e8e32", "pubkey": "tb1q8h8....mjxzny", "path": "m/49'/0'/0'/0/0", }, ], }); ``` - options - object[]: the options of signing psbts - autoFinalized - boolean: whether to finalize psbts after signing — the default is true - toSignInputs - array: - index - number: which input to sign - address - string: (at least specify either an address or a public key) which corresponding private key to use for signing - publicKey - string: (at least specify either an address or a public key) which corresponding private key to use for signing - sighashTypes - number[]: (optional) sighashTypes **Return value** - Promise - string[]: the hex strings of the signed psbts **Example** ```typescript try { let res = await okxwallet.bitcoinTestnet.signPsbts([ '70736274ff01007d...', '70736274ff01007d...', ]); console.log(res); } catch (e) { console.log(e); } ``` - [Provider API (Signet)](https://web3.okx.com/onchainos/dev-docs/sdks/chains/bitcoin/provider-signet.md) # Provider API (Signet) ## What is injected provider API (Signet) ? The OKX Injected Providers API (Signet) is based on a JavaScript model embedded by OKX into user-accessed websites. DApp projects can use this API to request your account information, read data from the blockchain to which you are connected, and help you in signing messages and transactions. ## connect `okxwallet.bitcoinSignet.connect()` **Description** Connect wallet **Parameters** none **Return value** - Promise - object - address - string: address of current account - publicKey - string: public key of current account **Example** ```typescript const result = await okxwallet.bitcoinSignet.connect() // example { address: 'bc1pwqye6x35g2n6xpwalywhpsvsu39k3l6086cvdgqazlw9mz2meansz9knaq', publicKey: '4a627f388196639041ce226c0229560127ef9a5a39d4885123cd82dc82d8b497' } ``` ## signMessage `okxwallet.bitcoinSignet.signMessage(signStr[, type])` **Description** Sign message **Parameters** - signStr - string: requires signed data - type - string: (optional) “ecdsa” | “bip322-simple”. The default value is “ecdsa” **Return value** - Promise - string: the signing result **Example** ```typescript const signStr = 'need sign string'; const result = await window.okxwallet.bitcoinSignet.signMessage(signStr, 'ecdsa') // example INg2ZeG8b6GsiYLiWeQQpvmfFHqCt3zC6ocdlN9ZRQLhSFZdGhgYWF8ipar1wqJtYufxzSYiZm5kdlAcnxgZWQU= ``` ## signPsbt `okxwallet.bitcoinSignet.signPsbt(psbtHex[, options])` **Description** Signing psbt: this will traverse all inputs that match the current address to sign. **Parameters** - psbtHex - string: hexadecimal string representation of the partially signed bitcoin transaction (PSBT) that needs to be signed. When you generate the psbt (string) to be signed, you need to add a public key for every input of the psbt if the input uses a Taproot address. Example: Refer to txInput and publicKey below. ```typescript const txInputs: utxoInput[] = []; txInputs.push({ txId: "1e0f92720ef34ab75eefc5d691b551fb2f783eac61503a69cdf63eb7305d2306", vOut: 2, amount: 341474, address: "tb1q8h8....mjxzny", privateKey: "0s79......ldjejke", publicKey: "tb1q8h8....mjxzny", bip32Derivation: [ { "masterFingerprint": "a22e8e32", "pubkey": "tb1q8h8....mjxzny", "path": "m/49'/0'/0'/0/0", }, ], }); ``` - options - autoFinalized - boolean: whether to finalize psbt after signing — the default is true - toSignInputs - array: - index - number: which input to sign - address - string: (at least specify either an address or a public key) which corresponding private key to use for signing - publicKey - string: (at least specify either an address or a public key) which corresponding private key to use for signing - sighashTypes - number[]: (optional) sighashTypes - disableTweakSigner - boolean :(optional) when signing and unlocking Taproot addresses, the tweakSigner is used by default for signature generation. Enabling this allows for signing with the original private key. **Return value** - Promise - string: the hex string of the signed psbt **Example** ```typescript try { let res = await okxwallet.bitcoinSignet.signPsbt('70736274ff01007d....', { autoFinalized: false, toSignInputs: [ { index: 0, address: 'tb1q8h8....mjxzny', }, { index: 1, publicKey: 'tb1q8h8....mjxzny', sighashTypes: [1], }, { index: 2, publicKey: '02062...8779693f', }, ], }); console.log(res); } catch (e) { console.log(e); } okxwallet.bitcoinSignet.signPsbt('xxxxxxxx', { toSignInputs: [{ index: 0, publicKey: 'xxxxxx', disableTweakSigner: true }], autoFinalized: false, }); ``` ## signPsbts `okxwallet.bitcoinSignet.signPsbts(psbtHexs[, options])` **Description** Signing psbts: this will traverse all inputs that match the current address to sign. **Parameters** - psbtHexs - string[]: the hex strings of psbts to sign When you generate the psbt (string) to be signed, you need to add a public key for every input of the psbt if the input uses a Taproot address. Example: Refer to txInput and publicKey below. ```typescript const txInputs: utxoInput[] = []; txInputs.push({ txId: "1e0f92720ef34ab75eefc5d691b551fb2f783eac61503a69cdf63eb7305d2306", vOut: 2, amount: 341474, address: "tb1q8h8....mjxzny", privateKey: "0s79......ldjejke", publicKey: "tb1q8h8....mjxzny", bip32Derivation: [ { "masterFingerprint": "a22e8e32", "pubkey": "tb1q8h8....mjxzny", "path": "m/49'/0'/0'/0/0", }, ], }); ``` - options - object[]: the options of signing psbts - autoFinalized - boolean: whether to finalize psbts after signing — the default is true - toSignInputs - array: - index - number: which input to sign - address - string: (at least specify either an address or a public key) which corresponding private key to use for signing - publicKey - string: (at least specify either an address or a public key) which corresponding private key to use for signing - sighashTypes - number[]: (optional) sighashTypes **Return value** - Promise - string[]: the hex strings of the signed psbts **Example** ```typescript try { let res = await okxwallet.bitcoinSignet.signPsbts([ '70736274ff01007d...', '70736274ff01007d...', ]); console.log(res); } catch (e) { console.log(e); } ``` - [Tron](https://web3.okx.com/onchainos/dev-docs/sdks/chains/tron/introduce.md) # Tron Tron aims to build a decentralized content entertainment ecosystem. The Tron network employs a Delegated Proof of Stake (DPoS) consensus mechanism, which allows it to achieve high throughput and low transaction fees. As a smart contract platform, Tron is fully compatible with the Ethereum Virtual Machine (EVM), enabling developers to easily migrate decentralized applications (DApps) from Ethereum to the Tron network. Tron's native token is TRX, which is used for network governance, transaction fee payment, and value transfer. The platform focuses particularly on applications in the digital content, entertainment, and social media sectors, aiming to create an intermediary-free content distribution system. With its efficient performance and active developer community, Tron has become an important platform for decentralized finance (DeFi), non-fungible tokens (NFTs), and decentralized applications. - [Obtain Wallet Address](https://web3.okx.com/onchainos/dev-docs/sdks/chains/tron/connect.md) # Obtain Wallet Address Wallet account addresses are used in various scenarios, including as identifiers and for signing transactions. ## Creating a Connection It is recommended to provide a button here that allows users to connect the OKX Web3 Wallet Tron to the DApp. In the example project code below, the JavaScript code accesses the user's account address when the user clicks the connect button, and the HTML code displays the button and the current account address: ```html ``` ```javascript const connectTronButton = document.querySelector('.connectTronButton'); connectTronButton.addEventListener('click', () => { //Will Start the OKX extension window.okxwallet.tronLink.request({ method: 'tron_requestAccounts'}) }); ``` ## Detect Account Address Changes You can also listen to the emitted events to get updates: ```typescript window.addEventListener('message', function (e) { if (e.data.message && e.data.message.action === "accountsChanged") { // handler logic console.log('got accountsChanged event', e.data, e.data.message.address) } }) ``` The OKX provider will emit this event whenever the return value of the `tron_requestAccounts` RPC changes. - [Provider API](https://web3.okx.com/onchainos/dev-docs/sdks/chains/tron/provider.md) # Provider API ## What is injected provider API? The OKX injected provider API is a JavaScript API that OKX injects into websites visited by our users. Your DApp can use this API to request users' accounts, read data from blockchains users are connected to, and help users sign messages and transactions. ## Connecting to OKX Wallet `window.okxwallet.tronLink.request(args)` **Description** OKX Wallet supports TRX transfers, signing and authorizing contracts, and other authorization functions initiated by DApps. For security reasons, OKX Wallet needs you to authorize your DApp to connect to the website. DApps must first connect to the website and wait for your permission to initiate an authorization request. ```typescript window.okxwallet.tronLink.request({ method: 'tron_requestAccounts'}) ``` **Status code** |
Status code
| Description | Message | |:-------------------|:------------------------------|:-----| | 200 | The site has been allowed to be connect to | The site is already in the allowlist | | 200 | User has approved the connection | User approved the request | | 4000 | The same DApp has already initiated a request to connect to the website | Authorization requests are being processed. Please do not re-submit. | | 4001 | User has rejected the connection | User rejected the request | **Example** Open in [codeopen](https://codepen.io/okxwallet/pen/eYLBpNp). ```html ``` ```javascript const connectTronButton = document.querySelector('.connectTronButton'); connectTronButton.addEventListener('click', () => { window.okxwallet.tronLink.request({ method: 'tron_requestAccounts' }).catch((error)=>{ console.log(error); }) }); ``` Three steps are required to initiate a transaction on the TRON network. 1. Start a transfer transaction 2. Sign the transaction 3. Broadcast the signed transaction In this process, the second step requires TronLink, while the first and third steps are done on tronWeb. ## Signing transactions `okxwallet.tronLink.tronWeb.trx.sign(transaction, privateKey)` **Description** **Step 1: Starting a transfer** **sendTRX** This will initiate an unsigned TRX transfer. **Usage** ```javascript okxwallet.tronLink.tronWeb.transactionBuilder.sendTrx(to,amount,from,options); ``` **Parameters** | Parameter | Description | Type | | ------ | ------ | ------ | | to | Address to transfer TRX | hexStrig | | amount | Number of TRX to send | integer | | from | Address that's transferring the tokens (optional). If left blank, it will be the address associated with the private key. | hexString | | options | Permission ID | integer | **Example** ```javascript okxwallet.tronLink.tronWeb.transactionBuilder.sendTrx("TVDGpn4hCSzJ5nkHPLetk8KQBtwaTppnkr", 100, "TNPeeaaFB7K9cmo4uQpcU32zGK8G1NYqeL"); ``` **Step 2: Signing a transaction** **sign** This will sign the transaction. To prevent disclosure of the private key, don't use this request on any web or user-oriented applications. **Usage** ```javascript // sign a transaction okxwallet.tronLink.tronWeb.trx.sign(transaction, privateKey); ``` **Parameters** | Parameter | Description | Type | | ----- | ----- | ----- | | transaction | The trading partner | JSON | | privateKey | The private key is used for signing (optional). By default, the private key is the one passed in when the tronweb was built. | string | **Example** ```javascript const tradeobj = await okxwallet.tronLink.tronWeb.transactionBuilder.sendTrx("TNo9e8MWQpGVqdyySxLSTw3gjgFQWE3vfg", 100,"TM2TmqauSEiRf16CyFgzHV2BVxBejY9iyR",1); const signedtxn = await okxwallet.tronLink.tronWeb.trx.sign(tradeobj, privateKey); console.log(signedtxn) ``` **Step 3: Broadcasting the signed transactions** **sendRawTransaction** This broadcasts the signed transactions to the network. **Usage** ```javascript // sign a transaction okxwallet.tronLink.tronWeb.trx.sendRawTransaction(signedTransaction); ``` **Parameters** | Parameter | Description | Type | | ----- | ----- | ----- | | signedTransaction | Signed trading partners | JSON | **Example** ```javascript const tronWeb = okxwallet.tronLink.tronWeb; const tradeobj = await tronWeb.transactionBuilder.sendTrx("TNo9e8MWQpGVqdyySxLSTw3gjgFQWE3vfg", 100,"TM2TmqauSEiRf16CyFgzHV2BVxBejY9iyR",1); const signedtxn = await tronWeb.trx.sign(tradeobj, privateKey); const receipt = await tronWeb.trx.sendRawTransaction(signedtxn); console.log(receipt) ``` **Example** Open in [codeopen](https://codepen.io/okxwallet/pen/JjabYWy). ```html ``` ```javascript const connectTronButton = document.querySelector('.connectTronButton'); const signTransactionButton = document.querySelector('.signTransactionButton'); signTransactionButton.addEventListener('click', () => { if (window.okxwallet.tronLink.ready) { const tronweb = okxwallet.tronLink.tronWeb; // const fromAddress = tronweb.defaultAddress.base58; const fromAddress = 'TNPeeaaFB7K9cmo4uQpcU32zGK8G1NYqeL' const toAddress = "TAHQdDiZajMMP26STUnfsiRMNyXdxAJakZ"; try { const tx = await tronweb.transactionBuilder.sendTrx(toAddress, 10); // Step1 const signedTx = await tronweb.trx.sign(tx); // Step2 await tronweb.trx.sendRawTransaction(signedTx); // Step3 } catch (error) { // error handling console.log(error) } } }); connectTronButton.addEventListener('click', () => { window.okxwallet.tronLink.request({ method: 'tron_requestAccounts' }).catch((error)=>{ console.log(error); }) }); ``` ## Signing messages `window.okxwallet.tronLink.tronWeb.trx.sign(message)` **Description** DApps require users to sign hexadecimal messages. The signed message will be forwarded to the backend to verify whether the user's login is valid. DApps will then send a request to ask the user to connect the wallet to the website, to which the user agrees. **Parameters** | Parameter | Description | Type | | ----- | ----- | ----- | | message | normal string or hexadecimal string | String | **Version** - For the versions of the okx wallet `prior to 2.80.0`: Regardless of whether the parameter is in hexadecimal format or not, it will undergo hexadecimal conversion before signing. Therefore, if the original message is already in hexadecimal, an additional hexadecimal conversion is required during signature verification. - For the versions of the okx wallet `2.80.0 and later`: If the input parameter is a hexadecimal string, no conversion is needed; it can be signed directly. If the input parameter is a non-hexadecimal string, the wallet internally converts it to a hexadecimal string for signing. For example, for the plain string "helloworld," the corresponding hexadecimal format is "68656c6c6f776f726c64." Therefore, .sign('helloworld') is equivalent to .sign('0x68656c6c6f776f726c64'). **Return value** If you choose the sign option in the pop-up window, the DApp will obtain the signed hexadecimal string. For example: ``` 0xaa302ca153b10dff25b5f00a7e2f603c5916b8f6d78cdaf2122e24cab56ad39a79f60ff3916dde9761baaadea439b567475dde183ee3f8530b4cc76082b29c341c ``` If an error occurs, the following information is returned: ``` Uncaught (in promise) Invalid transaction provided ``` **Example** Open in [codeopen](https://codepen.io/okxwallet/pen/qBMqOqX). ```html ``` ```javascript const connectTronButton = document.querySelector('.connectTronButton'); const signButton = document.querySelector('.signButton'); const verifyButton = document.querySelector('.verifyButton'); signButton.addEventListener('click', async() => { if (window.okxwallet.tronLink.ready) { const tronweb = window.okxwallet.tronLink.tronWeb; try { const message = "0x1e"; // any hex string const signedString = await tronweb.trx.sign(message); } catch (error) { // handle error } } }); verifyButton.addEventListener('click', async() => { if (window.okxwallet.tronLink.ready) { const tronweb = window.okxwallet.tronLink.tronWeb; try { const message = "0x1e"; const result = await tronweb.trx.verifyMessage(message, window.signedString); } catch (error) { // handle error } } }); connectTronButton.addEventListener('click', () => { connetAccount(); }); async function connetAccount() { await window.okxwallet.tronLink.request({ method: 'tron_requestAccounts' }) } ``` ## Verify Signed Message `window.okxwallet.tronLink.tronWeb.trx.verifyMessage(hexMsg, signedMsg[, address])` **Description** verify signature **Parameters** | Parameter | Description | Type | | ----- | ----- | ----- | | hexMsg | hex format message string | String | | signedMsg | signed message with signature | String | | address | account address, optional | String | **Version** Take the example of the above `helloworld` and its corresponding hexadecimal `0x68656c6c6f776f726c64`. - For the versions of the okx wallet `before 2.80.0`: Non-hexadecimal string: ```javascript const signedMsg = await window.okxwallet.tronLink.tronWeb.trx.sign('helloworld') const validate = await window.okxwallet.tronLink.tronWeb.trx.verifyMessage('0x68656c6c6f776f726c64', signedMsg) ``` Hexadecimal string: ```javascript const signedMsg = await window.okxwallet.tronLink.tronWeb.trx.sign('0x68656c6c6f776f726c64') // one more step to convert the original message to hexadecimal const hexed = await window.okxwallet.tronLink.tronWeb.toHex('0x68656c6c6f776f726c64') const validate = await window.okxwallet.tronLink.tronWeb.trx.verifyMessage(hexed, signedMsg) ``` - For the versions of the okx wallet `2.80.0 and later`: Non-hexadecimal string: ```javascript const signedMsg = await window.okxwallet.tronLink.tronWeb.trx.sign('helloworld') const validate = await window.okxwallet.tronLink.tronWeb.trx.verifyMessage('0x68656c6c6f776f726c64', signedMsg) ``` Hexadecimal string: ```javascript const signedMsg = await window.okxwallet.tronLink.tronWeb.trx.sign('0x68656c6c6f776f726c64') const validate = await window.okxwallet.tronLink.tronWeb.trx.verifyMessage('0x68656c6c6f776f726c64', signedMsg) ``` **Return value** (Promise) boolean: true or false ## Events **connect** This message will be generated during the following events: 1. The DApp requests to connect, and the user approves the connection in the pop-up. 2. The user connects to the website. **Usage** ```typescript window.addEventListener('message', function (e) { if (e.data.message && e.data.message.action == "connect") { // handler logic console.log('got connect event', e.data) } }) ``` **disconnect** This message will be generated during the following events: 1. The DApp requests to connect, and the user rejects the connection in the pop-up 2. The user disconnects from the website **Usage** ```typescript window.addEventListener('message', function (e) { if (e.data.message && e.data.message.action == "disconnect") { // handler logic console.log('got connect event', e.data) } }) ``` **accountsChanged** This message will be generated during the following events: 1. The user logs in 2. The user switches account 3. The user locks the account. 4. The wallet automatically locks after timeout. **Usage** ```typescript window.addEventListener('message', function (e) { if (e.data.message && e.data.message.action === "accountsChanged") { // handler logic console.log('got accountsChanged event', e.data) } }) ``` **Return value** ```typescript interface MessageEventAccountsChangedData { isTronLink: boolean; message: { action: string; data: { address: string | boolean; } } } ``` **Example** Open in [codeopen](https://codepen.io/okxwallet/pen/YzOpyLO). ```html ``` ```javascript const connectTronButton = document.querySelector('.connectTronButton'); window.addEventListener('message', function (e) { if (e.data.message && e.data.message.action == "connect") { // handler logic console.log('got connect event', e.data) } }) connectTronButton.addEventListener('click', () => { window.okxwallet.tronLink.request({ method: 'tron_requestAccounts' }).catch((error)=>{ console.log(error); }) }); ``` - [Solana-Compatible Chains](https://web3.okx.com/onchainos/dev-docs/sdks/chains/solana/introduce.md) # Solana-Compatible Chains Solana is a high-performance blockchain platform committed to providing fast, secure, and scalable solutions for decentralized applications and cryptocurrencies. The platform utilizes an innovative consensus algorithm called Proof of History (PoH) that can handle tens of thousands of transactions per second (TPS) while maintaining decentralization and security. Overall, Solana aims to achieve mass adoption of blockchain through its unique technological advantages, catering to various complex decentralized applications and global financial systems. Common Solana-compatible networks include SOON, Sonic, etc. - [Provider API](https://web3.okx.com/onchainos/dev-docs/sdks/chains/solana/provider.md) # Provider API ## What is injected provider API? The OKX injected provider API is a JavaScript API that OKX injects into websites visited by our users. Your DApp can use this API to request users' accounts, read data from blockchains users are connected to, and help users sign messages and transactions. ## Connecting to OKX Wallet `window.okxwallet.solana.connect()` **Description** You can connect to OKX Wallet by calling `window.okxwallet.solana.connect()`. The `connect` call will return a `Promise` object, which will `resolve` when the user accepts the connection request and`reject` if you reject the request. For more information about possible errors in OKX Wallet, see [Error message ](#error-codes). If you accept the connection request, `window.okxwallet.solana` will also trigger the connection event. ```typescript window.okxwallet.solana.on("connect", () => console.log("connected!")); ``` Once the web application is connected to OKX Wallet, OKX Wallet will be able to read the public key of the connecting account and prompt you to make other transactions. We'll also conveniently expose a boolean returned from the isConnected request. **Example** Open in [codeopen](https://codepen.io/okxwallet/pen/poOREZw). ```html ``` ```javascript const connectSolanaButton = document.querySelector('.connectSolanaButton'); connectSolanaButton.addEventListener('click', () => { try { const provider = window.okxwallet.solana; const resp = await provider.connect(); console.log(resp.publicKey.toString()); } catch (error) { console.log(error); } }); ``` ## Signing transactions `window.okxwallet.solana.signTransaction(transaction)` **Signing and sending the transaction** After the transaction is initiated, the web application may request the your OKX Wallet to sign and send the transaction. If accepted, OKX Wallet will use your private key to sign the transaction and submit it through the `Solana JSON RPC` connection. Calling the `signAndSendTransaction` method on `okxwallet`.`solana` will return a `Promise` for the signed transaction. ```typescript const provider = window.okxwallet.solana; const network = ""; const connection = new Connection(network); const transaction = new Transaction(); const { signature } = await provider.signAndSendTransaction(transaction); await connection.getSignatureStatus(signature); ``` **Signing the transaction without sending** After the transaction is initiated, the web application may require your OKX Wallet to sign the transaction without submitting it to the network. Calling the `signTransaction` method will return a `Promise` for the signed transaction. After the transaction is signed, the application can go through [@solana/web3.js](https://solana-labs.github.io/solana-web3.js/classes/Connection.html#sendRawTransaction) `sendRawTransaction` and submit the transaction. ```typescript const provider = window.okxwallet.solana; const network = ""; const connection = new Connection(network); const transaction = new Transaction(); const signedTransaction = await provider.signTransaction(transaction); const signature = await connection.sendRawTransaction(signedTransaction.serialize()); ``` **Batch signing transactions** You can also sign and send multiple transactions at the same time using `signAllTransactions` on the `provider`. ```typescript const provider = window.okxwallet.solana; const transactions = [new Transaction()]; const signedTransactions = await provider.signAllTransactions(transactions); ``` **Example** Open in [codeopen](https://codepen.io/okxwallet/pen/JjaERMa). ```html ``` ```javascript import { Connection, Transaction } from "@solana/web3.js"; const connectSolanaButton = document.querySelector('.connectSolanaButton'); const signTransactionButton = document.querySelector('.signTransactionButton'); signTransactionButton.addEventListener('click', async() => { try { const provider = window.okxwallet.solana; const network = ""; const connection = new Connection(network); const transaction = new Transaction(); const signedTransaction = await provider.signTransaction(transaction); const signature = await connection.sendRawTransaction(signedTransaction.serialize()); console.log(signature); } catch (error) { console.log(error) } }); connectSolanaButton.addEventListener('click', async() => { try { const provider = window.okxwallet.solana; const resp = await provider.connect(); console.log(resp.publicKey.toString()); } catch (error) { console.log(error); } }); ``` ## Signing messages `window.okxwallet.solana.signMessage(args)` **Description** When a web application connects to OKX Wallet, it can also request you to sign the given message. The application can freely write its own messages, which will be displayed OKX Wallet's signature prompt. Message signing doesn't involve network costs and is a convenient way for applications to verify address ownership. In order to send a message for you to sign, the web application must provide a hexadecimal or UTF-8 encoded string as Uint8Array, and request the encoded message to be signed through your OKX Wallet. ```typescript const message = `To avoid digital dognappers, sign below to authenticate with CryptoCorgis`; const encodedMessage = new TextEncoder().encode(message); const signedMessage = await window.okxwallet.solana.signMessage(encodedMessage, "utf8"); ``` **Example** Open in [codeopen](https://codepen.io/okxwallet/pen/eYLgdqK). ```html ``` ```javascript const connectSolanaButton = document.querySelector('.connectSolanaButton'); const signButton = document.querySelector('.signButton'); signButton.addEventListener('click', async() => { try { const message = `To avoid digital dognappers, sign below to authenticate with CryptoCorgis`; const encodedMessage = new TextEncoder().encode(message); const signedMessage = await window.okxwallet.solana.signMessage(encodedMessage, "utf8"); console.log(signedMessage); } catch (error) { // see "Errors" } }); connectSolanaButton.addEventListener('click', () => { connetAccount(); }); async function connetAccount() { try { const provider = window.okxwallet.solana; const resp = await provider.connect(); console.log(resp.publicKey.toString()); } catch (error) { console.log(error); } } ``` ## Events **Connecting to OKX Wallet** Call `window.okxwallet.solana.connect()` to connect to OKX Wallet. Once you accept the connection request, the connection event will trigge **Usage** ```typescript window.okxwallet.solana.on("connect", () => console.log("connected!")); ``` **Disconnecting from OKX Wallet** The disconnecting method is the same as the connecting method. However, the wallet can also initiate the disconnection. **Usage** ```typescript window.okxwallet.solana.on("disconnect", () => console.log("disconnected!") ); ``` **Switching accounts** OKX Wallet allows you to seamlessly manage multiple accounts from a single extension or mobile application. Whenever you switch accounts, OKX Wallet will send an `accountChanged` event. If you switch accounts while still connected to the application, and if the new account has placed the application on the allowlist, you will remain connected and OKX Wallet will pass the public key of the new account: **Usage** ```typescript window.okxwallet.solana.on('accountChanged', (publicKey) => { if (publicKey) { // Set new public key and continue as usual console.log(`Switched to account ${publicKey.toBase58()}`); } }); ``` If OKX Wallet doesn't pass the public key of the new account, the application can either do nothing or try to reconnect: ```typescript window.okxwallet.solana.on('accountChanged', (publicKey) => { if (publicKey) { // Set new public key and continue as usual console.log(`Switched to account ${publicKey.toBase58()}`); } else { // Attempt to reconnect to OKX wallet window.okxwallet.solana.connect().catch((error) => { // Handle connection failure }); } }); ``` **Example** Open in [codeopen](https://codepen.io/okxwallet/pen/OJoWRGX). ```html ``` ```javascript const connectSolanaButton = document.querySelector('.connectSolanaButton'); window.okxwallet.solana.on('connect',()=>{ console.log('connected'); }) connectSolanaButton.addEventListener('click', async() => { try { const res = await window.okxwallet.aptos.connect(); console.log(res); } catch (error) { console.log(error); } }); ``` - [Get genesisHash](https://web3.okx.com/onchainos/dev-docs/sdks/chains/solana/web-solana-detect-user-network.md) # Get genesisHash `window.okxwallet.svm.getNetwork()` All remote procedure call (RPC) requests are submitted to the currently connected network. Therefore, getting the user’s correct network genesisHash is crucial for SVM-based application development. Use the `window.okxwallet.svm.getNetwork()` method to retrieve the user’s current network genesisHash. ```javascript const { genesisHash } = await window.okxwallet.svm.getNetwork() ``` ### Deafult genesisHash Below are the genesisHash values of the SVM networks that OKX Wallet supports by default: | Network | genesisHash | | ---- | ------- | | SOL | 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d | | SONIC_TESTNET_VONE | E8nY8PG8PEdzANRsv91C2w28Dbw9w3AhLqRYfn5tNv2C | | SOONTEST_ETH | E41XcTqezgDG8GzWwnPW8Rjewv2o5UUtskPbuwA52Kjr | | ECLIPSE_ETH | EAQLJCV2mh23BsK2P9oYpV5CHVLDNHTxYss3URrNmg3s | | SOON_ETH | E8aYS7Vghmf1sZVSsCse9JdFHzccdE9QdpPF5SVNcGxr | | SONIC_SOL | 9qoRTAHGWBZHYzMJGkt62wBbFRASj6H7CvoNsNyRw2h4 | | SOON_BNB | 8MCzWLHk3FmrdW1gVtZe7NgDefMhYFZfTUmvMANn5r6X | - [Switch Network](https://web3.okx.com/onchainos/dev-docs/sdks/chains/solana/web-solana-switch-network.md) # Switch Network `window.okxwallet.svm.changeNetwork({ genesisHash })` **Description** Parameters - genesisHash - string: The genesisHash of the target network. Return value - Promise\: The user’s current network, containing: - genesisHash - string: The genesisHash of the user’s current network. This method prompts the user to confirm whether they want to switch to the network with the specified `genesisHash` and returns a confirmation value. Like any method requiring user confirmation, `window.okxwallet.svm.changeNetwork({ genesisHash })` can only be called as a direct result of a user action, such as clicking a button. OKX Wallet will automatically reject the request in the following cases: - The genesisHash format is incorrect. - The network corresponding to the specified genesisHash hasn’t been added to OKX Wallet. Example ```javascript const { genesisHash } = await window.okxwallet.svm.changeNetwork( { "genesisHash": "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d" } ) ``` ### Default genesisHash Below are the genesisHash values of the SVM networks that OKX Wallet supports by default: | Network | genesisHash | | ---- | ------- | | SOL | 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d | | SONIC_TESTNET_VONE | E8nY8PG8PEdzANRsv91C2w28Dbw9w3AhLqRYfn5tNv2C | | SOONTEST_ETH | E41XcTqezgDG8GzWwnPW8Rjewv2o5UUtskPbuwA52Kjr | | ECLIPSE_ETH | EAQLJCV2mh23BsK2P9oYpV5CHVLDNHTxYss3URrNmg3s | | SOON_ETH | E8aYS7Vghmf1sZVSsCse9JdFHzccdE9QdpPF5SVNcGxr | | SONIC_SOL | 9qoRTAHGWBZHYzMJGkt62wBbFRASj6H7CvoNsNyRw2h4 | | SOON_BNB | 8MCzWLHk3FmrdW1gVtZe7NgDefMhYFZfTUmvMANn5r6X | - [TON](https://web3.okx.com/onchainos/dev-docs/sdks/chains/ton/introduce.md) # TON TON blockchain, fully named The Open Network, aims to provide fast and efficient transaction processing capabilities while supporting smart contracts and decentralized applications. TON uses an innovative design called "multi-chain architecture," which enables high scalability by allowing multiple blockchains to run in parallel, thereby increasing the throughput and performance of the entire network. - [Provider API](https://web3.okx.com/onchainos/dev-docs/sdks/chains/ton/provider.md) # Provider API ## What is injected provider API? The OKX injected provider API is a JavaScript API that OKX injects into websites visited by our users. Your DApp can use this API to request users' accounts, read data from blockchains users are connected to, and help users sign messages and transactions. ## Special Notes OKX Wallet's TON API is fully compliant with the [Ton Connect protocol](https://docs.ton.org/develop/dapps/ton-connect/protocol/). Dapps can use the [TON Connect SDK](https://docs.ton.org/develop/dapps/ton-connect/developers) to more easily integrate with OKX Wallet. ## Getting the Injected Object OKX Wallet injects the following properties into Dapps according to the TON Connect protocol specification: ```js window.okxTonWallet.tonconnect ``` The data structure of the object it points to is as follows: ```ts interface TonConnectBridge { deviceInfo: DeviceInfo; walletInfo?: WalletInfo; protocolVersion: number; connect(protocolVersion: number, message: ConnectRequest): Promise; restoreConnection(): Promise; send(message: AppRequest): Promise; listen(callback: (event: WalletEvent) => void): () => void; } ``` ## deviceInfo To obtain device information, the data structure is as follows: ```js { platform: 'browser', appName: 'OKX Wallet', appVersion: '3.3.19', maxProtocolVersion: 2, features: [ 'SendTransaction', { name: 'SendTransaction', maxMessages: 4, }, ], } ``` * `platform`: Device platform * `appName`: Wallet name * `appVersion`: Wallet version * `maxProtocolVersion`: Supported maximum protocol version * `features`: Features supported by the wallet ## walletInfo To obtain wallet information, the data structure is as follows: ```js { name: 'OKX Wallet', app_name: 'okxTonWallet', image: 'https://static.okx.com/cdn/assets/imgs/247/58E63FEA47A2B7D7.png', about_url: 'https://web3.okx.com/web3', platforms: ['chrome', 'firefox', 'safari'], } ``` * `name`: Wallet name * `app_name`: Unique identifier for the wallet application * `image`: Wallet icon * `about_url`: Wallet introduction page * `platforms`: Platforms supported by the wallet ## protocolVersion The version of Ton Connect supported by OKX Wallet is currently 2 ## connect Method to connect the wallet. During the connection, the wallet can also be verified with a signature: ```ts connect(protocolVersion: number, message: ConnectRequest): Promise; ``` ### Parameters * `protocolVersion`: The version of Ton Connect that the Dapp expects the wallet to support. If the wallet does not support this version, an error will be returned immediately. * `message`: Connection request information **message parameter** ```ts type ConnectRequest = { manifestUrl: string; items: ConnectItem[], // Data items shared with the application } type ConnectItem = TonAddressItem | TonProofItem type TonAddressItem = { name: "ton_addr"; } type TonProofItem = { name: "ton_proof"; payload: string; // Arbitrary payload, such as nonce + expiration timestamp. } ``` * `manifestUrl`: The URL of the Dapp's manifest.json file, which contains the Dapp's metadata, with the following data structure: ```json { "url": "", // Required "name": "", // Required "iconUrl": "", // Required "termsOfUseUrl": "", // Optional "privacyPolicyUrl": "" // Optional } ``` * `items`: List of instructions requested from the wallet, currently supporting two instructions: * `ton_addr`: Obtain the user's address, public key, and other information * `ton_proof`: Verify the wallet with a signature ### Return value Returns a Promise object, with the result being `ConnectEvent` and the following data structure: ```ts type ConnectEvent = ConnectEventSuccess | ConnectEventError; type ConnectEventSuccess = { event: "connect"; id: number; // increasing event counter payload: { items: ConnectItemReply[]; device: DeviceInfo; } } type ConnectEventError = { event: "connect_error", id: number; // increasing event counter payload: { code: number; message: string; } } // Identical to the deviceInfo on the window.okxTonWallet.tonconnect object type DeviceInfo = { platform: "iphone" | "ipad" | "android" | "windows" | "mac" | "linux"; appName: string; appVersion: string; maxProtocolVersion: number; features: Feature[]; } type Feature = { name: 'SendTransaction', maxMessages: number } // `maxMessages` is maximum number of messages in one `SendTransaction` that the wallet supports type ConnectItemReply = TonAddressItemReply | TonProofItemReply; // Untrusted data returned by the wallet. // If you need a guarantee that the user owns this address and public key, you need to additionally request a ton_proof. type TonAddressItemReply = { name: "ton_addr"; address: string; // TON address raw (`0:`) network: NETWORK; // network global_id publicKey: string; // HEX string without 0x walletStateInit: string; // Base64 (not url safe) encoded stateinit cell for the wallet contract } type TonProofItemReply = { name: "ton_proof"; proof: { timestamp: string; // 64-bit unix epoch time of the signing operation (seconds) domain: { lengthBytes: number; // AppDomain Length value: string; // app domain name (as url part, without encoding) }; signature: string; // base64-encoded signature payload: string; // payload from the request } } // Currently supports only the mainnet enum NETWORK { MAINNET = '-239', TESTNET = '-3' } ``` ### Example Just to obtain the user's address, public key, and other information: ```js const result = await window.okxTonWallet.tonconnect.connect(2, { manifestUrl: 'https://example.com/manifest.json', items: [{ name: 'ton_addr' }] }) if (result.event === 'connect') { console.log(result.payload.items[0].address) } else { console.log(result.payload.message) } ``` Obtain the user's address, public key, and other information, and verify the wallet with a signature: ```js const result = await window.okxTonWallet.tonconnect.connect(2, { manifestUrl: 'https://example.com/manifest.json', items: [ { name: 'ton_addr' }, { name: 'ton_proof', payload: '123' } ] }) if(result.event === 'connect') { console.log(result.payload.items[0].address) console.log(result.payload.items[1].proof) } else { console.log(result.payload.message) } ``` ## restoreConnection Method to restore the connection, only returns the result of the `ton_addr` instruction. If the wallet cannot be connected, an error is returned. ```ts restoreConnection(): Promise; ``` ### Example ```js const result = await window.okxTonWallet.tonconnect.restoreConnection() if(result.event === 'connect') { console.log(result.payload.items[0].address) } else { console.log(result.payload.message) } ``` ## send Method to send a message to the wallet. ```ts send(message: AppRequest): Promise; ``` ### Parameters * `message`: Message body sent to the wallet **message parameter** ```ts interface AppRequest { method: string; params: string[]; id: string; } ``` * `method`: Name of the message, currently supports `sendTransaction` and `disconnect` * `params`: Parameters of the message * `id`: Incremental identifier to match requests and responses ### sendTransaction message Used to sign and broadcast transactions. **Parameters:** ```ts interface SendTransactionRequest { method: 'sendTransaction'; params: []; id: string; } ``` Where `` is JSON with following properties: * `valid_until`(integer, optional): unix timestamp. after th moment transaction will be invalid. * `network`(NETWORK, optional): Currently supports only the mainnet * `from`(string in wc:hex format, optional): The sender address from which DAppintends to send the transaction. * `messages`(array of messages): 1-4 outgoing messages from the wallet contract to other accounts. All messages are sent out in order, however the wallet cannot guarantee that messages will be delivered and executed in same order. Message structure: * `address` (string): message destination * `amount` (decimal string): number of nanocoins to send. * `payload` (string base64, optional): raw one-cell BoC encoded in Base64. * `stateInit` (string base64, optional): raw once-cell BoC encoded in Base64. Example: ```json { "valid_until": 1658253458, "network": "-239", "from": "0:348bcf827469c5fc38541c77fdd91d4e347eac200f6f2d9fd62dc08885f0415f", "messages": [ { "address": "0:412410771DA82CBA306A55FA9E0D43C9D245E38133CB58F1457DFB8D5CD8892F", "amount": "20000000", "stateInit": "base64bocblahblahblah==" //deploy contract },{ "address": "0:E69F10CC84877ABF539F83F879291E5CA169451BA7BCE91A37A5CED3AB8080D3", "amount": "60000000", "payload": "base64bocblahblahblah==" //transfer nft to new deployed account 0:412410771DA82CBA306A55FA9E0D43C9D245E38133CB58F1457DFB8D5CD8892F } ] } ``` **Return value:** ```ts type SendTransactionResponse = SendTransactionResponseSuccess | SendTransactionResponseError; interface SendTransactionResponseSuccess { result: ; id: string; } interface SendTransactionResponseError { error: { code: number; message: string }; id: string; } ``` Where result is the signed signature string. ### disconnect message Used to disconnect the wallet. **Parameters:** ```ts interface DisconnectRequest { method: 'disconnect'; params: []; id: string; } ``` **Return value:** ```ts type DisconnectResponse = DisconnectResponseSuccess | DisconnectResponseError; interface DisconnectResponseSuccess { result: {}; id: string; } interface DisconnectResponseError { error: { code: number; message: string }; id: string; } ``` ## listen Method to listen to wallet events. ```ts listen(callback: (event: WalletEvent) => void): () => void; ``` ### Parameters * `callback`: method to listen to wallet events. ```ts interface WalletEvent { event: WalletEventName; id: number; // increasing event counter payload: ; // specific payload for each event } type WalletEventName = 'connect' | 'connect_error' | 'disconnect'; ``` ### Return value Returns a function to cancel the listening. ## on / off Add/remove event listeners. Currently supported events include: - `connect`: This event is triggered when the wallet is connected. - `disconnect`: This event is triggered when the user disconnects. - `accountChanged`: This event is triggered when the user switches accounts. ```js const accountChanged = () => {} window.okxTonWallet.tonconnect.on('accountChanged', accountChanged) window.okxTonWallet.tonconnect.off('accountChanged', accountChanged) ``` - [Aptos/Movement](https://web3.okx.com/onchainos/dev-docs/sdks/chains/aptos/introduce.md) # Aptos/Movement Aptos is a layer 1 public blockchain project that aims to develop a safe, scalable, and upgradeable Web3 infrastructure. Developed by former engineers from the Facebook crypto project Diem (formerly Libra), Aptos contracts are written using Move. Common Aptos-compatible networks include Movement. - [Provider API](https://web3.okx.com/onchainos/dev-docs/sdks/chains/aptos/provider.md) # Provider API ## Aptos-AIP-62 The [AIP-62](https://aptos.dev/en/build/sdks/wallet-adapter/wallets) standard, introduced by Aptos for wallet connectivity, is already supported by the OKX wallet. ## What is injected provider API? The OKX injected provider API is a JavaScript API that OKX injects into websites visited by our users. Your DApp can use this API to request users' accounts, read data from blockchains users are connected to, and help users sign messages and transactions. ## Connecting to OKX Wallet `window.okxwallet.aptos.connect()` **Description** You can connect to OKX Wallet by calling `window.okxwallet.aptos.connect()` When `window.okxwallet.aptos.connect()` has been successfully called, the OKX Wallet connection page will be displayed. You can decide whether to connect to the current DApp or not. If you agree to connect, the `address` and `publicKey` key will be returned. ```javascript try { const response = await window.okxwallet.aptos.connect(); console.log(response); // { address: string, publicKey: string } } catch (error) { console.log(error); // { code: 4001, message: "User rejected the request."} } ``` **Example** Open in [codeopen](https://codepen.io/okxwallet/pen/NWLbxKx). ```html ``` ```javascript const connectAptosButton = document.querySelector('.connectAptosButton'); connectAptosButton.addEventListener('click', () => { try { const response = await window.okxwallet.aptos.connect(); console.log(response); // { address: string, publicKey: string } } catch (error) { console.log(error); // { code: 4001, message: "User rejected the request."} } }); ``` ## Get acount information `window.okxwallet.aptos.account()` **Description** Calling `window.okxwallet.aptos.account()` will retrieve the account information of the current 'Dapp' and return the `address` and `public` key`. ```typescript const account = await window.okxwallet.aptos.account(); // { address: string, publicKey: string } ``` **Example** Open in [codeopen](https://codepen.io/lsbwfyzl-the-reactor/pen/QWXpgZo) ```html ``` ```javascript const connectAptosButton = document.querySelector('.connectAptosButton'); const accountAptosButton = document.querySelector('.accountAptosButton'); connectAptosButton.addEventListener('click', async () => { try { const response = await window.okxwallet.aptos.connect(); console.log(response); // { address: string, publicKey: string } } catch (error) { console.log(error); // { code: 4001, message: "User rejected the request."} } }); accountAptosButton.addEventListener('click', async () => { const account = await window.okxwallet.aptos.account(); console.log(account); // { address: string, publicKey: string } }); ``` ## Get Current Network `window.okxwallet.aptos.network()` **Description** Calling `window.okxwallet.aptos.network()` will retrieve the network information of the current 'Dapp' and return the `network name`. ```typescript const network = await window.okxwallet.aptos.network(); // 'Mainnet' ``` ```typescript // We support network: `Mainnet` | `Movement Mainnet` | `Movement Testnet` enum Network { Mainnet = 'Mainnet' MovementMainnet = 'Movement Mainnet' MovementTestnet = 'Movement Testnet' } ``` **Example** Open in [codeopen](https://codepen.io/lsbwfyzl-the-reactor/pen/dyBvzGJ) ```html ``` ```javascript const connectAptosButton = document.querySelector('.connectAptosButton'); const networkAptosButton = document.querySelector('.networkAptosButton'); connectAptosButton.addEventListener('click', async () => { try { const response = await window.okxwallet.aptos.connect(); console.log(response); // { address: string, publicKey: string } } catch (error) { console.log(error); // { code: 4001, message: "User rejected the request."} } }); networkAptosButton.addEventListener('click', async () => { const network = await window.okxwallet.aptos.network(); console.log(network); // 'Mainnet' }); ``` ## Signing transactions `window.okxwallet.aptos.signAndSubmitTransaction(transaction)` **Description** In OKX Wallet, you can use `window.okxwallet.aptos.signAndSubmitTransaction(transaction)` to trigger a transaction on the Aptos chain. This function will return a `pendingTransaction` for DApps. ```javascript const transaction = { arguments: [address, '717'], function: '0x1::coin::transfer', type: 'entry_function_payload', type_arguments: ['0x1::aptos_coin::AptosCoin'], }; try { const pendingTransaction = await window.okxwallet.aptos.signAndSubmitTransaction(transaction); const client = new AptosClient('https://fullnode.mainnet.aptoslabs.com/'); const txn = await client.waitForTransactionWithResult( pendingTransaction.hash, ); } catch (error) { // see "Errors" } ``` Of course, it is also possible to simply sign the transaction without initiating an on-chain operation using `window.okxwallet.aptos.signTransaction(transaction)`. This method will return a signed buffer. This method is uncommon and unsafe for users, and isn't recommended. ```javascript const transaction = { arguments: [address, '717'], function: '0x1::coin::transfer', type: 'entry_function_payload', type_arguments: ['0x1::aptos_coin::AptosCoin'], }; try { const signTransaction = await window.okxwallet.aptos.signTransaction(transaction); } catch (error) { // see "Errors" } ``` **Example** Open in [codeopen](https://codepen.io/okxwallet/pen/qBMqbbJ). ```html ``` ```javascript const connectAptosButton = document.querySelector('.connectAptosButton'); const signTransactionButton = document.querySelector('.signTransactionButton'); let address=''; signTransactionButton.addEventListener('click', async() => { try { const transaction = { arguments: [address, '717'], function: '0x1::coin::transfer', type: 'entry_function_payload', type_arguments: ['0x1::aptos_coin::AptosCoin'], }; const pendingTransaction = await window.okxwallet.aptos.signAndSubmitTransaction(transaction); console.log(pendingTransaction); } catch (error) { console.log(error) } }); connectAptosButton.addEventListener('click', async() => { console.log(res); const res = await window.okxwallet.aptos.connect(); address = res.address; }); ``` ## Signing messages `window.okxwallet.aptos.signMessage(message)` **Description** DApps can call `window.okxwallet.aptos.signMessage(message)` to sign messages. If you agree to sign, OKX Wallet will return the successfully signed message, signature, input parameters, and return message. The data structure is shown below. **Parameters** ```typescript interface SignMessagePayload { address?: boolean; // Should we include the address of the account in the message application?: boolean; // Should we include the domain of the DApp chainId?: boolean; // Should we include the current chain id the wallet is connected to message: string; // The message to be signed and displayed to the user nonce: string; // A nonce the DApp should generate } ``` **Return value** ```typescript interface SignMessageResponse { address: string; application: string; chainId: number; fullMessage: string; // The message that was generated to sign message: string; // The message passed in by the user nonce: string; prefix: string; // Should always be APTOS signature: string; // The signed full message } ``` **Example** Open in [codeopen](https://codepen.io/okxwallet/pen/RwYorBP). ```html ``` ```javascript const connectAptosButton = document.querySelector('.connectAptosButton'); const signButton = document.querySelector('.signButton'); const signMessagePayload = { message: 'hello okx', nonce: 'okx' }; signButton.addEventListener('click', async() => { try { const signMessage = await window.okxwallet.aptos.signMessage(signMessagePayload) console.log(signMessage); // {"signature": string, "prefix": "APTOS", "fullMessage": "APTOS nonce: okx message: hello okx", "message": "hello okx", "nonce": "okx" } } catch (error) { // see "Errors" } }); connectAptosButton.addEventListener('click', () => { connetAccount(); }); async function connetAccount() { const res = await window.okxwallet.aptos.connect(); console.log(res); } ``` ## Signing Message Verification ```javascript import nacl from 'tweetnacl'; const message = 'hello'; const nonce = 'random_string'; try { const response = await window.okxwallet.aptos.signMessage({ message, nonce, }); const { publicKey } = await window.okxwallet.aptos.account(); // Remove the 0x prefix const key = publicKey!.slice(2, 66); const verified = nacl.sign.detached.verify( Buffer.from(response.fullMessage), Buffer.from(response.signature, 'hex'), Buffer.from(key, 'hex'), ); console.log(verified); } catch (error) { console.error(error); } ``` ## Events **Switching accounts** When you switch OKX Wallet accounts, it's necessary to listen to the wallet switching event: `onAccountChange` When you switch wallet accounts, your current account must have an `Aptos` address to trigger this event. ```typescript let currentAccount = await window.okxwallet.aptos.account(); // event listener for disconnecting window.okxwallet.aptos.onAccountChange((newAccount) => { // If the new account has already connected to your app then the newAccount will be returned if (newAccount) { currentAccount = newAccount; } else { // Otherwise you will need to ask to connect to the new account currentAccount = window.okxwallet.aptos.connect(); } }); ``` **Disconnecting from OKX Wallet** When OKX Wallet disconnects (OKX Wallet is a multi-chain wallet, so this event will also be triggered when you switch to an account that doesn't have an `Aptos` address): ```typescript // get current connection status let connectionStatus = await window.okxwallet.aptos.isConnected(); // event listener for disconnecting window.okxwallet.aptos.onDisconnect(() => { connectionStatus = false; }); ``` **onNetworkChange()** The DApp needs to ensure that the user is connected to the target network, so it needs to get the current network, switch networks, and listen for network changes. ```typescript // Current network let network = await window.okxwallet.aptos.network(); // event listener for network changing window.bitkeep.aptos.onNetworkChange((newNetwork) => { network = newNetwork; // { networkName: 'Mainnet' } }); ``` **Example** open in [codeopen](https://codepen.io/okxwallet/pen/PodbZEN). ```html ``` ```javascript const connectAptosButton = document.querySelector('.connectAptosButton'); window.okxwallet.aptos.on('connect',()=>{ console.log('got connect event'); }) connectAptosButton.addEventListener('click', async() => { try { const res = await window.okxwallet.aptos.connect(); console.log(res); // { address: string, publicKey: string } } catch (error) { console.log(error); // { code: 4001, message: "User rejected the request."} } }); ``` - [Cosmos/Sei](https://web3.okx.com/onchainos/dev-docs/sdks/chains/cosmos/introduce.md) # Cosmos/Sei The Cosmos network consists of many independent, parallel blockchains, called zones, each powered by classical Byzantine fault-tolerant (BFT) consensus protocols like Tendermint (already used by platforms like ErisDB). Some zones act as hubs with respect to other zones, allowing many zones to interoperate through a shared hub. The architecture is a more general application of the Bitcoin sidechains concept, using classic BFT and Proof-of-Stake algorithms, instead of Proof-of-Work. Cosmos can interoperate with multiple other applications and cryptocurrencies, something other blockchains can't do well. By creating a new zone, you can plug any blockchain system into the Cosmos hub and pass tokens back and forth between those zones, without the need for an intermediary. - [Provider API](https://web3.okx.com/onchainos/dev-docs/sdks/chains/cosmos/provider.md) # Provider API ## What is injected provider API? The OKX injected provider API is a JavaScript API that OKX injects into websites visited by our users. Your DApp can use this API to request users' accounts, read data from blockchains users are connected to, and help users sign messages and transactions. **Note**: Cosmos is only supported on the OKX browser extension. ## Connecting to OKX Wallet `window.okxwallet.keplr.enable(chainIds)` **Description** If OKX Wallet is locked, you can unlock the wallet by using `window.keplr.enable(chainIds)`. You'll be required to grant the webpage permission to access `Keplr` if such permission wasn't previously granted. The `enable` method can receive one or more chain IDs as an array. When passing the chain ID array, you can simultaneously request the permissions of all chains that haven't been authorized. If you cancel the unlocking or are denied permission, an error will show. ```typescript enable(chainIds: string | string[]): Promise ``` **Example** Open in [codeopen](https://codepen.io/okxwallet/pen/qBMRrEo). ```html ``` ```javascript const connectCosmosButton = document.querySelector('.connectCosmosButton'); connectCosmosButton.addEventListener('click', async() => { try { const chainId = "cosmoshub-4"; // Enabling before using the Keplr is recommended. // This method will ask the user whether to allow access if they haven't visited this website. // Also, it will request that the user unlock the wallet if the wallet is locked. await window.okxwallet.keplr.enable(chainId); console.log(res); } catch (error) { console.log(error); } }); ``` ## Signing transactions `window.okxwallet.keplr.signAmino(chainId, signer, signDoc)` **Description** This request signs in a fixed format, similar to the `signAmino` method of `OfflineSigner` of `cosmjs`. Parameters are objects, and `signDoc` is a fixed format. ```typescript window.okxwallet.keplr.signAmino(chainId: string, signer: string, signDoc: StdSignDoc, signOptions: any): Promise ``` **Example** Open in [codeopen](https://codepen.io/okxwallet/pen/PodWmJm). ```html ``` ```javascript const connectCosmosButton = document.querySelector('.connectCosmosButton'); const signTransactionButton = document.querySelector('.signTransactionButton'); signTransactionButton.addEventListener('click', async() => { try { const res = await window.okxwallet.keplr.signAmino( "osmosis-1", "osmo1sxqwesgp7253fdv985csvz95fwc0q53ulldggl", { account_number: "707744", chain_id: "osmosis-1", fee: { gas: "500000", amount: [ { denom: "uosmo", amount: "12500" } ] }, memo: "", msgs: [ { type: "osmosis/gamm/swap-exact-amount-in", value: { routes: [ { pool_id: "795", token_out_denom: "uosmo" }, { pool_id: "1", token_out_denom: "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2" } ], sender: "osmo1sxqwesgp7253fdv985csvz95fwc0q53ulldggl", token_in: { amount: "10000", denom: "ibc/2DA9C149E9AD2BD27FEFA635458FB37093C256C1A940392634A16BEA45262604" }, token_out_min_amount: "553" } } ], sequence: "54" } ); console.log(res); } catch (error) { console.log(error) } }); connectCosmosButton.addEventListener('click', async() => { try { const chainId = "cosmoshub-4"; // Enabling before using the Keplr is recommended. // This method will ask the user whether to allow access if they haven't visited this website. // Also, it will request that the user unlock the wallet if the wallet is locked. const res = await window.keplr.enable(chainId); console.log(res); } catch (error) { console.log(error); } }); ``` ## Signing messages `window.okxwallet.keplr.signArbitrary(chainId, signer, data)` **Description** This request will sign any information, which is equivalent to the `signMessage (any)` of the previous chains. ```typescript signArbitrary( chainId: string, signer: string, data: string | Uint8Array ): Promise; verifyArbitrary( chainId: string, signer: string, data: string | Uint8Array, signature: StdSignature ): Promise; ``` **Example** Open in [codeopen](https://codepen.io/okxwallet/pen/NWLdgKL). ```html ``` ```javascript const connectCosmosButton = document.querySelector('.connectCosmosButton'); const signMessageButton = document.querySelector('.signMessageButton'); signMessageButton.addEventListener('click', async() => { try { const res = await window.okxwallet.keplr.signArbitrary({ "osmosis-1", "osmo1sxqwesgp7253fdv985csvz95fwc0q53ulldggl", 'test cosmos' } ); console.log(res); } catch (error) { console.log(error) } }); connectCosmosButton.addEventListener('click', async() => { try { const chainId = "cosmoshub-4"; // Enabling before using the Keplr is recommended. // This method will ask the user whether to allow access if they haven't visited this website. // Also, it will request that the user unlock the wallet if the wallet is locked. const res = await window.keplr.enable(chainId); console.log(res); } catch (error) { console.log(error); } }); ``` ## Events **Connecting to OKX Wallet** You can connect to OKX Wallet by calling `window.okxwallet.keplr.enable(chainId)`. When the user approves the connection request, the connection event will be triggered. **Usage** ```typescript window.okxwallet.keplr.on("connect", () => console.log("connected!")); ``` **Example** Open in [codeopen](https://codepen.io/okxwallet/pen/QWVdpzp). ```html ``` ```javascript const connectCosmosButton = document.querySelector('.connectCosmosButton'); window.okxwallet.keplr.on("connect", () => console.log("connected!")); connectCosmosButton.addEventListener('click', () => { try { const chainId = "cosmoshub-4"; // Enabling before using the Keplr is recommended. // This method will ask the user whether to allow access if they haven't visited this website. // Also, it will request that the user unlock the wallet if the wallet is locked. const res = await window.okxwallet.keplr.enable(chainId); console.log(res); } catch (error) { console.log(error); } }); ``` - [SUI](https://web3.okx.com/onchainos/dev-docs/sdks/chains/sui/introduce.md) # SUI Sui (or Sui Network) is the first Layer 1 blockchain designed from the ground up to enable creators and developers to build experiences that cater for the next billion users in Web3. Sui is horizontally scalable to support a wide range of DApp development with fast speeds and low costs. The platform brings users a general-purpose blockchain with high throughput, instant settlement speeds, rich on-chain assets, and user-friendly Web3 experiences. Sui is a step-function advancement in blockchain, designed from the bottom up to meet the needs of everyone involved in crypto. - [Provider API](https://web3.okx.com/onchainos/dev-docs/sdks/chains/sui/provider.md) # Provider API ## What is injected provider API? The OKX injected provider API is a JavaScript API that OKX injects into websites visited by our users. Your DApp can use this API to request users' accounts, read data from blockchains users are connected to, and help users sign messages and transactions. ## Obtaining the wallet object We use the wallet standard in Sui, which is slightly different from other heterogeneous chains. You can obtain the wallet object through event notifications: ```typescript const GlobalWallet = { register: (wallet) => { GlobalWallet[wallet.chainName] = wallet } } const event = new CustomEvent('wallet-standard:app-ready', { detail: GlobalWallet }); window.dispatchEvent(event); const suiWallet = GlobalWallet.suiMainnet ``` ## Obtaining the account Using the suiWallet object obtained above, you can retrieve the account: ```typescript const suiAccounts = suiWallet.connectedAccounts // Structure of suiAccounts: [ { "address": "0x7995ca23961fe06d8cea7da58ca751567ce820d7cba77b4a373249034eecca4a", "publicKey": "tUvCYrG22rHKR0c306MxgnhXOSf16Ot6H3GMO7btwDI=", "chains": [ "sui:mainnet" ], "features": [ "sui:signAndExecuteTransactionBlock", "sui:signTransactionBlock", "sui:signMessage" ] } ] ``` ## The first transaction `suiWallet.features['sui:signAndExecuteTransactionBlock'].signAndExecuteTransactionBlock` **Signing and sending transactions** The Sui wallet follows the wallet standard, which is slightly different from other heterogeneous chains. All methods are attached to the features[] array. After creating a transaction, the web application may request you to sign and send the transaction using OKX Wallet. If accepted, OKX Wallet will sign the transaction with your private key and submit it through the SUI JSON RPC connection. Calling the signAndExecuteTransactionBlock method on suiWallet will return a Promise for the signed transaction. ```typescript const handleTransaction = async () => { const tx = new TransactionBlock() tx.moveCall({ target: `${packageId}::${moduleName}::${functionName}`, arguments: [ tx.pure(params1), tx.pure(params2), ], typeArguments: [], }) const result = await suiWallet.features['sui:signAndExecuteTransactionBlock'].signAndExecuteTransactionBlock({ transactionBlock: tx, options: { showEffects: true }, }) console.log('result', result) // You can retrieve the transaction status by accessing result?.effects?.status?.status. If the transaction is successful, the status will be 'success', and if it fails, the status will be 'failure'. } ``` **splitCoins** When sending a transaction, and the object used for paying gas fees is also included in the transaction, a technique called splitting coins is employed to handle this scenario. ```typescript const handleTransaction = async () => { const tx = new TransactionBlock() const value = '300000000' // This is the desired value to split const [coins] = tx.splitCoins(tx.gas, [ tx.pure(BigInt(value)), ]) tx.moveCall({ target: `${packageId}::${moduleName}::${functionName}`, arguments: [ tx.pure(params1), tx.pure(params2), tx.makeMoveVec({ objects: [coins] }), ], typeArguments: [], }) const result = await suiWallet.features['sui:signAndExecuteTransactionBlock'].signAndExecuteTransactionBlock({ transactionBlock: tx, options: { showEffects: true }, }) console.log('result', result) } ``` **Signing a transaction block** You can sign a transaction block (a collection of multiple transactions) using the signTransactionBlock method on the provider. ```typescript const tx = new TransactionBlock(); tx.moveCall({ target: 'xxx', arguments: [ tx.pure('okx'), tx.pure('wallet'), ], }); const input = { transactionBlockSerialized: tx.serialize(), options: { showEffects: true, } }l const transaction = await suiWallet.features['sui:signTransactionBlock'].signTransactionBlock(input); ``` ## Signing messages **Signing a single transaction (without sending)** After creating a transaction, a web application may request your OKX Wallet to sign the transaction without submitting it to the network. Calling the signMessage method will return a Promise for the signed transaction. ```typescript import { ethers } from 'ethers'; // Here we utilize the ethers library to help us handle the message and convert it to Uint8Array type const message = ethers.utils.toUtf8Bytes('okx') const { signature, messageBytes } = await suiWallet.features['sui:signMessage'].signMessage({ message }) ``` ### Error codes |
Code
|
Title
| Description | |:-------------------|:------------------------------|:-----| | 4900 | Disconnected | OKX Wallet could not connect to the network | | 4100 | Unauthorized | The requested method and/or account has not been authorized by the user | | 4001 | User rejected request | The user rejected the request through OKX Wallet | | -32000 | Invalid Input | Missing or invalid parameters | | -32002 | Resource unavailable | This error occurs when a DApp attempts to submit a new transaction while OKX Wallet's approval dialog is already open for a previous transaction. Only one approve window can be open at a time. Users should approve or reject their transaction before initiating a new one. | | -32003 | Transaction rejected | OKX Wallet does not recognize a valid transaction | | -32601 | Method not found | OKX Wallet does not recognize the method | | -32603 | Internal error | Something went wrong within OKX Wallet | ## Connect account `suiWallet.features['standard:connect'].connect()` **Description** Connecting to OKX Wallet can be done by calling `suiWallet.features['standard:connect'].connect()`. The connect call will return a Promise object that resolves if you accept the connection request, or rejects if you reject the request . For more information on possible errors that may occur with OKX Wallet, refer to the error codes section. Once you accept the connection request, the suiWallet.features['standard:events'] will also trigger a connection event. ```typescript suiWallet.features['standard:events'].on("connect", () => console.log("connected!")); ``` Once the web application is connected to OKX Wallet, it'll be able to read the public key of the connected account and prompt you for further transactions. **Example** Open in [codeopen](https://codepen.io/okxwallet/pen/RweEpKL)。 ## Events **Connection successful** Connecting to OKX Wallet can be done by calling `suiWallet.features['standard:events'].on`. The connection event is triggered when you accept the connection request. **Usage** ```typescript suiWallet.features['standard:events'].on("connect", () => console.log("connected!")); ``` **Disconnect** Disconnecting is similar to the connecting process. However, disconnection can also be initiated by the wallet in addition to the application. **Usage** ```typescript suiWallet.features['standard:events'].on("disconnect", () => { console.log("disconnected!") }); ``` **Switching accounts** OKX Wallet allows you to seamlessly manage multiple accounts from a single extension or mobile application. Whenever you switch accounts, OKX Wallet will emit an accountChanged event. If you switch accounts while already connected to an application, and the new account has allowlisted the application, you will remain connected and OKX Wallet will pass the public key of the new account. **Usage** ```typescript suiWallet.features['standard:events'].on('accountChanged', (publicKey) => { if (publicKey) { console.log(`Switched to account ${publicKey.toBase58()}`); } }); ``` - [Stacks](https://web3.okx.com/onchainos/dev-docs/sdks/chains/stacks/introduce.md) # Stacks Stacks is a layer-1 blockchain that allows dApps in the DeFi, NFT and smart contract space built on top of Bitcoin. This allows Stacks to leverage Bitcoin's security and stability while allowing developers to build native dApps on top of the Layer 1. - [Provider API](https://web3.okx.com/onchainos/dev-docs/sdks/chains/stacks/provider.md) # Provider API ## What is injected provider API? The OKX injected provider API is a JavaScript API that OKX injects into websites visited by our users. Your DApp can use this API to request users' accounts, read data from blockchains users are connected to, and help users sign messages and transactions. ## Connecting to OKX Wallet `window.okxwallet.stacks.connect()` **Description** Connect to OKX Wallet by calling `window.okxwallet.stacks.connect()` When `window.okxwallet.stacks.connect()` has been successfully called, the OKX Wallet connection page will be displayed. You decide whether to connect to the current DApp or not. If you agree to connect, the `address` and `publicKey` key will be returned. ```javascript try { const response = await window.okxwallet.stacks.connect(); console.log(response); // { address: string, publicKey: string } } catch (error) { console.log(error); // { code: 4001, message: "User rejected the request."} } ``` ## Calling contracts `window.okxwallet.stacks.signTransaction(transaction)` **Parameters** - transaction - object - stxAddress - string: The STX address of the currently connected wallet - txType - string: Transaction type, which must be `contract_call` - contractName - string: Contract name - contractAddress - string: Contract address - functionName - string: Function name - functionArgs - array<string>: Hexadecimal function call parameters - postConditionMode - number: Whether to allow postconditions (optional) - 1: Allow - 2: Refuse - postConditions - array<string>: Parameters of postconditions (optional) - anchorMode - number: (Not required)how a transaction should get appended to the Stacks blockchain (optional) - 1: The transaction MUST be included in an anchored block - 2: The transaction MUST be included in a microblock - 3: The leader can choose where to include the transaction (anchored block or microblock) **Return value** - result - object - txHash - string: Transaction hash - signature - string: Signature of transaction ```javascript try { const transaction = { "stxAddress": "", "txType": "contract_call", "contractName": "amm-swap-pool-v1-1", "contractAddress": "SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9", "functionName": "swap-helper", "functionArgs": [ "0616e685b016b3b6cd9ebf35f38e5ae29392e2acd51d0a746f6b656e2d77737478", "0616e685b016b3b6cd9ebf35f38e5ae29392e2acd51d176167653030302d676f7665726e616e63652d746f6b656e", "0100000000000000000000000005f5e100", "01000000000000000000000000000f4240", "0a010000000000000000000000000078b854" ], "postConditionMode": 2, "postConditions": [ "000216c03b5520cf3a0bd270d8e41e5e19a464aef6294c010000000000002710", "010316e685b016b3b6cd9ebf35f38e5ae29392e2acd51d0f616c65782d7661756c742d76312d3116e685b016b3b6cd9ebf35f38e5ae29392e2acd51d176167653030302d676f7665726e616e63652d746f6b656e04616c657803000000000078b854" ], "anchorMode": 3, }; const {txHash, signature} = await window.okxwallet.stacks.signTransaction(transaction); console.location({txHash, signature}); } catch (error) { console.log(error); } ``` ## Transfers **Parameters** - transaction - object - stxAddress - string: The STX address of the currently connected wallet - txType - string: transaction type, which must be `token_transfer` - recipient - string: Recipient address - amount - string: Number of STX to send - memo - string: Memo of transaction (optional) - anchorMode - number: How a transaction should get appended to the Stacks blockchain (optional) - 1: The transaction MUST be included in an anchored block - 2: The transaction MUST be included in a microblock - 3: The leader can choose where to include the transaction (anchored block or microblock) **Return value** - result - object - txHash - string: Transaction hash - signature - string: Signature of transaction ```javascript try { const transaction = { stxAddress: '', txType: 'token_transfer', recipient: '', amount: '10000', memo: 'test' }; const {txHash, signature} = await window.okxwallet.stacks.signTransaction(transaction); console.location({txHash, signature}); } catch (error) { console.log(error); } ``` ## Signing messages `window.okxwallet.stacks.signMessage(data)` **Parameters** - data - object - message - string: Signed data required **Return value** - result - object - publicKey - string: The public key that verifies the signature - signature - string: Signature of data ```javascript try { const data = { message: '1234' }; const {publicKey, signature} = await window.okxwallet.stacks.signMessage(data); console.location({publicKey, signature}); } catch (error) { console.log(error); } ``` - [Starknet](https://web3.okx.com/onchainos/dev-docs/sdks/chains/starknet/introduce.md) # Starknet Starknet is a Validity-Rollup (aka ZK-Rollup) Layer 2 network that operates on top of Ethereum, enabling dApps to massively scale without compromising on security. It achieves this by bundling transactions into an off-chain computed STARK proof. This proof is then submitted to Ethereum as a single transaction, resulting in significantly higher throughput, faster processing times, and much lower costs, all while retaining the robust security of the Ethereum settlement layer. - [Provider API](https://web3.okx.com/onchainos/dev-docs/sdks/chains/starknet/provider.md) # Provider API ## What is injected provider API? The OKX injected provider API is a JavaScript API that OKX injects into websites visited by our users. Your DApp can use this API to request users' accounts, read data from blockchains users are connected to, and help users sign messages and transactions. ## The injected object DApps can access the injected object with two methods, which are: - `window.okxwallet.starknet` - `window.starknet_okxwallet` All two attributes point to the same object, and these two methods are provided for the convenience of DApp usage. If a DApp wishes to directly access the Starknet object injected by OKX Wallet, it can simply use `window.okxwallet.starknet` or `window.starknet_okxwallet`. This helps avoid unintentional references to Starknet objects injected by other wallets. If a DApp utilizes third-party tool libraries like [get-starknet](https://github.com/starknet-io/get-starknet), it'll also be fully supported. ## The properties and methods of the injected object 1. `name` - string: Name of the wallet with a value of 'OKX Wallet' 2. `icon` - string: Wallet icon. 3. `version` - string: The version. 4. `isConnected` - boolean: Properties and methods of the injected object. 5. `selectedAddress` - string: The currently selected wallet address 6. `account` - Account: Accesses the account object, inherited from [Account](https://www.starknetjs.com/docs/API/#account) of starknet.js. For specific properties and methods on the instance, please refer to the starknet.js documentation. 7. `chainId` - string: Supports only the mainnet, with a value of `SN_MAIN`. 8. `provider` - Provider: Accesses the provider object, utilizing [RpcProvider](https://www.starknetjs.com/docs/API/classes/RpcProvider) of starknet.js. For specific properties and methods on the instance, please consult the starknet.js documentation. 9. `enable` - () => [string]: Used for wallet connection, upon successful invocation, it'll trigger the connection page of OKX Wallet, where you can decide whether to connect to the current DApp or not. If you agree to connect, a one-item array with the selected address will be returned. 10. `on` - (event, callback) => void: Add event listener - `accountsChanged` event: This event is triggered when you switch accounts, returning an array with the new address. When the connection is severed, an empty array will be returned. 11. `off` - (event, callback) => void: Remove event listener ## Simple example of connecting to a wallet ```js async function connect() { if(window.okxwallet.starknet.isConnected) { return } try { const [address] = await window.okxwallet.starknet.enable() console.log(address) console.log(window.okxwallet.starknet.account) console.log(window.okxwallet.starknet.selectedAddress) console.log(window.okxwallet.starknet.isConnected) window.okxwallet.starknet.on('accountsChanged', ([addr]) => { if (addr) { console.log('switched address') } else { console.log('disconnected') } }) } catch (e) { console.error(e) } } ``` ## Calling contracts `window.okxwallet.starknet.account.execute(transactions [, abi])` This can execute one or more calls. If there is only one call, `transactions` will be an object, and its contained attributes will be explained below. If there are multiple calls, there'll be an array of objects. ### Parameters `transactions` structure of the object is as follows: - `contractAddress` - string: Contract address. - `entrypoint` - string: Contract entrypoint. - `calldata` - array: The calldata - `signature` - array: The signature `abi` - Contract ABI (Application Binary Interface), optional. ### Return value - `result` - object - `transaction_hash` - string: Transaction hash ```js const transaction = { "contractAddress": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "calldata": [ "3055261660830722006547698919883585605584552967779072711973046411977660833095", "100000000000000", "0" ], "entrypoint": "transfer" } const result = await window.okxwallet.starknet.account.execute(transaction) ``` ## Signing messages `window.okxwallet.starknet.account.signMessage(data)` ### Parameters - `data` - object: The object to be signed. ### Return value - `signature` - string[]: The result of the signature, which includes two items. ```js let data = { "domain": { "name": "OKX", "chainId": "SN_MAIN", "version": "0.0.1" }, "types": { "StarkNetDomain": [ { "name": "name", "type": "felt" } ], "Message": [ { "name": "message", "type": "felt" } ] }, "primaryType": "Message", "message": { "message": "hello" } } const [r, s] = await window.okxwallet.starknet.account.signMessage(data) ``` For additional properties and methods on `starknet.account` and `starknet.provider`, please refer to the [starknet.js documentation](https://www.starknetjs.com/docs/API/). - [Cardano](https://web3.okx.com/onchainos/dev-docs/sdks/chains/cardano/introduce.md) # Cardano Cardano is a blockchain platform that aims to improve on the features of Ethereum and Bitcoin. It uses a proof-of-stake consensus mechanism that is energy-efficient and scalable. Cardano is developed using a peer-reviewed and evidence-based approach by a team of experts. Cardano supports smart contracts and decentralized applications, and has undergone several upgrades to enhance its capabilities. - [Provider API](https://web3.okx.com/onchainos/dev-docs/sdks/chains/cardano/provider.md) # Provider API ## What is injected provider API? The OKX injected provider API is a JavaScript API that OKX injects into websites visited by our users. Your DApp can use this API to request users' accounts, read data from blockchains users are connected to, and help users sign messages and transactions. ## The injected object DApps can access the injected object with two methods, which are: - `window.okxwallet.cardano` - `window.cardano.okxwallet` All two attributes point to the same object, and these two methods are provided for the convenience of DApp usage. ## The properties and methods of the injected object 1. `name` - string: Name of the wallet with a value of 'OKX Wallet'. 2. `icon` - string: Wallet icon. 3. `apiVersion` - string: The version. 4. `isEnabled` - () => Promise\: Returns true if the dApp is already connected to the user's wallet, and false otherwise.If this function returns true, then any subsequent calls to wallet.enable() during the current session should succeed and return the API object. 5. `enable` - () => Promise\: The wallet should request the user's permission to connect the web page to the user's wallet, and if permission has been granted, the full API will be returned to the dApp to use. ## Simple example of connecting to a wallet ```js try { const okxwalletCardanoApi = await window.okxwallet.cardano.enable(); } catch (error) { console.log(error); } ``` ## Get networkId `api.getNetworkId(): Promise` **Description** Returns the network id of the currently connected account. **Return value** - `networkId` - string: The network id of the currently connected account. ```js const okxwalletCardanoApi = await window.okxwallet.cardano.enable(); const networkId = await okxwalletCardanoApi.getNetworkId(); ``` ## Get utxos `api.getUtxos(amount: cbor = undefined): Promise` **Description** If amount is undefined, this shall return a list of all UTXOs (unspent transaction outputs) controlled by the wallet. If amount is not undefined, this request shall be limited to just the UTXOs that are required to reach the combined ADA/multiasset value target specified in amount, and if this cannot be attained, null shall be returned. **Return value** - `utxos` - string[]: List of utxos. ```js const okxwalletCardanoApi = await window.okxwallet.cardano.enable(); const utxos = await okxwalletCardanoApi.getUtxos(); ``` ## Get balance `api.getBalance(): Promise>` **Description** Returns the total balance available of the wallet. This is the same as summing the results of api.getUtxos(). **Return value** - `balance` - string: The total balance available of the wallet ```js const okxwalletCardanoApi = await window.okxwallet.cardano.enable(); const utxos = await okxwalletCardanoApi.getBalance(); ``` ## Get used addresses `api.getUsedAddresses(): Promise[]>` **Description** Returns a list of all used (included in some on-chain transaction) addresses controlled by the wallet. **Return value** - `addresses` - string[]: List of addresses ```js const okxwalletCardanoApi = await window.okxwallet.cardano.enable(); const utxos = await okxwalletCardanoApi.getUsedAddresses(); ``` ## Get unused addresses `api.getUnusedAddresses(): Promise[]>` **Description** Returns a list of unused addresses controlled by the wallet. **Return value** - `addresses` - string[]: List of unused addresses. ```js const okxwalletCardanoApi = await window.okxwallet.cardano.enable(); const utxos = await okxwalletCardanoApi.getUnusedAddresses(); ``` ## Get change address `api.getChangeAddress(): Promise>` **Description** Returns an address owned by the wallet that should be used as a change address to return leftover assets during transaction creation back to the connected wallet. This can be used as a generic receive address as well. **Return value** - `changeAddress` - string: A change address. ```js const okxwalletCardanoApi = await window.okxwallet.cardano.enable(); const utxos = await okxwalletCardanoApi.getChangeAddress(); ``` ## Sign transaction `api.signTx(tx: cbor): Promise>` **Description** Requests that a user sign the supplied transaction. The wallet should ask the user for permission, and if given, try to sign the supplied body and return a signed transaction. **Return value** - `signedTx` - string: Signed transaction. ```js const okxwalletCardanoApi = await window.okxwallet.cardano.enable(); const rawTransaction = ''; const result = await okxwalletCardanoApi.signTx(rawTransaction); ``` ## Sign data `api.signData: (addr: Cbor
, payload: HexString) => Promise` **Description** Sign data. Read more about message signing in [CIP-0030](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030). **Return value** - `dataSignature` - object - signature - string - key - string ```js const okxwalletCardanoApi = await window.okxwallet.cardano.enable(); const addresses = await okxwalletCardanoApi.getUsedAddresses(); const payload = ''; const result = await okxwalletCardanoApi.signData(addresses[0], payload); ``` ## Submit transaction `api.submitTx(tx: cbor): Promise` **Description** Send the transaction and return the transaction id for the dApp to track. **Return value** - `txHash` - string: Transaction hash. ```js const okxwalletCardanoApi = await window.okxwallet.cardano.enable(); const transaction = ''; const result = await okxwalletCardanoApi.submitTx(transaction); ``` - [Nostr](https://web3.okx.com/onchainos/dev-docs/sdks/chains/nostr/introduce.md) # Nostr Nostr is a protocol for creating a global social network that is simple to use, hard to censor, and has trustworthy accounts. It uses basic technology to exchange information and secure messages, doesn't rely on central servers (making it resilient), and allows users to easily check if messages are genuine. Nostr is a basic framework that others can use to build applications; it's not an app or a service itself. - [Provider API](https://web3.okx.com/onchainos/dev-docs/sdks/chains/nostr/provider.md) # Provider API ## What is injected provider API? The OKX injected provider API is a JavaScript API that OKX injects into websites visited by our users. Your DApp can use this API to request users' accounts, read data from blockchains users are connected to, and help users sign messages and transactions. ## The injected object Dapps can access the injected object through the following methods: - `window.okxwallet.nostr` ## Simple example of connecting to a wallet ```js try { const publicKey = await window.okxwallet.nostr.getPublicKey(); } catch (error) { console.log(error); } ``` ## Get public key `window.okxwallet.nostr.getPublicKey(): Promise` **Description** Returns the public key of the currently connected account. **Return value** - `publicKey` - string: the public key of the currently connected account. ```js try { const publicKey = await window.okxwallet.nostr.getPublicKey(); } catch (error) { console.log(error); } ``` ## Sign Event `window.okxwallet.nostr.signEvent(event: Event): Promise` **Description** Signing the Event. **Parameters** - `event` - object - `created_at` - number: event creation time - `kind` - number: event type - `tags` - string[][]: event tags - `content` - string: event content **Return value** - `event` - SignedEvent, In addition to all the properties that include the event parameter, it also includes the following properties: - `id` - string: id - `pubkey` - string: the public key - `sig` - string: the signature ```js const event = { content: "hello", kind: 4, "tags": [ [ "p", "693d3f45b81c1f3557383fb955f3a8cb2c194c44ffba1e2f4566e678773b44f8" ], [ "r", "json" ], [ "a", "b4f4e689fca78ebcaeec72162628ba61c51a62e1420b9b8ca8cb63d9a7e26219" ] ], "created_at": 1700726837, } const signedEvent = await window.okxwallet.nostr.signEvent(event) console.log(signedEvent.id) console.log(signedEvent.pubkey) console.log(signedEvent.sig) ``` ## Encrypting the message `window.okxwallet.nostr.nip04.encrypt(pubkey: string, message: string): Promise` **Description** Encrypt the message according to the [NIP-04](https://github.com/nostr-protocol/nips/blob/master/04.md) specification. **Return value** - `encryptMsg` - string: the encrypting result ```js const pubkey = '693d3f45b81c1f3557383fb955f3a8cb2c194c44ffba1e2f4566e678773b44f8' const msg = 'hello world' const encryptMsg = await window.okxwallet.nostr.nip04.encrypt(pubkey, msg); console.log(encryptMsg) ``` ## Decrypting the message `window.okxwallet.nostr.nip04.decrypt(pubkey: string, message: string): Promise` **Description** Decrypt the message according to the [NIP-04](https://github.com/nostr-protocol/nips/blob/master/04.md) specification. **Return value** - `decryptMsg` - string: the decrypting result ```js const pubkey = '693d3f45b81c1f3557383fb955f3a8cb2c194c44ffba1e2f4566e678773b44f8' const msg = 'VVPplRPF0w4dNZkuiQ==?iv=Nrb7gcph/9eKuqyuDx0yKQ==' const decryptMsg = await window.okxwallet.nostr.nip04.decrypt(pubkey, msg); console.log(decryptMsg) ``` ## Add/Remove Event Listeners `window.okxwallet.nostr.on(event:string, callback: Function): Promise` `window.okxwallet.nostr.off(event:string, callback: Function): Promise` **Description** Add event listener, currently supported events are: - `accountChanged`: this event is triggered when the user switches accounts. ```js window.okxwallet.nostr.on('accountChanged', async () => { const publicKey = await window.okxwallet.nostr.getPublicKey(); console.log(publicKey) }) ``` - [NEAR](https://web3.okx.com/onchainos/dev-docs/sdks/chains/near/introduce.md) # NEAR NEAR is the chain abstraction stack, empowering builders to create apps that scale to billions of users and across all blockchains - [Provider API](https://web3.okx.com/onchainos/dev-docs/sdks/chains/near/provider.md) # Provider API ## What is injected provider API? The OKX injected provider API is a JavaScript API that OKX injects into websites visited by our users. Your DApp can use this API to request users' accounts, read data from blockchains users are connected to, and help users sign messages and transactions. ## The injected object Dapps can access the injected object through the following methods: - `window.okxwallet.near` - Recommended - `window.near` ## Connecting to OKX Wallet ### requestSignIn() ```js /** * @param {String} contractId contract account id * @param {Array} methodNames methods on the contract should be allowed to be called. * @returns { accountId, accessKey } accountId and signed in access key */ window.okxwallet.near.requestSignIn({ contractId = '', methodNames = []}): Promise ``` #### Only get the accountId ```js try { const { accountId } = window.okxwallet.near.requestSignIn(); } catch (_) { // something error } ``` Example of return value: ```json { "accountId": "efad2c...9dae", } ``` #### Get accessKey Request sign in with the contractId, given the needed view and change methods, you will get the access key ```js const contractId = 'wrap.near'; const methodNames = ['ft_metadata']; try { const { accountId, accessKey } = window.okxwallet.near.requestSignIn({ contractId, methodNames }); } catch (_) { // something error } ``` Example of return value: ```json { "accountId": "efad2c...9dae", "accessKey": { "secretKey": "5S9Ngi...Uku6", "publicKey": "ed25519:9RivAy...Hxc8" } } ``` ### signOut() Disconnect to the wallet. However, disconnection can also be initiated by the wallet in addition to the application. ```js window.okxwallet.near.signOut(): void; ``` ### isSignedIn() Check whether the current account has connected ```js window.okxwallet.near.isSignedIn(): boolean; ``` ### getAccountId() Get the accountId of current connected ```js window.okxwallet.near.getAccountId(): string; ``` ## signMessage ```js near.signMessage({ message: string, recipient: string, nonce: Buffer }): Response; ``` signMessage, demo: ```js const message = { message: 'hello world', recipient: 'test.testnet', nonce: Buffer.from("4268ebc14ff247f5450d4a8682bec3729a06d268f83b0cb363083ab05b65486b", "hex") } const result = await window.okxwallet.near.signMessage(message); ``` Example of return value: ```json { "accountId": "efad2c...9dae", "publicKey": "ed25519:H8bbdL...ucKF", "signature": "zYbw0Z+YabpZTnYA1REkvAX5KeXt/qRgHkorYfjRR5dD5keySfFuWGMafkfi/RPUpG1EAqbUf9VFt4tTBebcDQ==" } ``` ## Contract interaction ### signAndSendTransaction() ```js near.signAndSendTransaction({ receiverId: string, actions: Action[]}): Response; ``` sign and send one single transaction, demo: ```js const tx = { receiverId: 'wrap.near', actions: [ { methodName: 'near_deposit', args: {}, deposit: '1250000000000000000000', }, ], } const result = await window.okxwallet.near.signAndSendTransaction(tx); ``` Example of return value: ```json { "method": "signAndSendTransaction", "txHash": "2bNbuT...UdSA", "code": 0 } ``` Note: dapp needs to obtain the result of transaction broadcast through txHash ### requestSignTransactions() ```js near.requestSignTransactions({transactions: Transaction[]}): Response; ``` Batch sign transactions, demo: ```js const transactions = [ { receiverId: 'wrap.near', actions: [ { methodName: 'near_deposit', args: {}, deposit: '1000000000000000', }, ], }, { receiverId: 'wrap.near', actions: [ { methodName: 'ft_transfer', args: { receiver_id: 'efad2c...9dae', amount: '10000000000', }, deposit: '1', }, ], }, ] const result = await window.okxwallet.near.signAndSendTransaction({ transactions }); ``` Example of return value: ```json { "txs": [ { "signedTx": "QAAAAG...kAoH", "txHash": "71MuUA...KVxt" }, { "signedTx": "QAAAAG...gksH", "txHash": "8RHzw4...hvLN" } ], "code": 0, "method": "requestSignTransactions" } ``` Note: Batch signature transaction wallets only sign and do not broadcast The DAPP side needs to handle the logic of broadcasting ## Events ### signIn The OXK wallet has connected ```js window.okxwallet.near.on("signIn", ((accountId) => { // accountId: current connected accountId }); ``` ### signOut The OXK wallet has disconnected ```js window.okxwallet.near.on("signIn", (() => { // do something }); ``` ### accountChanged Listen to the current account changed ```js window.okxwallet.near.on("accountChanged", ((accountId) => { // accountId: the accountId after change }); ``` - [WAX](https://web3.okx.com/onchainos/dev-docs/sdks/chains/wax/introduce.md) # WAX The WAX blockchain, or World Asset eXchange, is a blockchain platform specifically designed for trading digital assets. Established in 2017, its goal is to create a scalable and user-friendly blockchain for everyday users, with a focus on NFT trading and gaming applications. - [Provider API](https://web3.okx.com/onchainos/dev-docs/sdks/chains/wax/provider.md) # Provider API ## What is injected provider API? The OKX injected provider API is a JavaScript API that OKX injects into websites visited by our users. Your DApp can use this API to request users' accounts, read data from blockchains users are connected to, and help users sign messages and transactions. ## Special Notes The WAX API of OKX Wallet is fully compatible with the [Scatter protocol](https://github.com/GetScatter/scatter-js). The following APIs and examples are based on this protocol. For specific usage details, developers can refer to the Scatter protocol documentation. ## Connect wallet and retrieve wallet information ```js import ScatterJS from '@scatterjs/core'; import ScatterEOS from '@scatterjs/eosjs2'; ScatterJS.plugins(new ScatterEOS()); ScatterJS.login().then(identity => { const account = identity.accounts[0] console.log(account) }) ``` ## Whether the wallet is connected Verify whether the wallet is connected ```js import ScatterJS from '@scatterjs/core'; import ScatterEOS from '@scatterjs/eosjs2'; ScatterJS.plugins(new ScatterEOS()); const isConnected = ScatterJS.isConnected() console.log(isConnected) ``` ## Retrieve wallet information Retrieve information about the currently connected wallet; if no wallet is connected, it will return `null`. ```js import ScatterJS from '@scatterjs/core'; import ScatterEOS from '@scatterjs/eosjs2'; ScatterJS.plugins(new ScatterEOS()); const isConnected = ScatterJS.isConnected() if (isConnected) { const identity = ScatterJS.account() const account = identity.accounts[0] console.log(account) } ``` ## Sign transaction When signing transactions, need to use the [eosjs](https://www.npmjs.com/package/eosjs) library. ```js import ScatterJS from '@scatterjs/core'; import ScatterEOS from '@scatterjs/eosjs2'; import {JsonRpc, Api} from 'eosjs'; ScatterJS.plugins(new ScatterEOS()); const network = ScatterJS.Network.fromJson({ blockchain:'wax', chainId:'1064487b3cd1a897ce03ae5b6a865651747e2e152090f99c1d19d44e01aea5a4', host:'nodes.get-scatter.com', port:443, protocol:'https' }); const rpc = new JsonRpc(network.fullhost()); ScatterJS.connect('YourAppName', {network}).then(connected => { if(!connected) return console.error('no scatter'); const eos = ScatterJS.eos(network, Api, {rpc}); ScatterJS.login().then(identity => { if(!identity) return console.error('no identity'); const account = identity.accounts[0] eos.transact({ actions: [] }).then(res => { console.log('sent: ', res); }).catch(err => { console.error('error: ', err); }); }); }); ``` ## Add/Remove Event Listeners Add/remove event listeners. Currently supported events include: - `connect`: This event is triggered when the wallet is connected. - `disconnect`: This event is triggered when the user disconnects. - `accountChanged`: This event is triggered when the user switches accounts. ```js import ScatterJS from '@scatterjs/core'; const connect = () => {} ScatterJS.on('connect', connect) ScatterJS.off('connect', connect) ``` - [Display DApp icon](https://web3.okx.com/onchainos/dev-docs/sdks/web-display-dapp-icon.md) # Display DApp icon When your site makes a login request to an OKX Wallet user, OKX Wallet may render a modal that displays your site icon. We retrieve this icon using the HTML selector `` link[rel="shortcut icon"]``. To customize this icon for your site, please make sure that you follow the [Favicon standard](https://en.wikipedia.org/wiki/Favicon) and have a ``link`` tag within your site's ``head`` with ``rel = "shortcut icon"``, like such. The tag's ``href`` attribute will be used for assigning the site icon. ```html ``` ## OKX V5 Documentation - [What is DEX API](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-what-is-dex-api.md) # What is DEX API ## Introduction Welcome to the OKX DEX Developer Documentation. OKX DEX is a decentralized exchange aggregator that supports both **EVM-compatible and non-EVM chains such as Solana, Sui, and TON**. Powered by a sophisticated smart routing algorithm, OKX DEX API optimizes trades by identifying the best quotes and most efficient swap routes, enabling projects to access the best liquidity pools and secure optimal trading prices. The OKX DEX API provides a robust suite of core functionalities, including **single-chain spot trading, swap instructions, transaction simulation and broadcasting**, and **real-time market data and on-chain analytics**. These features encompass the essential modules of decentralized trading systems, empowering developers to streamline their development process while reducing both time and costs. This documentation is designed to help enterprises or developers build a wide array of Web3 trading services and applications, such as - **Swap apps** - **Market data websites** - **Web3 wallets** - **Trading bots** ## Why Choose OKX DEX API? ### Product Capabilities and Ecosystem Synergy - Supports 20+ popular chains and 500+ decentralized exchanges (DEXs) across Solana, EVM, SUI and more, delivering optimal pricing and deep liquidity. - Supports emerging meme token launch platforms like Pump.fun, enabling real-time access to trending trading pairs, markets, and price data. ### Technical Performance and Advantages - Average API response time: under 100 ms - 99.9% SLA uptime ### Developer Experience and Support - 24/7 technical support to assist you at every stage - Access to an active and thriving developer community for collaboration and knowledge sharing ### Security and Compliance - Essential smart contract codes are audited and open-sourced - Enterprise-grade security measures aligned with OKX’s global compliance framework to ensure trust and reliability - [API Access and Usage](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-api-access-and-usage.md) # API Access and Usage Before using the DEX API, you need to create a project and generate an API key in the developer portal. For step-by-step instructions and additional resources, please refer to the guide available [here](./dex-developer-portal). ## Authentication All API requests must include the following headers: - OK-ACCESS-KEY: Your API key. - OK-ACCESS-TIMESTAMP: Request timestamp in UTC (ISO format, e.g., `2020-12-08T09:08:57.715Z`). - OK-ACCESS-PASSPHRASE: The passphrase specified when creating the API key. - OK-ACCESS-SIGN: Request signature. Signature steps: - Step 1: Concatenate the `timestamp`, HTTP method (e.g., `GET`/`POST`), `requestPath`, and `body` (if applicable) into a string. - Step 2: Sign the pre-hashed string (from Step 1) using the HMAC SHA256 algorithm with your secret key (generated during API key creation). - Step 3: Encode the signature using Base64. - For example, sign = CryptoJS.enc.Base64.stringify(CryptoJS.HmacSHA256(timestamp + 'GET' + '/api/v6/dex/aggregator/swap', SecretKey)) - Timestamp and OK-ACCESS-TIMESTAMP must be the same - GET is the method (HTTP request method, all letters are uppercase) - /api/v6/dex/aggregator/swap is the requestPath (request interface path) - Body is empty. If the request has no request body (usually a GET request), body can be omitted - The time difference between the timestamp and the server must not exceed 30 seconds - The POST request must include the original request in the signature - The secret key is only visible during its creation. Please store it in a safe place that is accessible only by you ## Postman example Postman is a popular API development and testing tool that allows developers to design, test, and document APIs. It provides a user-friendly graphical interface for making HTTP requests to APIs. If you have not installed Postman, you can download it for free from the Postman website: https://www.postman.com/ This example requires you to have a basic understanding of Postman. ### Add parameters - This typically applies to GET requests. - If your request requires query parameters, you can add them under the **Params** tab. Here, you can add key-value pairs for your query parameters. ![img](../images/postman1.png) ### Set headers Under the **Headers** tab, add the following key-value pairs: - `OK-ACCESS-KEY` - `OK-ACCESS-PASSPHRASE` ![img](../images/postman2.png) ### Add body - This typically applies to POST requests. - If your request requires a request body, you can add them under the **Body** tab. - Select **raw** and **JSON** under the dropdown menu. - Input your request body in JSON format. ![img](../images/postman3.png) ### Set pre-request script - This is used to generate the necessary signature (`OK-ACCESS-SIGN`) and timestamp (`OK-ACCESS-TIMESTAMP`) - Under the **Pre-request Script** tab, insert the script which corresponds to the request type. - Exclude the request body when generating the prehash string for GET requests. - Edit the secret key accordingly. GET requests: ```javascript var method = pm.request.method; var now = new Date(); var isoString = now.toISOString(); var path = pm.request.url.getPathWithQuery(); var sign=CryptoJS.enc.Base64.stringify(CryptoJS.HmacSHA256(isoString + method + path, pm.variables.replaceIn('{{secret_key}}'))); pm.request.headers.add({ key: 'OK-ACCESS-SIGN', value: sign }); pm.request.headers.add({ key: 'OK-ACCESS-TIMESTAMP', value: isoString }); ``` POST requests: ```javascript var method = pm.request.method; var now = new Date(); var isoString = now.toISOString(); var path = pm.request.url.getPathWithQuery(); var bodyStr = pm.request.body.raw; var sign=CryptoJS.enc.Base64.stringify(CryptoJS.HmacSHA256(isoString + method + path + bodyStr, pm.variables.replaceIn('{{secret_key}}'))) pm.request.headers.add({ key: 'OK-ACCESS-SIGN', value: sign }); pm.request.headers.add({ key: 'OK-ACCESS-TIMESTAMP', value: isoString }); ``` ## Javascript example To invoke the API through a Javascript script, refer to the following code example: ```javascript const https = require('https'); const crypto = require('crypto'); const querystring = require('querystring'); // Define API credentials const api_config = { "api_key": '', "secret_key": '', "passphrase": '', }; function preHash(timestamp, method, request_path, params) { // Create a pre-signature based on strings and parameters let query_string = ''; if (method === 'GET' && params) { query_string = '?' + querystring.stringify(params); } if (method === 'POST' && params) { query_string = JSON.stringify(params); } return timestamp + method + request_path + query_string; } function sign(message, secret_key) { // Use HMAC-SHA256 to sign the pre-signed string const hmac = crypto.createHmac('sha256', secret_key); hmac.update(message); return hmac.digest('base64'); } function createSignature(method, request_path, params) { // Get the timestamp in ISO 8601 format const timestamp = new Date().toISOString().slice(0, -5) + 'Z'; // Generate a signature const message = preHash(timestamp, method, request_path, params); const signature = sign(message, api_config['secret_key']); return { signature, timestamp }; } function sendGetRequest(request_path, params) { // Generate a signature const { signature, timestamp } = createSignature("GET", request_path, params); // Generate the request header const headers = { 'OK-ACCESS-KEY': api_config['api_key'], 'OK-ACCESS-SIGN': signature, 'OK-ACCESS-TIMESTAMP': timestamp, 'OK-ACCESS-PASSPHRASE': api_config['passphrase'], 'Content-Type': 'application/json' }; const options = { hostname: 'web3.okx.com', path: request_path + (params ? `?${querystring.stringify(params)}` : ''), method: 'GET', headers: headers }; const req = https.request(options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { console.log(data); }); }); req.end(); } function sendPostRequest(request_path, params) { // Generate a signature const { signature, timestamp } = createSignature("POST", request_path, params); // Generate the request header const headers = { 'OK-ACCESS-KEY': api_config['api_key'], 'OK-ACCESS-SIGN': signature, 'OK-ACCESS-TIMESTAMP': timestamp, 'OK-ACCESS-PASSPHRASE': api_config['passphrase'], 'Content-Type': 'application/json' }; const options = { hostname: 'web3.okx.com', path: request_path, method: 'POST', headers: headers }; const req = https.request(options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { console.log(data); }); }); if (params) { req.write(JSON.stringify(params)); } req.end(); } // GET request example const getRequestPath = '/api/v6/dex/aggregator/quote'; const getParams = { 'chainId': 42161, 'amount': 1000000000000, 'toTokenAddress': '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', 'fromTokenAddress': '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1' }; sendGetRequest(getRequestPath, getParams); // POST request example const postRequestPath = '/api/v6/dex/index/current-price'; const postParams = [{ chainIndex: "1", tokenContractAddress: "0xc18360217d8f7ab5e7c516566761ea12ce7f9d72" }]; sendPostRequest(postRequestPath, postParams); ``` ## Legacy API The Wallet API, Marketplace API, and DeFi API will no longer be updated. If you are still using these APIs, please contact our [BD](mailto:dexapi@okx.com) for alternative solutions. - [API Fee](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-api-fee.md) # API Fee OKX DEX API provides our integration partners with various API tiers and flexible methodology to add fees to each transaction, designed to support various stages of development and commercialization. As our integration partner, you can access OKX DEX API with a few different tiers to meet your specific needs. With OKX DEX API, you can earn revenue by setting your own partner fee scheme to charge your users per swap. In detail, integration partners can configure partner fee and fee-receiving address for each token swap. You can charge your users up to 3% per swap for most supported chains; while for Solana, you can charge up to 10% per swap. All tiers of OKX DEX API are subject to the [User agreement](https://web3.okx.com/help/okx-web3-build-user-agreement). ## Trial API Tier OKX DEX API offers a Trial tier that includes access to selected OKX DEX API functions. To start using the trial plan, you need to create an account on the [Developer Portal](https://web3.okx.com/build/dev-docs/dex-api/dex-developer-portal) and verify your email and phone number. This plan provides a default rate limit of 1 request per second (RPS) and can be increased to 5 RPS upon review and approval. The trial tier is valid for 60 days upon the API key creation. During the trial period, OKX DEX API is accessible free of charge. For the trial tier, when OKX DEX API secures a better price than quoted infrequently, the additional value named positive slippage is kept as our infrastructure fee. The positive slippage is capped at 10% of the trade amount. ## Start-up API Tier To continue using OKX DEX API after the 60-day trial period, you can upgrade your developer account to the Start-up tier on the [Developer Portal](https://web3.okx.com/build/dev-docs/dex-api/dex-developer-portal). Once upgraded to the Start-up tier, you immediately have access to additional product features, much higher RPS, standard technical and growth support. For start-up tier partners charging partner fee in token swaps, a standard revenue-sharing agreement is entered for OKX DEX API to retain 20% of your revenue as our infrastructure fee. In such cases, the positive slippage (if happened) is returned to your users by default; however, you can apply to have access to the feature to keep a portion of the positive slippage as your revenue. If you do not configure partner fees in token swaps to make revenue, OKX DEX API will keep the positive slippage (if happened) as our infrastructure fee, capped at 10% of the trade value. ## Enterprise API Tier For high-volume partners who need a much higher RPS, customized fee structure, dedicated technical and growth support, access to additional product features or customized features, you can upgrade to the Enterprise tier by contacting our BD team and signing a contract with us. Furthermore, Enterprise partners have access to the feature to keep the positive slippage as your revenue or provide the positive slippage entirely to your users. ## Need Help? If you need to increase your rate limit, upgrade to the Start-up tier or Enterprise tier, or have product-related queries, please join our [discord](https://discord.com/invite/okxdexapi), or contact our BD team directly at dexapi@okx.com ## API Tiers Summary | | Trial Tier | Start-up Tier | Enterprise Tier | |--------------------- |-------------------------------------------------------------------------------------------------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | DEX API fee | Positive slippage only | 20% rev-share, or positive slippage if no partner fee is configured | Customized fee structure | | Features & Benefits | • RPS 1-5
• Access to standard API endpoints
• Valid for 60 days
| • RPS 2-50
• Access to most advanced API endpoints
• Access to positive slippage feature to retain as extra revenue (upon approval)
• Receive standard tech and growth support
| • Customised RPS
• Access to all advanced API endpoints, including positive slippage feature to retain as extra revenue
• Request customized feature development (upon approval)
• Receive dedicated tech and growth support
| *RPS adjustment is correlated to trading volume
*Positive slippage refers to a situation where a trade is executed at a more favorable price than initially quoted, which is relatively rare. For selected API tiers, the additional value generated by positive slippage will be retained as an API fee, capped at no more than 10% of the total traded amount.
*Start-up customers with monthly trading volume exceeding $10M need to contact our BD to upgrade to Enterprise tier for customized support
- [Supported Chains](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-supported-chain.md) # Supported Chains ## EVM Chains | Chain | Swap API | ChainIndex | |----------------------------------|------------------------------------------|------------------| | Ethereum Mainnet | [Supported](./dex-swap-api-introduction) | 1 | | OP Mainnet | [Supported](./dex-swap-api-introduction) | 10 | | BNB Smart Chain Mainnet | [Supported](./dex-swap-api-introduction) | 56 | | Uni Chain | [Supported](./dex-swap-api-introduction) | 130 | | Sonic | [Supported](./dex-swap-api-introduction) | 146 | | X layer | [Supported](./dex-swap-api-introduction) | 196 | | Polygon Mainnet | [Supported](./dex-swap-api-introduction) | 137 | | Arbitrum One | [Supported](./dex-swap-api-introduction) | 42161 | | Avalanche C-Chain | [Supported](./dex-swap-api-introduction) | 43114 | | zkSync Era Mainnet | [Supported](./dex-swap-api-introduction) | 324 | | Polygon zkEVM | [Supported](./dex-swap-api-introduction) | 1101 | | Base | [Supported](./dex-swap-api-introduction) | 8453 | | Linea | [Supported](./dex-swap-api-introduction) | 59144 | | Fantom Opera | [Supported](./dex-swap-api-introduction) | 250 | | Mantle | [Supported](./dex-swap-api-introduction) | 5000 | | Conflux eSpace | [Supported](./dex-swap-api-introduction) | 1030 | | Metis Andromeda Mainnet | [Supported](./dex-swap-api-introduction) | 1088 | | Merlin Chain | [Supported](./dex-swap-api-introduction) | 4200 | | Blast | [Supported](./dex-swap-api-introduction) | 81457 | | Manta Pacific Mainnet | [Supported](./dex-swap-api-introduction) | 169 | | Scroll | [Supported](./dex-swap-api-introduction) | 534352 | | Cronos Mainnet | [Supported](./dex-swap-api-introduction) | 25 | | ZetaChain Mainnet | [Supported](./dex-swap-api-introduction) | 7000 | ## Other Chains | Chain | Swap API | ChainIndex | |--------|-------------------------------------------------|-------------| | Tron | [Supported](./dex-swap-api-introduction) | 195 | | Solana | [Supported](./dex-swap-api-introduction) | 501 | | SUI | [Supported](./dex-swap-api-introduction) | 784 | | Ton | [Supported](./dex-swap-api-introduction) | 607 | The other APIs support additional chains beyond those listed above. For the most up-to-date chain information, we recommend using the relevant API endpoint provided in each module. - [Developer Portal](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-developer-portal.md) # Developer Portal This section covers the features of the development portal and best practices which will help you to build your own apps efficiently. ## Sign up/Log in 1. Click on the ['**Developer portal**'](https://web3.okx.com/build/dev-portal) under the navigation bar **Build**. 2. Click '**Connect Wallet**' to create or log in to an account. We recommend to use OKX Wallet for a seamless experience.You can also choose other wallets for your project. 3. Click '**Verify**' in the developer portal, then confirm **Signature** request in the extension. Congrats! You have successfully created an account and are logged into the developer management platform. A default project is also created for your convenience. ## Link E-mail and Phone number to your account 1. Click the 'Link now' Button and switch to the 'Setting' tab 2. Input your E-mail and Phone number correctly If you find you cannot find your country in the Phone number country selection part, that's mainly because some regions are restricted to DEX API services 3. Complete the verification code process Congrats! You have successfully linked the E-mail and phone number to your created account and got access to create OKX DEX API keys to start your Web3 trading system build journey. ## Generate a New API Key 1. Click the API keys button in the project where you want to create the API key. 2. Click the Create API key button. 3. Enter the name of API key and passphrase, click Create to generate the corresponding API key. Please keep your passphrase safe and accessible. You cannot access your API key without it. ## View the Secret Key When making a request to the API, you need to also provide the secret key. Click the Copy button on the right to view your secret key. ## General Terms - API key: Provides a unique identifier for the application or user to interact with the API. - Secret Key: Works with API keys to provide additional security by adding a security token. - Passphrase: Used to encrypt secret keys on the server to provide additional security. Passphrase is also used to view secret keys and modify API information. - [Environment Settings](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-env-setup.md) # Environment Settings The following guide uses TypeScript as a reference. ## Install the Following Libraries ```bash npm install @okx-dex/okx-dex-sdk npm install dotenv ``` ## Create .env 1. You will always need your OKX API credentials. Put those in the .env file ```bash OKX_API_KEY= OKX_SECRET_KEY= OKX_API_PASSPHRASE= ``` Parameter values need to be obtained from the OKX developer platform 2. Network dependencies Import the required variables into the .env file based on the network you're interacting with. For example: ```bash # Solana SOLANA_WALLET_ADDRESS= SOLANA_PRIVATE_KEY= SOLANA_RPC_URL= ``` - SOLANA_RPC_URL: Paid RPC service is recommended to ensure stability. - It is recommended to manage private parameters (such as SOLANA_PRIVATE_KEY) through encryption. 1. Use process.env to read environment variables 2. Add .env to .gitignore to prevent sensitive information leakage 3. When developing multiple chains, you can create environment configuration files such as .env.solana and .env.evm - [Run Your First Program ](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-run-application.md) # Run Your First Program In your codebase, plug in your private wallet key using `Initialize http client`, then run the `Get Quote` application. ## Initialize HTTP Client ```javascript import { OKXDexClient } from '@okx-dex/okx-dex-sdk'; import 'dotenv/config'; const client = new OKXDexClient({ apiKey: process.env.OKX_API_KEY!, secretKey: process.env.OKX_SECRET_KEY!, apiPassphrase: process.env.OKX_API_PASSPHRASE!, projectId: process.env.OKX_PROJECT_ID!, // Required for executing swaps solana: { connection: { rpcUrl: process.env.SOLANA_RPC_URL!, confirmTransactionInitialTimeout: 60000}, privateKey: process.env.SOLANA_PRIVATE_KEY!, walletAddress: process.env.SOLANA_WALLET_ADDRESS! } } ); ``` ## Get Quote (SOL → USDC) ```javascript async function main() { try { // Get a quote const quote = await client.dex.getQuote({ chainIndex: '501', // Native token contract address fromTokenAddress: 'So11111111111111111111111111111111111111112', toTokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', amount: '1000000000', slippage: '0.1' }); console.log('Swap Quote:', JSON.stringify(quote, null, 2)); } catch (error) { console.error('Error:', error); } } main(); ``` Key parameter description: - chainIndex: unique identifier of each public chain. (501 = Solana network) - slippage: It is recommended to adjust dynamically according to market volatility (range 0.1-1%) - amount: needs to be converted to the minimum unit of tokens (such as SOL's Lamport accuracy) Here are additional examples of setting up programs - [Support](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-support.md) # Support Welcome to DEX API Support. Here you'll find resources and guidance for getting help with our products and services. Technical Support:[Discord](https://discord.gg/okxdexapi)
Business Support:dexapi@okx.com - [Smart Contract Safety](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-smart-contract-safety.md) # Smart Contract Safety ## Bug Bounty Program We provide generous rewards to the world’s foremost ethical hackers, and you, our community, for reporting bugs and security vulnerabilities. For more details, visit our [website](https://web3.okx.com/zh-hans/web3/security).
Submit a bug report: https://hackerone.com/okg?type=team ## Open Source Smart Contract We've released the core smart contract code as open source on GitHub, enabling community oversight: - Solana Chain Contract Repository https://github.com/okxlabs/DEX-Router-Solana-V1 - EVM Chain Contract Repository https://github.com/okxlabs/DEX-Router-EVM-V1 ## Join Community Discussions Join our [Discord community](https://discord.gg/okxdexapi) to help other developers troubleshoot their integration issues and share your experience with the Smart Contract. Our Discord is the main hub for technical discussions, questions, and real-time support. - [Change log](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-change-log.md) # Change log ### September 11, 2025 Update - Standard market maker integration guidelines are published for market makers to easily integrate with OKX DEX RFQ system and provide liquidity to our users and partners. ### September 4, 2025 Update - The DEX API now supports **Token API services**, allowing you to search for the tokens you need, access basic and detailed information, check holder statistics, or retrieve token ranking lists with a single request. ### August 28, 2025 Update - We are excited to announce that our paid plan will officially launch in September 2025! - The DEX API now supports multiple service tiers, designed to give you greater flexibility and scalability. - Higher tiers unlock enhanced features, increased rate limits, and priority support — empowering your business to build faster and scale with confidence. ### August 27, 2025 Update - The trading API swap endpoint now **supports RFQ quotes by default**, enabling your large orders to receive more favorable pricing. Since RFQ quotes may introduce some latency, you can disable it by adding the `disableRFQ` parameter in the `/swap` endpoint request. ### August 19, 2025 Update - DEX API does not support OKT Chain any more. - The `/swap API` now supports excluding specific liquidity sources when assembling calldata. You can use the `excludeDexIds` parameter to specify the liquidity pools you don’t want to use. ### July 1, 2025 Update - The `feePercent` parameter in the swap API now supports 9 decimal. - Trade API now supports MEV protection feature on SOL,ETH,BSC,BASE. ### June 6, 2025 Update - The `swapReceiverAddress` parameter in the swap API now supports Sui and Ton chains. You can now specify a different receiving address for a swap transaction on Sui and Ton chains. ### May 30, 2025 Update - Trade API now supports transaction simulate. You can take a look at "Onchain gateway API" for reference. - The Trade API now supports the `exactOut` reverse quoting function. You can specify the amount you want to receive in the swap to query the required input token amount. {' '} ExactOut feature currently only support Ethereum、Base、BSC 、Arbitrum chain and Uni v3 protocols ### May 22, 2025 Update - Market API now supports to returen up to 100 tokens' 5m、1h、4h、24h trading volume and 5m、1h、4h、24h price change,you can check in the /price-info endpoint ### May 16, 2025 Update - Trade API now supports Uni chain. - Trade API now supports four tier priority fee for the Solana chain. ### May 13, 2025 Update - Trade API now supports setting positive slippage gains for the Solana chain. This feature is only available to **whitelisted or enterprise users**. If you would like to use it, please contact dexapi.okx.com. ### May 5, 2025 Update - Trade API now supports setting the referral fee **for Solana chain up to 10%**. ### May 2, 2025 Update - Trade API now supports the Onchain Gateway API function, offering gas price estimation and on-chain transaction broadcasting services. ### May 1, 2025 Update - Trade API now supports setting the referral fee for **Ton chain**. - Trade API now supports setting referral fees for **wrapped tokens on EVM chains**. ### March 27, 2025 Update - OKX DEX API now supports the **Market API**. ### March 12, 2025 Update - Single-chain swaps now support the Sonic chain. ### January 23, 2025 Update - The single-chain swap API now supports specifying a single liquidity pool for swaps. You can achieve this by setting the `directRoute` parameter. - The single-chain swap API now supports the Transaction querying feature. ### December 26, 2024 Update - The single-chain swap API now supports an automatic slippage feature. ### November 25, 2024 Update - The single-chain swap API parameter `swapReceiverAddress` now supports the Solana chain. It is now possible to specify a different recipient address for a swap transaction on the Solana chain. ### November 12, 2024 Update - Added a new referral wallet address parameter for the single-chain swap API. Both Sol and SPL tokens now support direct use of wallet addresses for referral fee collection. - APIs for retrieving the single-chain liquidity list and the cross-chain bridge list now support protocol logos. - Single-chain quote and swap APIs now recognize and return risk tokens with honeypot mechanisms or tokens with 100% buy/sell tax. ### October 29, 2024 Update - Single-chain swaps now support the Sui chain. ### July 1, 2024 Update - The ETH dexRouter contract 0xf3de3c0d654fda23dad170f0f320a92172509127 will no longer function normally after August 1, 2024. Please switch to the latest version. ### June 19, 2024 Update - Swap API DEX Router eth contract address update ### May 7, 2024 Update - Solana mainnet supports commission-sharing ### April 19, 2024 Update - Cross-chain swap support SUI chain ### April 19, 2024 Update - Cross-chain swap support X Layer chain ### April 12, 2024 Update - Cross-chain slippage request parameter range adjusted to 0.002-0.5 - Cross-chain swap support Merlin chain ### April 12, 2024 Update - Added new response parameters (quoteCompareList) to DEX swap endpoint ### April 8, 2024 Update - Added new response parameters (toTokenReferrerAddress) to DEX swap endpoint ### April 2, 2024 Update - Updated DEX swap trading support Merlin Chain ### March 22, 2024 Update - Added new response parameters (callDataMemo) to DEX swap endpoint ### March 22, 2024 Update - Added new request parameters (sort) to cross-chain Get route information and Cross-chain swap endpoint - DEX XBridge contract address update ### March 13, 2024 Update - Added new response parameters (sourceChainGasfee, destinationChainGasfee, crossChainFee) to cross-chain Get transaction status endpoint - Added new request parameters (onlyBridge) and new response parameters (minmumReceive,maxPriorityFeePerGas) - Cross-chain API Smart contract part added cross-chain contract address (DEX XBridge contract address) - Cross-chain API added new Get the list of tokens supported by the cross-chain bridges endpoint ### March 07, 2024 Update - Added new request parameters (priceImpactProtectionPercentage) to Cross-chain & Single-chain swap endpoint ### February 29, 2024 Update - Added new response parameters (decimal) to DEX swap endpoint ### February 22, 2024 Update - Added new response parameters (maxPriorityFeePerGas) to DEX swap endpoint ### February 01, 2024 Update - Updated DEX swap trading support solana, added new request parameters (solTokenAccountAddress) - Added DEX swap trading support solana quick start ### January 17, 2024 Update - Added new request parameters (feePercent, referrerAddress) to Cross-chain swap endpoint ### January 11, 2024 Update - Cross-chain slippage range adjusted to 0.005-0.5 ### January 02, 2024 Update - Added new request parameters (receiveAddress) to Cross-chain swap endpoint - Added new request parameters (chainld) to cross-chain Get transaction status endpoint ### December 28, 2023 Update - Launched the first edition of OKX Web3 DeFi API documentation - Added functionality for investment, redemption, and reward claiming processes via DeFi API - Added methods for querying information, calculating estimated data, generating transaction data, and querying user information ### December 20, 2023 Update - Added new response parameters (crossChainFeeTokenAddress) to cross-chain Get route information endpoint and Cross-chain swap endpoint - Added new response parameters (status) to cross-chain Get transaction status endpoint ### December 14, 2023 Update - Added DEX Iframe ### December 14, 2023 Update - Added new optional parameter (swapReceiverAddress) to DEX swap interface ### December 08, 2023 Update - Added DEX limit order list query - Added DEX limit order get cancellation calldata ### December 06, 2023 Update - Added new response parameters (toDexRouterList) to cross-chain Get route information endpoint - Added new response parameters (toAmount, errorMsg) to cross-chain Get transaction status endpoint - Added cross-chain refund issues to cross-chain FAQ ### November 24, 2023 Update - The Order API has been expanded with a new listing module, enabling listings on OpenSea and OKX. - Added more detailed description to order structure ### November 23, 2023 Update - Added DEX cross-chain API quick start guidelines ### November 21, 2023 Update- Added DEX cross-chain API quick start guidelines ### November 15, 2023 Update - Added new response parameters (crossChainFee) to cross chain Get route information endpoint cross-chain/quote - Added new response parameters (crossChainFee) to cross chain Cross-chain swap endpoint cross-chain/quote ### November 10, 2023 Update - Added DEX API quick start guidelines ### November 7, 2023 Update - Added DEX cross-chain aggregator API ### October 31, 2023 Update - Added DEX limit order API ### October 23, 2023 Update - Added smart contract information, including contract addresses and ABI ### September 27, 2023 Update - Updated the content of integrating DApps with OKX Wallet on the mobile app - Added guide and sub pages for integrating DApps with OKX Wallet on the mobile app
### August 17, 2023 Update - Updated the API key authentication mechanism. Moving forward, all endpoints will require an API key generated from the Web3 developer portal. - Updated the URI of all endpoints to reflect the latest versioning - Updated error codes Update - Added API key authentication. Moving forward, all endpoints will require an API key generated from the Web3 developer portal - Updated error codes Update - Updated the API key authentication mechanism. Moving forward, all Web3 API endpoints will require an API key generated from the Web3 developer portal - Updated the URI of all endpoints to reflect the latest versioning
### May 29, 2023 Update- Added new BRC-20 endpoint: ``brc20/token-list`` - Added new response parameters (index, location) to BRC-20 endpoint ``brc20/transaction-list`` - Added new response parameters (location) to BRC-20 endpoint ``brc20/inscriptions-list``
- [Trade API](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-trade-api-introduction.md) # Trade API Our Trade API provides developers a set of APIs to identify the best quotes and execute the most efficient swap routes through our smart routing algorithm and liquidity aggregation across 500+ DEXs across Solana, EVM, SUI and more. It provides the critical multi-chain DEX aggregator backend for developers to build and scale trading experience within a variety of dApps such as - DEX Dashboards and Aggregators: offering users a comprehensive view of prices and liquidity across multiple decentralized exchanges for optimized trading. - Native Swap in Wallets: enabling wallets to incorporate built-in swap functionalities with access to the best liquidity pools. - Multi-chain Trading Bots: allowing automation of trading strategies such as arbitrage, liquidity mining, and asset management by leveraging high liquidity and efficient trade routing across 20+ chains. - DeFi Lending Platforms: supporting Defi platforms with liquidity tracking for optimized asset management and lending strategies. - Arbitrage Bots: providing tools and infrastructure to enable developers to perform and profit from price differences across multiple DEXs or between DEXs and CEXs. - [Build Swap Applications on Solana](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-use-swap-solana-quick-start.md) # Build Swap Applications on Solana There are two approaches to building swap applications with OKX DEX on Solana: 1. The API-first approach - directly interacting with OKX DEX API endpoints 2. The SDK approach - using the `@okx-dex/okx-dex-sdk` package for a simplified developer experience This guide covers both methods to help you choose the approach that best fits your needs. ## Method 1: API-First Approach This approach demonstrates a token swap using the OKX DEX API endpoints directly. You will swap SOL to USDC on Solana Mainnet. ## 1. Set Up Your Environment Import the necessary Node.js libraries and set up your environment variables: ```typescript // Required libraries import base58 from "bs58"; import BN from "bn.js"; import * as solanaWeb3 from "@solana/web3.js"; import { Connection } from "@solana/web3.js"; import cryptoJS from "crypto-js"; import axios from "axios"; import dotenv from 'dotenv'; dotenv.config(); // Environment variables const apiKey = process.env.OKX_API_KEY; const secretKey = process.env.OKX_SECRET_KEY; const apiPassphrase = process.env.OKX_API_PASSPHRASE; const projectId = process.env.OKX_PROJECT_ID; const userAddress = process.env.WALLET_ADDRESS; const userPrivateKey = process.env.PRIVATE_KEY; const solanaRpcUrl = process.env.SOLANA_RPC_URL; // Constants const SOLANA_CHAIN_ID = "501"; const COMPUTE_UNITS = 300000; const MAX_RETRIES = 3; // Initialize Solana connection const connection = new Connection(`${solanaRpcUrl}`, { confirmTransactionInitialTimeout: 5000 }); ``` ```typescript // Utility function for OKX API authentication function getHeaders(timestamp: string, method: string, requestPath: string, queryString = "", body = "") { const stringToSign = timestamp + method + requestPath + (queryString || body); return { "Content-Type": "application/json", "OK-ACCESS-KEY": apiKey, "OK-ACCESS-SIGN": cryptoJS.enc.Base64.stringify( cryptoJS.HmacSHA256(stringToSign, secretKey) ), "OK-ACCESS-TIMESTAMP": timestamp, "OK-ACCESS-PASSPHRASE": apiPassphrase, "OK-ACCESS-PROJECT": projectId, }; } ``` ## 2. Get Swap Data Solana's native token address is 11111111111111111111111111111111. Use the /swap endpoint to retrieve detailed swap information: ```typescript async function getSwapData( fromTokenAddress: string, toTokenAddress: string, amount: string, slippage = '0.005' // 0.5% slippage ) { const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/aggregator/swap"; const params = { amount: amount, chainId: SOLANA_CHAIN_ID, fromTokenAddress: fromTokenAddress, toTokenAddress: toTokenAddress, userWalletAddress: userAddress, slippage: slippage }; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); try { const response = await axios.get( `https://web3.okx.com${requestPath}${queryString}`, { headers } ); if (response.data.code !== "0" || !response.data.data?.[0]) { throw new Error(`API Error: ${response.data.msg || "Failed to get swap data"}`); } return response.data.data[0]; } catch (error) { console.error("Error fetching swap data:", error); throw error; } } ``` ## 3. Prepare Transaction ```typescript async function prepareTransaction(callData: string) { try { // Decode the base58 encoded transaction data const decodedTransaction = base58.decode(callData); // Get the latest blockhash const recentBlockHash = await connection.getLatestBlockhash(); console.log("Got blockhash:", recentBlockHash.blockhash); let tx; // Try to deserialize as a versioned transaction first try { tx = solanaWeb3.VersionedTransaction.deserialize(decodedTransaction); console.log("Successfully created versioned transaction"); tx.message.recentBlockhash = recentBlockHash.blockhash; } catch (e) { // Fall back to legacy transaction if versioned fails console.log("Versioned transaction failed, trying legacy:", e); tx = solanaWeb3.Transaction.from(decodedTransaction); console.log("Successfully created legacy transaction"); tx.recentBlockhash = recentBlockHash.blockhash; } return { transaction: tx, recentBlockHash }; } catch (error) { console.error("Error preparing transaction:", error); throw error; } } ``` ## 4. Simulate Transaction Before executing the actual swap, it's crucial to simulate the transaction to ensure it will succeed and to identify any potential issues: The Simulate API is available to our whitelisted customers only. Please reach out to dexapi@okx.com to request access. ```typescript async function simulateTransaction(swapData: any) { try { if (!swapData.tx) { throw new Error('Invalid swap data format - missing transaction data'); } const tx = swapData.tx; const params: any = { fromAddress: tx.from, toAddress: tx.to, txAmount: tx.value, chainIndex: SOLANA_CHAIN_ID, extJson: { inputData: tx.data }, includeDebug: true }; const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/pre-transaction/simulate"; const requestBody = JSON.stringify(params); const headers = getHeaders(timestamp, "POST", requestPath, "", requestBody); console.log('Simulating transaction...'); const response = await axios.post( `https://web3.okx.com${requestPath}`, params, { headers } ); if (response.data.code !== "0") { throw new Error(`Simulation failed: ${response.data.msg || "Unknown simulation error"}`); } const simulationResult = response.data.data[0]; // Check simulation success if (simulationResult.success === false) { console.error('Transaction simulation failed:', simulationResult.error); throw new Error(`Transaction would fail: ${simulationResult.error}`); } console.log('Transaction simulation successful'); console.log(`Estimated gas used: ${simulationResult.gasUsed || 'N/A'}`); if (simulationResult.logs) { console.log('Simulation logs:', simulationResult.logs); } return simulationResult; } catch (error) { console.error("Error simulating transaction:", error); throw error; } } ``` ## 5. Broadcast Transaction 5.1 Create a Compute Unit Estimation Utility Function Solana uses compute units instead of gas to measure transaction complexity. There are two approaches to estimate compute units for your transactions: using standard RPC calls or leveraging the Onchain Gateway API. Method 1: Using the Onchain Gateway API for Compute Unit Estimation The first approach leverages OKX's Onchain Gateway API, which provides more accurate compute unit estimations than standard methods. ```typescript /** * Get transaction compute units from Onchain Gateway API * @param fromAddress - Sender address * @param toAddress - Target program address * @param inputData - Transaction data (base58 encoded) * @returns Estimated compute units */ async function getComputeUnits( fromAddress: string, toAddress: string, inputData: string ): Promise { try { const path = 'dex/pre-transaction/gas-limit'; const url = `https://web3.okx.com/api/v5/${path}`; const body = { chainIndex: "501", // Solana chain ID fromAddress: fromAddress, toAddress: toAddress, txAmount: "0", extJson: { inputData: inputData } }; // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { const computeUnits = parseInt(response.data.data[0].gasLimit); console.log(`API estimated compute units: ${computeUnits}`); return computeUnits; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get compute units from API:', (error as Error).message); throw error; } } ``` Method 2: Using RPC to Estimate Compute Units The second approach utilizes standard Solana RPC calls to simulate and estimate the required compute units for your transaction. ```typescript /** * Estimate compute units for a transaction */ async function getComputeUnits(transaction: VersionedTransaction): Promise { try { // Simulate the transaction to get compute unit usage const simulationResult = await connection.simulateTransaction(transaction, { replaceRecentBlockhash: true, commitment: 'processed' }); if (simulationResult.value.err) { throw new Error(`Simulation failed: ${JSON.stringify(simulationResult.value.err)}`); } // Get the compute units consumed from simulation const computeUnitsConsumed = simulationResult.value.unitsConsumed || 200000; // Add 20% buffer for safety const computeUnitsWithBuffer = Math.ceil(computeUnitsConsumed * 1.2); console.log(`Estimated compute units: ${computeUnitsConsumed}`); console.log(`With 20% buffer: ${computeUnitsWithBuffer}`); return computeUnitsWithBuffer; } catch (error) { console.warn('Failed to estimate compute units, using default:', error); return 300000; // Default fallback } } ``` 5.2 Transaction Preparation with Compute Units Before broadcasting, prepare your transaction with the estimated compute units and latest blockhash: Method 1: Transaction Using Compute Units from Gas-Limit API prepare your transaction with compute units estimated from the Onchain Gateway API: ```typescript /** * Get transaction compute units from Onchain Gateway API */ async function getComputeUnitsFromAPI( fromAddress: string, inputData: string ): Promise { try { const path = 'dex/pre-transaction/gas-limit'; const url = `https://web3.okx.com/api/v5/${path}`; const body = { chainIndex: "501", // Solana chain ID fromAddress: fromAddress, toAddress: "", // Can be empty for Solana txAmount: "0", extJson: { inputData: inputData } }; // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await fetch(url, { method: 'POST', headers, body: bodyString }); const data = await response.json(); if (data.code === '0') { const computeUnits = parseInt(data.data[0].gasLimit); console.log(`API estimated compute units: ${computeUnits}`); return computeUnits; } else { throw new Error(`API Error: ${data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get compute units from API:', (error as Error).message); throw error; } } /** * Prepare transaction with compute units from API */ async function prepareTransactionWithAPIComputeUnits( transaction: VersionedTransaction, fromAddress: string, transactionData: string ): Promise<{ transaction: VersionedTransaction; gasData: { estimatedComputeUnits: number; priorityFee: number; blockhash: string; }; }> { try { // Get fresh blockhash const { blockhash } = await connection.getLatestBlockhash('confirmed'); console.log(`Using blockhash: ${blockhash}`); // Update the transaction's blockhash transaction.message.recentBlockhash = blockhash; // Check if transaction already has compute budget instructions const hasComputeBudgetIx = transaction.message.compiledInstructions.some(ix => { const programId = transaction.message.staticAccountKeys[ix.programIdIndex]; return programId.equals(ComputeBudgetProgram.programId); }); if (hasComputeBudgetIx) { console.log('Transaction already contains compute budget instructions, skipping addition'); return { transaction, gasData: { estimatedComputeUnits: 300000, priorityFee: 1000, blockhash } }; } // Get compute units from API const estimatedComputeUnits = await getComputeUnitsFromAPI(fromAddress, transactionData); // Set priority fee const priorityFee = 1000; // microLamports const gasData = { estimatedComputeUnits, priorityFee, blockhash }; console.log(`Priority fee: ${gasData.priorityFee} microLamports`); // Create compute unit limit instruction const computeBudgetIx = ComputeBudgetProgram.setComputeUnitLimit({ units: gasData.estimatedComputeUnits }); // Create compute unit price instruction for priority const computePriceIx = ComputeBudgetProgram.setComputeUnitPrice({ microLamports: gasData.priorityFee }); // Get existing instructions and account keys const existingInstructions = [...transaction.message.compiledInstructions]; const existingAccountKeys = [...transaction.message.staticAccountKeys]; // Add compute budget program to account keys if not present let computeBudgetProgramIndex = existingAccountKeys.findIndex( key => key.equals(ComputeBudgetProgram.programId) ); if (computeBudgetProgramIndex === -1) { computeBudgetProgramIndex = existingAccountKeys.length; existingAccountKeys.push(ComputeBudgetProgram.programId); } // Create new instructions array with compute budget instructions const newInstructions = [ { programIdIndex: computeBudgetProgramIndex, accountKeyIndexes: [], data: computeBudgetIx.data }, { programIdIndex: computeBudgetProgramIndex, accountKeyIndexes: [], data: computePriceIx.data }, ...existingInstructions ]; // Create new versioned message with proper instruction mapping const newMessage = new TransactionMessage({ payerKey: existingAccountKeys[0], recentBlockhash: gasData.blockhash, instructions: newInstructions.map(ix => ({ programId: existingAccountKeys[ix.programIdIndex], keys: ix.accountKeyIndexes.map(idx => ({ pubkey: existingAccountKeys[idx], isSigner: false, isWritable: false })).filter(key => key.pubkey), data: Buffer.from(ix.data) })).filter(ix => ix.programId) }).compileToV0Message(); // Create and return new transaction const preparedTransaction = new VersionedTransaction(newMessage); return { transaction: preparedTransaction, gasData }; } catch (error) { console.error('Error preparing transaction:', error); throw error; } } ``` Method 2: Transaction Using Compute Units from RPC ```typescript // Simple connection setup const connection = new Connection( process.env.SOLANA_RPC_URL || "https://api.mainnet-beta.solana.com" ); /** * Prepare transaction with compute units */ async function prepareTransactionWithComputeUnits( transaction: VersionedTransaction ): Promise<{ transaction: VersionedTransaction; gasData: { estimatedComputeUnits: number; priorityFee: number; blockhash: string; }; }> { try { // Get fresh blockhash const { blockhash } = await connection.getLatestBlockhash('confirmed'); console.log(`Using blockhash: ${blockhash}`); // Update the transaction's blockhash transaction.message.recentBlockhash = blockhash; // Check if transaction already has compute budget instructions const hasComputeBudgetIx = transaction.message.compiledInstructions.some(ix => { const programId = transaction.message.staticAccountKeys[ix.programIdIndex]; return programId.equals(ComputeBudgetProgram.programId); }); if (hasComputeBudgetIx) { console.log('Transaction already contains compute budget instructions, skipping addition'); return { transaction, gasData: { estimatedComputeUnits: 300000, priorityFee: 1000, blockhash } }; } // Estimate compute units const estimatedComputeUnits = await getComputeUnits(transaction); // Set priority fee const priorityFee = 1000; // microLamports const gasData = { estimatedComputeUnits, priorityFee, blockhash }; console.log(`Priority fee: ${gasData.priorityFee} microLamports`); // Create compute unit limit instruction const computeBudgetIx = ComputeBudgetProgram.setComputeUnitLimit({ units: gasData.estimatedComputeUnits }); // Create compute unit price instruction for priority const computePriceIx = ComputeBudgetProgram.setComputeUnitPrice({ microLamports: gasData.priorityFee }); // Get existing instructions and account keys const existingInstructions = [...transaction.message.compiledInstructions]; const existingAccountKeys = [...transaction.message.staticAccountKeys]; // Add compute budget program to account keys if not present let computeBudgetProgramIndex = existingAccountKeys.findIndex( key => key.equals(ComputeBudgetProgram.programId) ); if (computeBudgetProgramIndex === -1) { computeBudgetProgramIndex = existingAccountKeys.length; existingAccountKeys.push(ComputeBudgetProgram.programId); } // Create new instructions array with compute budget instructions const newInstructions = [ { programIdIndex: computeBudgetProgramIndex, accountKeyIndexes: [], data: computeBudgetIx.data }, { programIdIndex: computeBudgetProgramIndex, accountKeyIndexes: [], data: computePriceIx.data }, ...existingInstructions ]; // Create new versioned message with proper instruction mapping const newMessage = new TransactionMessage({ payerKey: existingAccountKeys[0], recentBlockhash: gasData.blockhash, instructions: newInstructions.map(ix => ({ programId: existingAccountKeys[ix.programIdIndex], keys: ix.accountKeyIndexes.map(idx => ({ pubkey: existingAccountKeys[idx], isSigner: false, isWritable: false })).filter(key => key.pubkey), data: Buffer.from(ix.data) })).filter(ix => ix.programId) }).compileToV0Message(); // Create and return new transaction const preparedTransaction = new VersionedTransaction(newMessage); return { transaction: preparedTransaction, gasData }; } catch (error) { console.error('Error preparing transaction:', error); throw error; } } ``` 5.3 Broadcasting Transactions Using Onchain Gateway API For developers with access to the Onchain Gateway API, you can broadcast transactions directly through OKX's infrastructure. This method provides enhanced reliability and monitoring capabilities for high-volume trading operations. The Broadcast API is available to our whitelisted customers only. Please reach out to dexapi@okx.com to request access. ```typescript async function broadcastTransaction( signedTx: solanaWeb3.Transaction | solanaWeb3.VersionedTransaction ) { try { const serializedTx = signedTx.serialize(); const encodedTx = base58.encode(serializedTx); const path = "dex/pre-transaction/broadcast-transaction"; const url = `https://web3.okx.com/api/v5/${path}`; const broadcastData = { signedTx: encodedTx, chainIndex: SOLANA_CHAIN_ID, address: userAddress // See [MEV Section](#8-mev-protection) for MEV protection settings }; // Prepare authentication with body included in signature const bodyString = JSON.stringify(broadcastData); const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, broadcastData, { headers }); if (response.data.code === '0') { const orderId = response.data.data[0].orderId; console.log(`Transaction broadcast successfully, Order ID: ${orderId}`); return orderId; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to broadcast transaction:', error); throw error; } } ``` Using Standard RPC For developers who prefer using standard blockchain RPC methods or do not have yet requested API whitelisting, you can broadcast transactions directly to the network using Web3 RPC calls. ```typescript async function signAndBroadcastTransaction( tx: solanaWeb3.Transaction | solanaWeb3.VersionedTransaction, connection: Connection ) { if (!userPrivateKey) { throw new Error("Private key not found"); } const feePayer = solanaWeb3.Keypair.fromSecretKey( base58.decode(userPrivateKey) ); // Sign the transaction if (tx instanceof solanaWeb3.VersionedTransaction) { tx.sign([feePayer]); } else { tx.partialSign(feePayer); } // Send the transaction with retry logic const maxRetries = 3; let attempt = 0; while (attempt < maxRetries) { try { const txId = await connection.sendRawTransaction(tx.serialize(), { skipPreflight: false, preflightCommitment: 'processed', maxRetries: 0 // Handle retries manually }); console.log(`Transaction sent: ${txId}`); // Wait for confirmation with timeout const confirmation = await connection.confirmTransaction({ signature: txId, blockhash: tx instanceof solanaWeb3.VersionedTransaction ? tx.message.recentBlockhash : tx.recentBlockhash!, lastValidBlockHeight: tx instanceof solanaWeb3.VersionedTransaction ? undefined : tx.lastValidBlockHeight! }, 'confirmed'); if (confirmation.value.err) { throw new Error(`Transaction failed: ${JSON.stringify(confirmation.value.err)}`); } console.log(`Transaction confirmed: https://solscan.io/tx/${txId}`); return txId; } catch (error) { attempt++; console.warn(`Attempt ${attempt} failed:`, error); if (attempt >= maxRetries) { throw new Error(`Transaction failed after ${maxRetries} attempts: ${error}`); } // Wait before retry await new Promise(resolve => setTimeout(resolve, 1000 * attempt)); } } } ``` ### Swap Transaction Using Compute Unit Data Here's a complete example that demonstrates the full flow from getting swap data to preparing transactions with proper compute unit estimation: ```typescript import { getHeaders } from '../../shared'; import { Connection, VersionedTransaction, ComputeBudgetProgram, TransactionMessage } from "@solana/web3.js"; import base58 from 'bs58'; import dotenv from 'dotenv'; dotenv.config(); // Simple connection to one RPC endpoint const connection = new Connection( process.env.SOLANA_RPC_URL || "https://api.mainnet-beta.solana.com" ); async function getQuote(params: any) { const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/aggregator/swap"; const queryString = "?" + new URLSearchParams({ ...params, }).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); const response = await fetch(`https://web3.okx.com${requestPath}${queryString}`, { method: "GET", headers }); const data = await response.json(); return data; } /** * * Get compute units using Onchain Gateway API (API registration and whitelist required) */ async function getComputeUnitsFromAPI( fromAddress: string, inputData: string ): Promise { try { const path = 'dex/pre-transaction/gas-limit'; const url = `https://web3.okx.com/api/v5/${path}`; const body = { chainIndex: "501", // Solana chain ID fromAddress: fromAddress, toAddress: "", // Can be empty for Solana txAmount: "0", extJson: { inputData: inputData } }; const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await fetch(url, { method: 'POST', headers, body: bodyString }); const data = await response.json(); if (data.code === '0') { const computeUnits = parseInt(data.data[0].gasLimit); console.log(`API estimated compute units: ${computeUnits}`); return computeUnits; } else { throw new Error(`API Error: ${data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get compute units from API, falling back to simulation:', error); // Fallback to RPC simulation return 300000; } } /** * Execute a complete Solana transaction with proper compute unit estimation */ async function executeTransaction(): Promise<{ quote: any; gasData: { estimatedComputeUnits: number; priorityFee: number; blockhash: string; }; preparedTransaction: string; }> { try { console.log('Getting Solana swap data...'); // Step 1: Get swap data from OKX DEX API const quote = await getQuote({ chainId: '501', // Solana chain ID amount: '10000000', // 0.01 SOL in lamports fromTokenAddress: '11111111111111111111111111111111', // SOL toTokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC userWalletAddress: "YOUR_WALLET_ADDRESS", slippage: '0.1', autoSlippage: "true", maxAutoSlippageBps: "100" }); console.log('Quote response:', JSON.stringify(quote, null, 2)); // Step 2: Process transaction data if available if (quote.data && quote.data[0] && quote.data[0].tx && quote.data[0].tx.data) { console.log('\nGetting gas data for transaction...'); // Step 3: Create transaction from the data const decodedTransaction = base58.decode(quote.data[0].tx.data); const transaction = VersionedTransaction.deserialize(decodedTransaction); // Step 4: Get compute units using API (API whitelist required) or fallback to RPC const userWalletAddress = "YOUR_WALLET_ADDRESS"; let estimatedComputeUnits: number; try { // Try API first (API whitelist required) estimatedComputeUnits = await getComputeUnitsFromAPI( userWalletAddress, quote.data[0].tx.data ); console.log('Using API estimate for compute units'); } catch (error) { // Fallback to RPC simulation estimatedComputeUnits = await getComputeUnits(transaction); console.log('Using RPC simulation for compute units'); } // Step 5: Prepare transaction with compute units const { transaction: preparedTransaction, gasData } = await prepareTransactionWithComputeUnits(transaction); // Override with API estimate if we got one gasData.estimatedComputeUnits = estimatedComputeUnits; console.log('\nGas Data Summary:'); console.log('Blockhash:', gasData.blockhash); console.log('Estimated Compute Units:', gasData.estimatedComputeUnits); console.log('Priority Fee:', gasData.priorityFee, 'microLamports'); console.log('Transaction prepared successfully'); // Return the complete result const result = { quote: quote.data[0], gasData, preparedTransaction: Buffer.from(preparedTransaction.serialize()).toString('base64') }; console.log('\nFinal Result:', JSON.stringify(result, null, 2)); return result; } else { throw new Error('No transaction data received from swap API'); } } catch (error) { console.error("Error executing transaction:", error); throw error; } } // Example usage async function main() { try { await executeTransaction(); } catch (error) { console.error('Failed to prepare transaction:', error); process.exit(1); } } // Run if this file is executed directly if (require.main === module) { main(); } export { executeTransaction, prepareTransactionWithComputeUnits, getComputeUnits, getComputeUnitsFromAPI }; ``` ## 6. Track Transaction Finally, create a transaction tracking system, choose the first(Section 6.2) for basic transaction confirmation status, and the second(Section 6.1) when you need detailed information about the swap execution itself. 6.1 With the Onchain gateway API The Onchain gateway API provides transaction tracking capabilities through the `/dex/post-transaction/orders` endpoint. Use the order ID returned by the broadcast API to track transactions as they progress through OKX's systems with simple status codes (1: Pending, 2: Success, 3: Failed). ```typescript // Define transaction status interface interface TxErrorInfo { error: string; message: string; action: string; } /** * Tracking transaction confirmation status using the Onchain gateway API * @param orderId - Order ID from broadcast response * @param intervalMs - Polling interval in milliseconds * @param timeoutMs - Maximum time to wait * @returns Final transaction confirmation status */ async function trackTransaction( orderId: string, intervalMs: number = 5000, timeoutMs: number = 300000 ): Promise { console.log(`Tracking transaction with Order ID: ${orderId}`); const startTime = Date.now(); let lastStatus = ''; while (Date.now() - startTime < timeoutMs) { // Get transaction status try { const path = 'dex/post-transaction/orders'; const url = `https://web3.okx.com/api/v5/${path}`; const params = { orderId: orderId, chainIndex: SOLANA_CHAIN_ID, address: userAddress, limit: '1' }; // Prepare authentication const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); if (response.data.code === '0' && response.data.data && response.data.data.length > 0) { if (response.data.data[0].orders && response.data.data[0].orders.length > 0) { const txData = response.data.data[0].orders[0]; // Use txStatus to match the API response const status = txData.txStatus; // Only log when status changes if (status !== lastStatus) { lastStatus = status; if (status === '1') { console.log(`Transaction pending: ${txData.txHash || 'Hash not available yet'}`); } else if (status === '2') { console.log(`Transaction successful: https://solscan.io/tx/${txData.txHash}`); return txData; } else if (status === '3') { const failReason = txData.failReason || 'Unknown reason'; const errorMessage = `Transaction failed: ${failReason}`; console.error(errorMessage); const errorInfo = handleTransactionError(txData); console.log(`Error type: ${errorInfo.error}`); console.log(`Suggested action: ${errorInfo.action}`); throw new Error(errorMessage); } } } else { console.log(`No orders found for Order ID: ${orderId}`); } } } catch (error) { console.warn('Error checking transaction status:', (error instanceof Error ? error.message : "Unknown error")); } // Wait before next check await new Promise(resolve => setTimeout(resolve, intervalMs)); } throw new Error('Transaction tracking timed out'); } /** * Comprehensive error handling with failReason * @param txData - Transaction data from post-transaction/orders * @returns Structured error information */ function handleTransactionError(txData: any): TxErrorInfo { const failReason = txData.failReason || 'Unknown reason'; // Log the detailed error console.error(`Transaction failed with reason: ${failReason}`); // Default error info let errorInfo: TxErrorInfo = { error: 'TRANSACTION_FAILED', message: failReason, action: 'Try again or contact support' }; // More specific error handling based on the failure reason if (failReason.includes('insufficient funds')) { errorInfo = { error: 'INSUFFICIENT_FUNDS', message: 'Your wallet does not have enough funds to complete this transaction', action: 'Add more SOL to your wallet to cover the transaction' }; } else if (failReason.includes('blockhash')) { errorInfo = { error: 'BLOCKHASH_EXPIRED', message: 'The transaction blockhash has expired', action: 'Try again with a fresh transaction' }; } else if (failReason.includes('compute budget')) { errorInfo = { error: 'COMPUTE_BUDGET_EXCEEDED', message: 'Transaction exceeded compute budget', action: 'Increase compute units or simplify the transaction' }; } return errorInfo; } ``` 6.2 For more detailed swap-specific information, you can use the SWAP API: SWAP API transaction tracking provides comprehensive swap execution details using the `/dex/aggregator/history` endpoint. It offers token-specific information (symbols, amounts), fees paid, and detailed blockchain data. Use this when you need complete swap insight with token-level details. ```typescript /** * Track transaction using SWAP API * @param chainId - Chain ID (e.g., 501 for Solana) * @param txHash - Transaction hash * @returns Transaction details */ async function trackTransactionWithSwapAPI( txHash: string ): Promise { try { const path = 'dex/aggregator/history'; const url = `https://web3.okx.com/api/v5/${path}`; const params = { chainId: SOLANA_CHAIN_ID, txHash: txHash, isFromMyProject: 'true' }; // Prepare authentication const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); if (response.data.code === '0') { const txData = response.data.data[0]; const status = txData.status; if (status === 'pending') { console.log(`Transaction is still pending: ${txHash}`); return { status: 'pending', details: txData }; } else if (status === 'success') { console.log(`Transaction successful!`); console.log(`From: ${txData.fromTokenDetails.symbol} - Amount: ${txData.fromTokenDetails.amount}`); console.log(`To: ${txData.toTokenDetails.symbol} - Amount: ${txData.toTokenDetails.amount}`); console.log(`Transaction Fee: ${txData.txFee}`); console.log(`Explorer URL: https://solscan.io/tx/${txHash}`); return { status: 'success', details: txData }; } else if (status === 'failure') { console.error(`Transaction failed: ${txData.errorMsg || 'Unknown reason'}`); return { status: 'failure', details: txData }; } return txData; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to track transaction status:', (error instanceof Error ? error.message : "Unknown error")); throw error; } } ``` ## 7. Complete Implementation Here's a complete implementation example: ```typescript import { getHeaders } from '../../shared'; import { Connection, PublicKey, Transaction, Keypair, VersionedTransaction, SystemProgram } from '@solana/web3.js'; import * as axios from 'axios'; import bs58 from 'bs58'; // // Utility function for OKX API authentication // function getHeaders(timestamp: string, method: string, requestPath: string, queryString = "", body = "") { // const stringToSign = timestamp + method + requestPath + (queryString || body); // return { // "Content-Type": "application/json", // "OK-ACCESS-KEY": apiKey, // "OK-ACCESS-SIGN": cryptoJS.enc.Base64.stringify( // cryptoJS.HmacSHA256(stringToSign, secretKey) // ), // "OK-ACCESS-TIMESTAMP": timestamp, // "OK-ACCESS-PASSPHRASE": apiPassphrase, // "OK-ACCESS-PROJECT": projectId, // }; // Environment variables const WALLET_ADDRESS = process.env.SOLANA_WALLET_ADDRESS; const PRIVATE_KEY = process.env.SOLANA_PRIVATE_KEY; const chainId = '501'; // Solana Mainnet const rpcUrl = process.env.SOLANA_RPC_URL || 'https://api.mainnet-beta.solana.com'; // Constants const SOL_ADDRESS = '11111111111111111111111111111111'; // Native SOL const USDC_ADDRESS = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'; // USDC // Initialize Solana connection const connection = new Connection(rpcUrl, 'confirmed'); // Type definitions interface GasLimitApiResponse { code: string; msg?: string; data: Array<{ gasLimit: string; }>; } interface SimulationApiResponse { code: string; msg?: string; data: Array<{ intention: string; gasUsed?: string; failReason?: string; assetChange?: Array<{ assetType: string; name: string; symbol: string; decimals: number; address: string; imageUrl: string; rawValue: string; }>; risks?: Array; }>; } interface BroadcastApiResponse { code: string; msg?: string; data: Array<{ orderId: string; }>; } interface TxErrorInfo { error: string; message: string; action: string; } // ============================================================================ // API Functions // ============================================================================ /** * Get gas limit from Onchain Gateway API */ async function getGasLimit( fromAddress: string, toAddress: string, txAmount: string = '0', inputData: string = '' ): Promise { try { console.log('Getting gas limit from Onchain Gateway API...'); const path = 'dex/pre-transaction/gas-limit'; const url = `https://web3.okx.com/api/v5/${path}`; const body = { chainIndex: chainId, fromAddress: fromAddress, toAddress: toAddress, txAmount: txAmount, extJson: { inputData: inputData } }; // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { const gasLimit = response.data.data[0].gasLimit; console.log(`Gas Limit obtained: ${gasLimit}`); return gasLimit; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get gas limit:', (error as Error).message); throw error; } } /** * Get swap data from OKX API */ async function getSwapData( fromTokenAddress: string, toTokenAddress: string, amount: string, slippage = '0.5' ) { try { console.log('Getting swap data from OKX API...'); const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/aggregator/swap"; const queryString = "?" + new URLSearchParams({ chainIndex: chainId, fromTokenAddress, toTokenAddress, amount, slippage, userWalletAddress: WALLET_ADDRESS!, autoSlippage: "false", maxAutoSlippageBps: "0" }).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); const response = await fetch(`https://web3.okx.com${requestPath}${queryString}`, { method: "GET", headers }); if (!response.ok) { throw new Error(`Failed to get swap data: ${response.status} ${await response.text()}`); } const data = await response.json(); console.log('Swap data obtained'); return data.data[0]; // Return only the first swap data object } catch (error) { console.error('Failed to get swap data:', (error as Error).message); throw error; } } /** * Simulate transaction using Onchain Gateway API */ async function simulateTransaction(swapData: any) { try { console.log('Simulating transaction with Onchain Gateway API...'); const path = 'dex/pre-transaction/simulate'; const url = `https://web3.okx.com/api/v5/${path}`; const body = { chainIndex: chainId, fromAddress: swapData.tx.from, toAddress: swapData.tx.to, txAmount: swapData.tx.value, extJson: { inputData: swapData.tx.data } }; // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { const simulationData = response.data.data[0]; if (simulationData.failReason) { throw new Error(`Simulation failed: ${simulationData.failReason}`); } console.log(`Transaction simulation successful. Gas used: ${simulationData.gasUsed}`); console.log('Simulation API Response:', simulationData); return simulationData; } else { throw new Error(`Simulation API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Transaction simulation failed:', (error as Error).message); throw error; } } /** * Broadcast transaction using Onchain Gateway API with RPC fallback */ async function broadcastTransaction( signedTx: string, chainId: string, walletAddress: string ): Promise { try { console.log('Broadcasting transaction via Onchain Gateway API...'); const path = 'dex/pre-transaction/broadcast-transaction'; const url = `https://web3.okx.com/api/v5/${path}`; const body = { signedTx: signedTx, chainIndex: chainId, address: walletAddress }; console.log('Broadcast request body:', JSON.stringify(body, null, 2)); // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { const orderId = response.data.data[0].orderId; console.log(`Transaction broadcast successful. Order ID: ${orderId}`); return orderId; } else { throw new Error(`Broadcast API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('OKX API broadcast failed:', (error as Error).message); // Fallback to direct RPC broadcast try { console.log('Attempting direct RPC broadcast as fallback...'); // Decode the signed transaction const txBytes = bs58.decode(signedTx); // Send directly to Solana RPC const signature = await connection.sendRawTransaction(txBytes, { skipPreflight: false, preflightCommitment: 'processed' }); console.log(`Direct RPC broadcast successful. Signature: ${signature}`); // Wait for confirmation const confirmation = await connection.confirmTransaction(signature, 'confirmed'); if (confirmation.value.err) { throw new Error(`Transaction failed: ${JSON.stringify(confirmation.value.err)}`); } console.log(`Transaction confirmed: https://solscan.io/tx/${signature}`); return signature; } catch (rpcError) { console.error('RPC broadcast also failed:', (rpcError as Error).message); throw new Error(`Both OKX API and RPC broadcast failed. OKX Error: ${(error as Error).message}, RPC Error: ${(rpcError as Error).message}`); } } } /** * Track transaction status using Onchain Gateway API */ async function trackTransaction( orderId: string, intervalMs: number = 5000, timeoutMs: number = 180000 // Reduced timeout to 3 minutes ): Promise { console.log(`Tracking transaction with Order ID: ${orderId}`); const startTime = Date.now(); let lastStatus = ''; let pendingCount = 0; while (Date.now() - startTime < timeoutMs) { try { const path = 'dex/post-transaction/orders'; const url = `https://web3.okx.com/api/v5/${path}`; const params = { orderId: orderId, chainIndex: chainId, address: WALLET_ADDRESS!, limit: '1' }; const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); const responseData = response.data as any; if (responseData.code === '0' && responseData.data && responseData.data.length > 0) { if (responseData.data[0].orders && responseData.data[0].orders.length > 0) { const txData = responseData.data[0].orders[0]; const status = txData.txStatus; if (status !== lastStatus) { lastStatus = status; if (status === '1') { pendingCount++; console.log(`Transaction pending (${pendingCount}): ${txData.txHash || 'Hash not available yet'}`); // If pending too long without a hash, something is wrong if (pendingCount > 12 && !txData.txHash) { // 1 minute of pending without hash console.warn('Transaction has been pending for too long without a transaction hash. This may indicate an issue.'); } } else if (status === '2') { console.log(`Transaction successful: https://web3.okx.com/explorer/solana/tx/${txData.txHash}`); return txData; } else if (status === '3') { const failReason = txData.failReason || 'Unknown reason'; const errorMessage = `Transaction failed: ${failReason}`; console.error(errorMessage); const errorInfo = handleTransactionError(txData); console.log(`Error type: ${errorInfo.error}`); console.log(`Suggested action: ${errorInfo.action}`); throw new Error(errorMessage); } } else if (status === '1') { pendingCount++; // Show progress for long pending transactions if (pendingCount % 6 === 0) { // Every 30 seconds const elapsed = Math.round((Date.now() - startTime) / 1000); console.log(`Still pending... (${elapsed}s elapsed)`); } } } else { console.log(`No orders found for Order ID: ${orderId}`); } } else { console.log('No response data from tracking API'); } } catch (error) { console.warn('Error checking transaction status:', (error as Error).message); } await new Promise(resolve => setTimeout(resolve, intervalMs)); } throw new Error(`Transaction tracking timed out after ${timeoutMs/1000} seconds. The transaction may still be processing.`); } // ============================================================================ // Transaction Signing Functions // ============================================================================ /** * Sign transaction with private key - Fixed OKX approach with gas limit analysis */ async function signTransaction(swapData: any, gasLimit: string): Promise { try { console.log('Signing transaction...'); if (!PRIVATE_KEY) { throw new Error('Private key not found in environment variables'); } // Create keypair from private key const privateKeyBytes = bs58.decode(PRIVATE_KEY); const keypair = Keypair.fromSecretKey(privateKeyBytes); if (!swapData.tx || !swapData.tx.data) { throw new Error('No transaction data found in swap response'); } const callData = swapData.tx.data; console.log('Transaction data length:', callData.length); console.log('Gas limit from API:', gasLimit); try { // Decode the base58 encoded transaction data (this is the correct approach) const decodedTransaction = bs58.decode(callData); console.log('Decoded transaction bytes length:', decodedTransaction.length); // Get the latest blockhash (CRITICAL!) const recentBlockHash = await connection.getLatestBlockhash(); console.log('Got recent blockhash:', recentBlockHash.blockhash); let transaction: Transaction | VersionedTransaction; // Try VersionedTransaction first (more common for modern Solana programs) try { transaction = VersionedTransaction.deserialize(decodedTransaction); console.log('Successfully deserialized as VersionedTransaction'); // DEBUGGING: Let's see what instructions are already in the transaction console.log('Number of instructions in OKX transaction:', transaction.message.compiledInstructions.length); // Check if there are already ComputeBudget instructions const computeBudgetProgram = new PublicKey('ComputeBudget111111111111111111111111111111'); const computeBudgetIndex = transaction.message.staticAccountKeys.findIndex( key => key.equals(computeBudgetProgram) ); if (computeBudgetIndex !== -1) { console.log('ComputeBudget program found at index:', computeBudgetIndex); // Check which instructions use the ComputeBudget program const computeBudgetInstructions = transaction.message.compiledInstructions.filter( ix => ix.programIdIndex === computeBudgetIndex ); console.log('Number of ComputeBudget instructions:', computeBudgetInstructions.length); // Analyze each ComputeBudget instruction computeBudgetInstructions.forEach((ix, i) => { const data = ix.data; if (data.length > 0) { const instructionType = data[0]; console.log(`ComputeBudget instruction ${i}: type ${instructionType}`); if (instructionType === 0 && data.length >= 5) { // SetComputeUnitLimit instruction const computeUnits = new Uint32Array(data.slice(1, 5).buffer)[0]; console.log(` - Current compute unit limit: ${computeUnits}`); console.log(` - Gas limit from API: ${gasLimit}`); // Check if we need to update it const apiGasLimit = parseInt(gasLimit); if (computeUnits !== apiGasLimit) { console.log(` - Compute units mismatch! OKX: ${computeUnits}, API: ${apiGasLimit}`); // We could potentially update this here } } else if (instructionType === 1 && data.length >= 9) { // SetComputeUnitPrice instruction const microLamports = new BigUint64Array(data.slice(1, 9).buffer)[0]; console.log(` - Current compute unit price: ${microLamports} microlamports`); } } }); } else { console.log('No ComputeBudget program found - OKX transaction may not have compute budget instructions'); console.log('We should add ComputeBudget instruction with gas limit:', gasLimit); // Add ComputeBudget instruction since OKX didn't include one const setComputeUnitLimitData = Buffer.alloc(5); setComputeUnitLimitData[0] = 0; // SetComputeUnitLimit instruction setComputeUnitLimitData.writeUInt32LE(parseInt(gasLimit), 1); // Add the ComputeBudget program to static accounts transaction.message.staticAccountKeys.push(computeBudgetProgram); const programIndex = transaction.message.staticAccountKeys.length - 1; // Add the compute budget instruction at the beginning transaction.message.compiledInstructions.unshift({ programIdIndex: programIndex, accountKeyIndexes: [], data: setComputeUnitLimitData }); console.log('Added ComputeBudget instruction with gas limit:', gasLimit); } // CRITICAL: Update the blockhash in the transaction message transaction.message.recentBlockhash = recentBlockHash.blockhash; // Sign the versioned transaction transaction.sign([keypair]); console.log('Signed VersionedTransaction'); } catch (versionedError) { console.log('VersionedTransaction failed, trying legacy Transaction'); try { transaction = Transaction.from(decodedTransaction); console.log('Successfully deserialized as legacy Transaction'); // DEBUGGING: Check legacy transaction instructions console.log('Number of instructions in legacy transaction:', transaction.instructions.length); // Check for ComputeBudget instructions in legacy format const computeBudgetProgram = new PublicKey('ComputeBudget111111111111111111111111111111'); const computeBudgetInstructions = transaction.instructions.filter( ix => ix.programId.equals(computeBudgetProgram) ); if (computeBudgetInstructions.length === 0) { console.log('No ComputeBudget instructions found in legacy transaction'); console.log('Adding ComputeBudget instruction with gas limit:', gasLimit); // Add ComputeBudget instruction const setComputeUnitLimitData = Buffer.alloc(5); setComputeUnitLimitData[0] = 0; // SetComputeUnitLimit instruction setComputeUnitLimitData.writeUInt32LE(parseInt(gasLimit), 1); const computeBudgetIx = { programId: computeBudgetProgram, keys: [], data: setComputeUnitLimitData }; // Add at the beginning transaction.instructions.unshift(computeBudgetIx); console.log('Added ComputeBudget instruction to legacy transaction'); } else { console.log('Found existing ComputeBudget instructions:', computeBudgetInstructions.length); } // CRITICAL: Update the blockhash in the transaction transaction.recentBlockhash = recentBlockHash.blockhash; // Sign the legacy transaction transaction.sign(keypair); console.log('Signed legacy Transaction'); } catch (legacyError) { console.log('Both transaction types failed to deserialize'); console.log('VersionedTransaction error:', (versionedError as Error).message); console.log('Legacy Transaction error:', (legacyError as Error).message); // This should not happen with proper OKX data throw new Error('Failed to deserialize OKX transaction data. Data may be corrupted.'); } } // Serialize and encode the signed transaction const serializedTx = transaction.serialize(); const encodedTx = bs58.encode(serializedTx); console.log('Transaction signed and encoded successfully'); return encodedTx; } catch (error) { console.log('Failed to process OKX transaction data:', (error as Error).message); // If we reach here, the OKX data is not in expected format throw new Error(`Cannot process OKX transaction data: ${(error as Error).message}`); } } catch (error) { console.error('Failed to sign transaction:', (error as Error).message); throw error; } } // ============================================================================ // Error Handling // ============================================================================ /** * Comprehensive error handling with failReason */ function handleTransactionError(txData: any): TxErrorInfo { const failReason = txData.failReason || 'Unknown reason'; console.error(`Transaction failed with reason: ${failReason}`); return { error: 'TRANSACTION_FAILED', message: failReason, action: 'Try again or contact support' }; } // ============================================================================ // Main Execution Functions // ============================================================================ /** * Execute swap with full transaction flow */ async function executeSwap( fromTokenAddress: string, toTokenAddress: string, amount: string, slippage: string = '0.05' ): Promise { try { console.log('Starting swap execution...'); // Step 1: Get swap data const swapData = await getSwapData(fromTokenAddress, toTokenAddress, amount, slippage); console.log('Swap data obtained'); // Step 2: Simulate transaction const simulationResult = await simulateTransaction(swapData); console.log('Transaction simulation completed'); console.log('Simulation result', simulationResult.intention); // Step 3: Get gas limit const gasLimit = await getGasLimit( swapData.tx.from, swapData.tx.to, swapData.tx.value || '0', swapData.tx.data ); console.log('Gas limit obtained'); // Step 4: Check account balance if (!(swapData.tx && swapData.tx.data)) { throw new Error('No valid transaction data found in swap API response (tx.data missing)'); } console.log('Checking account balance...'); const fromPubkey = new PublicKey(swapData.tx.from); const balance = await connection.getBalance(fromPubkey); console.log(`Account balance: ${balance / 1e9} SOL`); // Check if we have enough balance for the transaction const requiredAmount = parseInt(swapData.tx.value || '0'); console.log(`Required amount: ${requiredAmount / 1e9} SOL`); if (balance < requiredAmount) { throw new Error(`Insufficient balance. Required: ${requiredAmount / 1e9} SOL, Available: ${balance / 1e9} SOL`); } // Step 5: Sign the transaction with private key console.log('Signing transaction with private key...'); const signedTx = await signTransaction(swapData, gasLimit); console.log('Transaction signed successfully'); // Step 6: Broadcast transaction console.log('Broadcasting signed transaction via Onchain Gateway API...'); const txHash = await broadcastTransaction(signedTx, chainId, WALLET_ADDRESS!); console.log(`Transaction broadcast successful. Hash: ${txHash}`); // Step 7: Track transaction console.log('Tracking transaction status...'); const trackingResult = await trackTransaction(txHash); console.log('Transaction tracking completed'); console.log('Tracking result', trackingResult); return txHash; } catch (error) { console.error('Swap execution failed:', (error as Error).message); throw error; } } /** * Execute swap with simulation and detailed logging */ async function executeSwapWithSimulation( fromTokenAddress: string, toTokenAddress: string, amount: string, slippage: string = '0.05' ): Promise { try { console.log('Starting swap execution with simulation...'); const txHash = await executeSwap(fromTokenAddress, toTokenAddress, amount, slippage); console.log('Swap execution completed successfully!'); console.log(`Transaction Hash: ${txHash}`); return { success: true, txHash }; } catch (error) { console.error('Swap execution failed:', (error as Error).message); return { success: false, error: (error as Error).message }; } } /** * Simulation-only mode */ async function simulateOnly( fromTokenAddress: string, toTokenAddress: string, amount: string, slippage: string = '0.05' ): Promise { try { console.log('Starting simulation-only mode...'); console.log(`Simulation Details:`); console.log(` From Token: ${fromTokenAddress}`); console.log(` To Token: ${toTokenAddress}`); console.log(` Amount: ${amount}`); console.log(` Slippage: ${slippage}%`); // Step 1: Get swap data const swapData = await getSwapData(fromTokenAddress, toTokenAddress, amount, slippage); console.log('Swap data obtained'); // Step 2: Simulate transaction const simulationResult = await simulateTransaction(swapData); console.log('Transaction simulation completed'); // Step 3: Get gas limit const gasLimit = await getGasLimit( swapData.tx.from, swapData.tx.to, swapData.tx.value || '0', swapData.tx.data ); console.log('Gas limit obtained'); return { success: true, swapData, simulationResult, gasLimit, estimatedGasUsed: simulationResult.gasUsed, }; } catch (error) { console.error('Simulation failed:', (error as Error).message); return { success: false, error: (error as Error).message }; } } // ============================================================================ // Main Entry Point // ============================================================================ async function main() { try { console.log('Solana Swap Tools with Onchain Gateway API'); console.log('====================================='); // Validate environment variables if (!WALLET_ADDRESS || !PRIVATE_KEY) { throw new Error('Missing wallet address or private key in environment variables'); } console.log(`Wallet Address: ${WALLET_ADDRESS}`); console.log(`Chain ID: ${chainId}`); console.log(`RPC URL: ${rpcUrl}`); // Parse command line arguments const args = process.argv.slice(2); const mode = args[0] || 'simulate'; // Default to simulate mode // Example parameters const fromToken = SOL_ADDRESS; const toToken = USDC_ADDRESS; const amount = '10000000'; // 0.01 SOL in lamports const slippage = '0.05'; // 0.5% console.log('\nConfiguration:'); console.log(` From: ${fromToken} (SOL)`); console.log(` To: ${toToken} (USDC)`); console.log(` Amount: ${parseInt(amount) / 1e9} SOL`); console.log(` Slippage: ${slippage}%`); console.log(` Mode: ${mode}`); let result; switch (mode.toLowerCase()) { case 'simulate': case 'sim': result = await simulateOnly(fromToken, toToken, amount, slippage); break; case 'execute': case 'exec': result = await executeSwapWithSimulation(fromToken, toToken, amount, slippage); break; default: console.log('\nAvailable modes:'); console.log(' simulate/sim - Only simulate the transaction'); console.log(' execute/exec - Execute the full swap'); console.log('\nExample: npm run solana-swap simulate'); return; } if (result.success) { console.log('\nOperation completed successfully!'); if (mode === 'simulate' || mode === 'sim') { console.log(`Gas Limit: ${result.gasLimit}`); } else { console.log(`Transaction Hash: ${result.txHash}`); } } else { console.log('\nOperation failed!'); console.log(`Error: ${result.error}`); } } catch (error) { console.error('Main execution failed:', (error as Error).message); process.exit(1); } } // Run the script if (require.main === module) { main(); } // ============================================================================ // Exports // ============================================================================ export { executeSwap, executeSwapWithSimulation, simulateOnly, getSwapData, simulateTransaction, getGasLimit, broadcastTransaction, trackTransaction, signTransaction }; ``` You can run this script using `solana-swap-executor.ts sim` or `solana-swap-executor.ts exec`. `sim` simulates a transaction using swap data using the transaction simulation API and retruns `gasLimit` info `exec` executes a transaction using the broadcast API ## 8. MEV Protection ### MEV Protection with Broadcast Transaction API The OKX Broadcast Transaction API provides built-in MEV protection capabilities to help safeguard your transactions from front-running and sandwich attacks. The Broadcast API is available to our whitelisted customers only. Please reach out to dexapi@okx.com to request access. **Disclaimer:** Your end-user's transaction can only be covered by the MEV protection feature if you actually utilise OKX Build's API services for that particular transaction. MEV protection is currently an experimental feature provided by third-parties and OKX Build does not guarantee the effectiveness and quality of such MEV protection. #### Basic MEV Protection To enable MEV protection, add the `extraData` field to your broadcast transaction request with `enableMevProtection: true`: ```typescript /** * Broadcast transaction with MEV protection enabled */ async function broadcastTransactionWithMEV( signedTx: string, chainId: string = "501", walletAddress: string, enableMevProtection: boolean = true ): Promise { try { console.log('Broadcasting transaction with MEV protection...'); const path = 'dex/pre-transaction/broadcast-transaction'; const url = `https://web3.okx.com/api/v5/${path}`; const body = { signedTx: signedTx, chainIndex: chainId, address: walletAddress, extraData: JSON.stringify({ enableMevProtection: enableMevProtection }) }; const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { const orderId = response.data.data[0].orderId; console.log(`Transaction broadcast with MEV protection. Order ID: ${orderId}`); return orderId; } else { throw new Error(`Broadcast API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('MEV-protected broadcast failed:', error); throw error; } } ``` #### Jito Integration for Enhanced Protection For additional MEV protection on Solana, you can include Jito-specific parameters: ```typescript /** * Broadcast transaction with Jito MEV protection */ async function broadcastTransactionWithJito( signedTx: string, jitoSignedTx: string, chainId: string = "501", walletAddress: string ): Promise { try { console.log('Broadcasting transaction with Jito MEV protection...'); const path = 'dex/pre-transaction/broadcast-transaction'; const url = `https://web3.okx.com/api/v5/${path}`; const body = { signedTx: signedTx, chainIndex: chainId, address: walletAddress, extraData: JSON.stringify({ enableMevProtection: true, jitoSignedTx: jitoSignedTx }) }; const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { const orderId = response.data.data[0].orderId; console.log(`Transaction broadcast with Jito protection. Order ID: ${orderId}`); return orderId; } else { throw new Error(`Broadcast API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Jito-protected broadcast failed:', error); throw error; } } ``` #### Updated Broadcast Function with MEV Parameters Here's the updated `broadcastTransaction` function that includes MEV protection parameters: ```typescript /** * Enhanced broadcast transaction with MEV protection parameters */ async function broadcastTransaction( signedTx: string, chainId: string = "501", walletAddress: string, enableMevProtection: boolean = false, jitoSignedTx: string = "" ): Promise { try { console.log(`Broadcasting transaction${enableMevProtection ? ' with MEV protection' : ''}...`); const path = 'dex/pre-transaction/broadcast-transaction'; const url = `https://web3.okx.com/api/v5/${path}`; const body: any = { signedTx: signedTx, chainIndex: chainId, address: walletAddress }; // Add MEV protection parameters if enabled if (enableMevProtection || jitoSignedTx) { const extraData: any = {}; if (enableMevProtection) { extraData.enableMevProtection = true; } if (jitoSignedTx) { extraData.jitoSignedTx = jitoSignedTx; } body.extraData = JSON.stringify(extraData); } const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { const orderId = response.data.data[0].orderId; console.log(`Transaction broadcast successful. Order ID: ${orderId}`); return orderId; } else { throw new Error(`Broadcast API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Broadcast failed:', error); throw error; } } ``` #### Usage Examples **Basic swap without MEV protection:** ```typescript // Standard broadcast (no MEV protection) const orderId = await broadcastTransaction(signedTx, "501", walletAddress); ``` **Swap with MEV protection enabled:** ```typescript // With MEV protection const orderId = await broadcastTransaction(signedTx, "501", walletAddress, true); ``` **Swap with Jito MEV protection:** ```typescript // With Jito protection const orderId = await broadcastTransaction(signedTx, "501", walletAddress, true, jitoSignedTransaction); ``` **Swap with only Jito (no general MEV protection):** ```typescript // Only Jito protection const orderId = await broadcastTransaction(signedTx, "501", walletAddress, false, jitoSignedTransaction); ``` #### Integration with Complete Swap Flow Here's how to integrate MEV protection into your complete swap execution: ```typescript /** * Execute swap with MEV protection */ async function executeSwapWithMEVProtection( fromTokenAddress: string, toTokenAddress: string, amount: string, slippage: string = '0.005', enableMevProtection: boolean = true ): Promise { try { // Step 1: Get swap data const swapData = await getSwapData(fromTokenAddress, toTokenAddress, amount, slippage); // Step 2: Prepare and sign transaction const { transaction } = await prepareTransaction(swapData.tx.data); const signedTx = await signTransaction(transaction); // Step 3: Broadcast with MEV protection const orderId = await broadcastTransaction(signedTx, "501", userAddress, enableMevProtection); // Step 4: Track transaction const result = await trackTransaction(orderId); return result.txHash; } catch (error) { console.error("MEV-protected swap failed:", error); throw error; } } ``` The MEV protection feature integrates seamlessly with your existing EVM and Solana swap implementation and provides an additional layer of security against MEV attacks across Solana, Base, Ethereum, and BSC. ## Method 2: SDK approach Using the OKX DEX SDK provides a much simpler developer experience while retaining all the functionality of the API-first approach. The SDK handles many implementation details for you, including retry logic, error handling, and transaction management. ## 1. Install the SDK ```typescript npm install @okx-dex/okx-dex-sdk # or yarn add @okx-dex/okx-dex-sdk # or pnpm add @okx-dex/okx-dex-sdk ``` ## 2. Setup Your Environment Create a .env file with your API credentials and wallet information: ```typescript # OKX API Credentials OKX_API_KEY=your_api_key OKX_SECRET_KEY=your_secret_key OKX_API_PASSPHRASE=your_passphrase OKX_PROJECT_ID=your_project_id # Solana Configuration SOLANA_RPC_URL=your_solana_rpc_url SOLANA_WALLET_ADDRESS=your_solana_wallet_address SOLANA_PRIVATE_KEY=your_solana_private_key # Ethereum Configuration EVM_RPC_URL=your_evm_rpc_url EVM_WALLET_ADDRESS=your_evm_wallet_address EVM_PRIVATE_KEY=your_evm_private_key ``` ## 3. Initialize the Client Create a file for your DEX client (e.g., DexClient.ts): ```typescript import { OKXDexClient } from '@okx-dex/okx-dex-sdk'; import { createEVMWallet } from '@okx-dex/okx-dex-sdk/core/evm-wallet'; import { createWallet } from '@okx-dex/okx-dex-sdk/core/wallet'; import { Connection } from '@solana/web3.js'; import { ethers } from 'ethers'; import dotenv from 'dotenv'; dotenv.config(); // EVM setup (Ethereum, Base, Arbitrum, etc.) const evmProvider = new ethers.JsonRpcProvider(process.env.EVM_RPC_URL!); const evmWallet = createEVMWallet(process.env.EVM_PRIVATE_KEY!, evmProvider); // Solana setup const solanaConnection = new Connection(process.env.SOLANA_RPC_URL!); const solanaWallet = createWallet(process.env.SOLANA_PRIVATE_KEY!, solanaConnection); // Initialize the client const client = new OKXDexClient({ // API credentials (get from OKX Developer Portal) apiKey: process.env.OKX_API_KEY!, secretKey: process.env.OKX_SECRET_KEY!, apiPassphrase: process.env.OKX_API_PASSPHRASE!, projectId: process.env.OKX_PROJECT_ID!, // EVM configuration (works for all EVM chains) evm: { wallet: evmWallet }, // Solana configuration solana: { wallet: solanaWallet, computeUnits: 300000, // Optional maxRetries: 3 // Optional }, }) ``` ## 4. Execute a Swap With the SDK Create a swap execution file: ```typescript // swap.ts import { client } from './DexClient'; /** * Example: Execute a swap from SOL to USDC */ async function executeSwap() { try { if (!process.env.SOLANA_PRIVATE_KEY) { throw new Error('Missing SOLANA_PRIVATE_KEY in .env file'); } // Get quote to fetch token information console.log("Getting token information..."); const quote = await client.dex.getQuote({ chainId: '501', fromTokenAddress: '11111111111111111111111111111111', // SOL toTokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC amount: '1000000', // Small amount for quote slippage: '0.005' // 0.5% slippage }); const tokenInfo = { fromToken: { symbol: quote.data[0].fromToken.tokenSymbol, decimals: parseInt(quote.data[0].fromToken.decimal), price: quote.data[0].fromToken.tokenUnitPrice }, toToken: { symbol: quote.data[0].toToken.tokenSymbol, decimals: parseInt(quote.data[0].toToken.decimal), price: quote.data[0].toToken.tokenUnitPrice } }; // Convert amount to base units (for display purposes) const humanReadableAmount = 0.1; // 0.1 SOL const rawAmount = (humanReadableAmount * Math.pow(10, tokenInfo.fromToken.decimals)).toString(); console.log("\nSwap Details:"); console.log("--------------------"); console.log(`From: ${tokenInfo.fromToken.symbol}`); console.log(`To: ${tokenInfo.toToken.symbol}`); console.log(`Amount: ${humanReadableAmount} ${tokenInfo.fromToken.symbol}`); console.log(`Amount in base units: ${rawAmount}`); console.log(`Approximate USD value: $${(humanReadableAmount * parseFloat(tokenInfo.fromToken.price)).toFixed(2)}`); // Execute the swap console.log("\nExecuting swap..."); const swapResult = await client.dex.executeSwap({ chainId: '501', // Solana chain ID fromTokenAddress: '11111111111111111111111111111111', // SOL toTokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC amount: rawAmount, slippage: '0.005', // 0.5% slippage userWalletAddress: process.env.SOLANA_WALLET_ADDRESS! }); console.log('Swap executed successfully:'); console.log(JSON.stringify(swapResult, null, 2)); return swapResult; } catch (error) { if (error instanceof Error) { console.error('Error executing swap:', error.message); // API errors include details in the message if (error.message.includes('API Error:')) { const match = error.message.match(/API Error: (.*)/); if (match) console.error('API Error Details:', match[1]); } } throw error; } } // Run if this file is executed directly if (require.main === module) { executeSwap() .then(() => process.exit(0)) .catch((error) => { console.error('Error:', error); process.exit(1); }); } export { executeSwap }; ``` ## 5. Additional SDK Functionality The SDK provides additional methods that simplify development: Get a quote for a token pair ```typescript const quote = await client.dex.getQuote({ chainId: '501', // Solana fromTokenAddress: '11111111111111111111111111111111', // SOL toTokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC amount: '100000000', // 0.1 SOL (in lamports) slippage: '0.005' // 0.5% slippage }); ``` - [Advanced Control With Swap-Instructions on Solana](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-use-swap-solana-advance-control.md) # Advanced Control With Swap-Instructions on Solana The `swap-instruction` endpoint offers more control over the swap process than the standard `/swap` endpoint. While `/swap` gives you a pre-built transaction ready to sign, `swap-instruction` lets you: - Build custom transaction signing flows - Handle instruction processing your own way - Add your own instructions to the transaction if needed - Work with lookup tables directly for optimizing transaction size ## 1. Set Up Your Environment Import the necessary libraries: ```javascript // Required Solana dependencies for DEX interaction import { Connection, // Handles RPC connections to Solana network Keypair, // Manages wallet keypairs for signing PublicKey, // Handles Solana public key conversion and validation TransactionInstruction, // Core transaction instruction type TransactionMessage, // Builds transaction messages (v0 format) VersionedTransaction, // Supports newer transaction format with lookup tables RpcResponseAndContext, // RPC response wrapper type SimulatedTransactionResponse, // Simulation result type AddressLookupTableAccount, // For transaction size optimization PublicKeyInitData // Public key input type } from "@solana/web3.js"; import base58 from "bs58"; // Required for private key decoding ``` ## 2. Initialize Your Connection and Wallet Set up your connection and wallet instance: ```javascript // Note: Consider using a reliable RPC endpoint with high rate limits for production const connection = new Connection( process.env.SOLANA_RPC_URL || "https://api.mainnet-beta.solana.com" ); // Initialize wallet for signing // This wallet will be the fee payer and transaction signer const wallet = Keypair.fromSecretKey( Uint8Array.from(base58.decode(userPrivateKey)) ); ``` ## 3. Configure Swap Parameters Set up the parameters for your swap: ```javascript // Configure swap parameters const baseUrl = "https://web3.okx.com/api/v6/dex/aggregator/swap-instruction"; const params = { chainId: "501", // Solana mainnet chain ID feePercent: "1", // Platform fee percentage amount: "1000000", // Amount in smallest denomination (lamports for SOL) fromTokenAddress: "11111111111111111111111111111111", // SOL mint address toTokenAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC mint address slippage: "0.1", // Slippage tolerance 10% userWalletAddress: userAddress, // Wallet performing the swap priceTolerance: "0", // Maximum allowed price impact autoSlippage: "false", // Use fixed slippage instead of auto pathNum: "3" // Maximum routes to consider }; ``` ## 4. Process Swap Instructions Fetch and process the swap instructions: ```javascript // Helper function to convert DEX API instructions to Solana format function createTransactionInstruction(instruction) { return new TransactionInstruction({ programId: new PublicKey(instruction.programId), // DEX program ID keys: instruction.accounts.map((key) => ({ pubkey: new PublicKey(key.pubkey), // Account address isSigner: key.isSigner, // True if account must sign tx isWritable: key.isWritable // True if instruction modifies account })), data: Buffer.from(instruction.data, 'base64') // Instruction parameters }); } // Fetch optimal swap route and instructions from DEX const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/aggregator/swap-instruction"; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); const response = await fetch( `https://web3.okx.com${requestPath}${queryString}`, { method: 'GET', headers } ); const { data } = await response.json(); const { instructionLists, addressLookupTableAccount } = data; // Process DEX instructions into Solana-compatible format const instructions = []; // Remove duplicate lookup table addresses returned by DEX const uniqueLookupTables = Array.from(new Set(addressLookupTableAccount)); console.log("Lookup tables to load:", uniqueLookupTables); // Convert each DEX instruction to Solana format if (instructionLists?.length) { instructions.push(...instructionLists.map(createTransactionInstruction)); } ``` ## 5. Handle Address Lookup Tables Process the address lookup tables for transaction optimization: ```javascript // Process lookup tables for transaction optimization // Lookup tables are crucial for complex swaps that interact with many accounts // They significantly reduce transaction size and cost const addressLookupTableAccounts = []; if (uniqueLookupTables?.length > 0) { console.log("Loading address lookup tables..."); // Fetch all lookup tables in parallel for better performance const lookupTableAccounts = await Promise.all( uniqueLookupTables.map(async (address) => { const pubkey = new PublicKey(address); // Get lookup table account data from Solana const account = await connection .getAddressLookupTable(pubkey) .then((res) => res.value); if (!account) { throw new Error(`Could not fetch lookup table account ${address}`); } return account; }) ); addressLookupTableAccounts.push(...lookupTableAccounts); } ``` ## 6. Create and Sign Transaction Create the transaction message and sign it: ```javascript // Get recent blockhash for transaction timing and uniqueness const latestBlockhash = await connection.getLatestBlockhash('finalized'); // Create versioned transaction message (V0 format required for lookup table support) const messageV0 = new TransactionMessage({ payerKey: wallet.publicKey, // Fee payer address recentBlockhash: latestBlockhash.blockhash, // Transaction timing instructions // Swap instructions from DEX }).compileToV0Message(addressLookupTableAccounts); // Include lookup tables // Create new versioned transaction with optimizations const transaction = new VersionedTransaction(messageV0); // Simulate transaction to check for errors // This helps catch issues before paying fees const result = await connection.simulateTransaction(transaction); // Sign transaction with fee payer wallet transaction.sign([wallet]); ``` ## 7. Execute Transaction Finally, simulate and send the transaction: ```javascript // Send transaction to Solana // skipPreflight=false ensures additional validation // maxRetries helps handle network issues const txId = await connection.sendRawTransaction(transaction.serialize(), { skipPreflight: false, // Run preflight validation maxRetries: 5 // Retry on failure }); // Log transaction results console.log("Transaction ID:", txId); console.log("Explorer URL:", `https://solscan.io/tx/${txId}`); // Wait for confirmation await connection.confirmTransaction({ signature: txId, blockhash: latestBlockhash.blockhash, lastValidBlockHeight: latestBlockhash.lastValidBlockHeight }); console.log("Transaction confirmed!"); ``` ## Best Practices and Considerations When implementing swap instructions, keep these key points in mind: - Error Handling: Always implement proper error handling for API responses and transaction simulation results. - Slippage Protection: Choose appropriate slippage parameters based on your use case and market conditions. - Gas Optimization: Use address lookup tables when available to reduce transaction size and costs. - Transaction Simulation: Always simulate transactions before sending them to catch potential issues early. - Retry Logic: Implement proper retry mechanisms for failed transactions with appropriate backoff strategies. MEV Protection Trading on Solana comes with MEV (Maximal Extractable Value) risks. While the MEV protection is not directly included in the SDK, you can implement it yourself using the API-first approach. - [Build Swap Applications on EVM](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-use-swap-quick-start.md) # Build Swap Applications on EVM There are two approaches to building swap applications with OKX DEX on EVM networks: 1. The API-first approach - directly interacting with OKX DEX API endpoints 2. The SDK approach - using the @okx-dex/okx-dex-sdk package for a simplified developer experience This guide covers both methods to help you choose the approach that best fits your needs. ## Method 1: API-First Approach This approach demonstrates a token swap using the OKX DEX API endpoints directly. You will swap USDC to ETH on the Ethereum network. ## 1. Set Up Your Environment ```typescript // --------------------- npm package --------------------- import { Web3 } from 'web3'; import axios from 'axios'; import * as dotenv from 'dotenv'; import CryptoJS from 'crypto-js'; // The URL for the Ethereum node you want to connect to const web3 = new Web3('https://......com'); // --------------------- environment variable --------------------- // Load hidden environment variables dotenv.config(); // Your wallet information - REPLACE WITH YOUR OWN VALUES const WALLET_ADDRESS: string = process.env.EVM_WALLET_ADDRESS || '0xYourWalletAddress'; const PRIVATE_KEY: string = process.env.EVM_PRIVATE_KEY || 'YourPrivateKey'; // Token addresses for swap on Base Chain const ETH_ADDRESS: string = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'; // Native ETH const USDC_ADDRESS: string = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'; // USDC on Base // Chain ID for Base Chain const chainId: string = '8453'; // API URL const baseUrl: string = 'https://web3.okx.com/api/v5/'; // Amount to swap in smallest unit (0.0005 ETH) const SWAP_AMOUNT: string = '500000000000000'; // 0.0005 ETH const SLIPPAGE: string = '0.005'; // 0.5% slippage tolerance // --------------------- util function --------------------- export function getHeaders(timestamp: string, method: string, requestPath: string, queryString = "") { // Check https://web3.okx.com/zh-hans/web3/build/docs/waas/rest-authentication for api-key const apiKey = process.env.OKX_API_KEY; const secretKey = process.env.OKX_SECRET_KEY; const apiPassphrase = process.env.OKX_API_PASSPHRASE; const projectId = process.env.OKX_PROJECT_ID; if (!apiKey || !secretKey || !apiPassphrase || !projectId) { throw new Error("Missing required environment variables"); } const stringToSign = timestamp + method + requestPath + queryString; return { "Content-Type": "application/json", "OK-ACCESS-KEY": apiKey, "OK-ACCESS-SIGN": CryptoJS.enc.Base64.stringify( CryptoJS.HmacSHA256(stringToSign, secretKey) ), "OK-ACCESS-TIMESTAMP": timestamp, "OK-ACCESS-PASSPHRASE": apiPassphrase, "OK-ACCESS-PROJECT": projectId, }; }; ``` ## 2. Check Allowance You need to check if the token has been approved for the DEX to spend. This step is only needed for ERC20 tokens, not for native tokens like ETH. ```typescript /** * Check token allowance for DEX * @param tokenAddress - Token contract address * @param ownerAddress - Your wallet address * @param spenderAddress - DEX spender address * @returns Allowance amount */ async function checkAllowance( tokenAddress: string, ownerAddress: string, spenderAddress: string ): Promise { const tokenABI = [ { "constant": true, "inputs": [ { "name": "_owner", "type": "address" }, { "name": "_spender", "type": "address" } ], "name": "allowance", "outputs": [{ "name": "", "type": "uint256" }], "payable": false, "stateMutability": "view", "type": "function" } ]; const tokenContract = new web3.eth.Contract(tokenABI, tokenAddress); try { const allowance = await tokenContract.methods.allowance(ownerAddress, spenderAddress).call(); return BigInt(String(allowance)); } catch (error) { console.error('Failed to query allowance:', error); throw error; } } ``` ## 3. Check the Approval Parameters and Initiate the Approval If the allowance is lower than the amount you want to swap, you need to approve the token.
3.1 Define your transaction approval parameters ```typescript const getApproveTransactionParams = { chainId: chainId, tokenContractAddress: tokenAddress, approveAmount: amount }; ``` 3.2 Define helper functions ```typescript async function getApproveTransaction( tokenAddress: string, amount: string ): Promise { try { const path = 'dex/aggregator/approve-transaction'; const url = `${baseUrl}${path}`; const params = { chainId: chainId, tokenContractAddress: tokenAddress, approveAmount: amount }; // Prepare authentication const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); if (response.data.code === '0') { return response.data.data[0]; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get approval transaction data:', (error as Error).message); throw error; } } ``` 3.3 Create Compute gasLimit utility function Using the Onchain gateway API to get the gas limit. ```typescript /** * Get transaction gas limit from Onchain gateway API * @param fromAddress - Sender address * @param toAddress - Target contract address * @param txAmount - Transaction amount (0 for approvals) * @param inputData - Transaction calldata * @returns Estimated gas limit */ async function getGasLimit( fromAddress: string, toAddress: string, txAmount: string = '0', inputData: string = '' ): Promise { try { const path = 'dex/pre-transaction/gas-limit'; const url = `https://web3.okx.com/api/v5/${path}`; const body = { chainIndex: chainId, fromAddress: fromAddress, toAddress: toAddress, txAmount: txAmount, extJson: { inputData: inputData } }; // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { return response.data.data[0].gasLimit; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get gas limit:', (error as Error).message); throw error; } } ``` Using RPC to get the gas limit. ```typescript const gasLimit = await web3.eth.estimateGas({ from: WALLET_ADDRESS, to: tokenAddress, value: '0', data: approveData.data }); // Add 20% buffer const gasLimit = (BigInt(gasLimit) * BigInt(12) / BigInt(10)).toString(); ``` 3.4 Get transaction information and send approveTransaction ```typescript /** * Sign and send approve transaction * @param tokenAddress - Token to approve * @param amount - Amount to approve * @returns Transaction hash of the approval transaction */ async function approveToken(tokenAddress: string, amount: string): Promise { const spenderAddress = '0x3b3ae790Df4F312e745D270119c6052904FB6790'; // Ethereum Mainnet DEX spender // See Router addresses at: https://web3.okx.com/build/docs/waas/dex-smart-contract const currentAllowance = await checkAllowance(tokenAddress, WALLET_ADDRESS, spenderAddress); if (currentAllowance >= BigInt(amount)) { console.log('Sufficient allowance already exists'); return null; } console.log('Insufficient allowance, approving tokens...'); // Get approve transaction data from OKX DEX API const approveData = await getApproveTransaction(tokenAddress, amount); // Get accurate gas limit using RPC const gasLimit = await web3.eth.estimateGas({ from: WALLET_ADDRESS, to: tokenAddress, value: '0', data: approveData.data }); // Get accurate gas limit using Onchain gateway API // const gasLimit = await getGasLimit(WALLET_ADDRESS, tokenAddress, '0', approveData.data); // Get current gas price const gasPrice = await web3.eth.getGasPrice(); const adjustedGasPrice = BigInt(gasPrice) * BigInt(15) / BigInt(10); // 1.5x for faster confirmation // Get current nonce const nonce = await web3.eth.getTransactionCount(WALLET_ADDRESS, 'latest'); // Create transaction object const txObject = { from: WALLET_ADDRESS, to: tokenAddress, data: approveData.data, value: '0', gas: gasLimit, gasPrice: adjustedGasPrice.toString(), nonce: nonce }; // Sign and broadcast transaction const signedTx = await web3.eth.accounts.signTransaction(txObject, PRIVATE_KEY); const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction); console.log(`Approval transaction successful: ${receipt.transactionHash}`); return receipt.transactionHash; } ``` ## 4. Get Quote Data 4.1 Define quote parameters ```typescript const quoteParams = { amount: fromAmount, chainId: chainId, toTokenAddress: toTokenAddress, fromTokenAddress: fromTokenAddress, }; ``` 4.2 Define helper functions ```typescript /** * Get swap quote from DEX API * @param fromTokenAddress - Source token address * @param toTokenAddress - Destination token address * @param amount - Amount to swap * @param slippage - Maximum slippage (e.g., "0.005" for 0.5%) * @returns Swap quote */ async function getSwapQuote( fromTokenAddress: string, toTokenAddress: string, amount: string, slippage: string = '0.005' ): Promise { try { const path = 'dex/aggregator/quote'; const url = `${baseUrl}${path}`; const params = { chainId: chainId, fromTokenAddress, toTokenAddress, amount, slippage }; // Prepare authentication const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); if (response.data.code === '0') { return response.data.data[0]; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get swap quote:', (error as Error).message); throw error; } } ``` ## 5. Prepare Transaction 5.1 Define swap parameters ```typescript const swapParams = { chainId: chainId, fromTokenAddress, toTokenAddress, amount, userWalletAddress: userAddress, slippage }; ``` 5.2 Request swap transaction data ```typescript /** * Get swap transaction data from DEX API * @param fromTokenAddress - Source token address * @param toTokenAddress - Destination token address * @param amount - Amount to swap * @param userAddress - User wallet address * @param slippage - Maximum slippage (e.g., "0.005" for 0.5%) * @returns Swap transaction data */ async function getSwapTransaction( fromTokenAddress: string, toTokenAddress: string, amount: string, userAddress: string, slippage: string = '0.005' ): Promise { try { const path = 'dex/aggregator/swap'; const url = `${baseUrl}${path}`; const params = { chainId: chainId, fromTokenAddress, toTokenAddress, amount, userWalletAddress: userAddress, slippage }; // Prepare authentication const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); if (response.data.code === '0') { return response.data.data[0]; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get swap transaction data:', (error as Error).message); throw error; } } ``` ## 6. Simulate Transaction Before executing the actual swap, it's crucial to simulate the transaction to ensure it will succeed and to identify any potential issues: The Simulate API is available to our whitelisted customers only. Please reach out to dexapi@okx.com to request access. ```typescript async function simulateTransaction(swapData: any) { try { if (!swapData.tx) { throw new Error('Invalid swap data format - missing transaction data'); } const tx = swapData.tx; const params: any = { fromAddress: tx.from, toAddress: tx.to, txAmount: tx.value || '0', chainIndex: chainId, extJson: { inputData: tx.data }, includeDebug: true }; const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/pre-transaction/simulate"; const requestBody = JSON.stringify(params); const headers = getHeaders(timestamp, "POST", requestPath, "", requestBody); console.log('Simulating transaction...'); const response = await axios.post( `https://web3.okx.com${requestPath}`, params, { headers } ); if (response.data.code !== "0") { throw new Error(`Simulation failed: ${response.data.msg || "Unknown simulation error"}`); } const simulationResult = response.data.data[0]; // Check simulation success if (simulationResult.success === false) { console.error('Transaction simulation failed:', simulationResult.error); throw new Error(`Transaction would fail: ${simulationResult.error}`); } console.log('Transaction simulation successful'); console.log(`Estimated gas used: ${simulationResult.gasUsed || 'N/A'}`); if (simulationResult.logs) { console.log('Simulation logs:', simulationResult.logs); } return simulationResult; } catch (error) { console.error("Error simulating transaction:", error); throw error; } } ``` ## 7. Broadcast Transaction Creating a Compute Gas Limit Utility Function There are two approaches to obtain the gas limit for your transactions: using standard RPC calls or leveraging the Onchain Gateway API. Method 1: Using the Onchain Gateway API for Gas Estimation The first approach leverages OKX's Onchain Gateway API, which provides more accurate gas estimations than standard methods. ```typescript /** * Get transaction gas limit from Onchain gateway API * @param fromAddress - Sender address * @param toAddress - Target contract address * @param txAmount - Transaction amount (0 for approvals) * @param inputData - Transaction calldata * @returns Estimated gas limit */ async function getGasLimit( fromAddress: string, toAddress: string, txAmount: string = '0', inputData: string = '' ): Promise { try { const path = 'dex/pre-transaction/gas-limit'; const url = `https://web3.okx.com/api/v5/${path}`; const body = { chainIndex: chainId, fromAddress: fromAddress, toAddress: toAddress, txAmount: txAmount, extJson: { inputData: inputData } }; // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { return response.data.data[0].gasLimit; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get gas limit:', (error as Error).message); throw error; } } ``` Method 2: Using RPC to Estimate Gas Limit The second approach utilizes standard Web3 RPC calls to estimate the required gas for your transaction. ```typescript const gasLimit = await web3.eth.estimateGas({ from: WALLET_ADDRESS, to: tokenAddress, value: '0', data: swapData.data }); // Add 20% buffer const gasLimit = (BigInt(gasLimit) * BigInt(12) / BigInt(10)).toString(); ``` Broadcasting Transactions with the Onchain Gateway API For developers with access to the Onchain Gateway API, you can broadcast transactions directly through OKX's infrastructure. This method provides enhanced reliability and monitoring capabilities for high-volume trading operations. The Broadcast API requires API is available to our whitelisted customers only. Please reach out to dexapi@okx.com to request access. ```typescript import { Web3 } from 'web3'; import axios from 'axios'; import * as dotenv from 'dotenv'; import CryptoJS from 'crypto-js'; // Load environment variables dotenv.config(); // Connect to Base network const web3 = new Web3(process.env.EVM_RPC_URL || 'https://mainnet.base.org'); // Your wallet information - REPLACE WITH YOUR OWN VALUES const WALLET_ADDRESS = process.env.EVM_WALLET_ADDRESS || ''; const PRIVATE_KEY = process.env.EVM_PRIVATE_KEY || ''; // Token addresses for swap on Base Chain const ETH_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'; // Native ETH // Chain ID for Base Chain const chainId = '8453'; // API URL const baseUrl = 'https://web3.okx.com/api/v5/'; // Define interfaces interface GasLimitApiResponse { code: string; msg?: string; data: Array<{ gasLimit: string; }>; } // Interface for broadcast API response interface BroadcastApiResponse { code: string; msg?: string; data: Array<{ orderId: string; }>; } /** * Generate API authentication headers */ function getHeaders(timestamp: string, method: string, requestPath: string, queryString = "", body = "") { const apiKey = process.env.OKX_API_KEY; const secretKey = process.env.OKX_SECRET_KEY; const apiPassphrase = process.env.OKX_API_PASSPHRASE; const projectId = process.env.OKX_PROJECT_ID; if (!apiKey || !secretKey || !apiPassphrase || !projectId) { throw new Error("Missing required environment variables for API authentication"); } const stringToSign = timestamp + method + requestPath + (queryString || body); return { "Content-Type": "application/json", "OK-ACCESS-KEY": apiKey, "OK-ACCESS-SIGN": CryptoJS.enc.Base64.stringify( CryptoJS.HmacSHA256(stringToSign, secretKey) ), "OK-ACCESS-TIMESTAMP": timestamp, "OK-ACCESS-PASSPHRASE": apiPassphrase, "OK-ACCESS-PROJECT": projectId, }; } /** * Get transaction gas limit from Onchain gateway API * @param fromAddress - Sender address * @param toAddress - Target contract address * @param txAmount - Transaction amount (0 for approvals) * @param inputData - Transaction calldata * @returns Estimated gas limit */ async function getGasLimit( fromAddress: string, toAddress: string, txAmount: string = '0', inputData: string = '' ): Promise { const path = 'dex/pre-transaction/gas-limit'; const url = `${baseUrl}${path}`; const body = { chainIndex: chainId, fromAddress, toAddress, txAmount, extJson: { inputData } }; const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const headers = getHeaders(timestamp, 'POST', `/api/v5/${path}`, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { return response.data.data[0].gasLimit; } throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } /** * Get swap data from OKX API */ async function getSwapData( fromTokenAddress: string, toTokenAddress: string, amount: string, slippage = '0.5' ) { const path = 'dex/aggregator/swap'; const url = `${baseUrl}${path}`; const params = { chainIndex: chainId, fromTokenAddress, toTokenAddress, amount, slippage, userWalletAddress: WALLET_ADDRESS }; const queryString = "?" + new URLSearchParams(params).toString(); const timestamp = new Date().toISOString(); const headers = getHeaders(timestamp, 'GET', `/api/v5/${path}`, queryString); const response = await axios.get(`${url}${queryString}`, { headers }); const responseData = response.data as any; if (responseData.code === '0') { return responseData.data[0]; } throw new Error(`Swap API Error: ${responseData.msg || 'Unknown error'}`); } /** * Build and sign transaction using gas limit */ async function buildAndSignTransaction(swapData: any, gasLimit: string): Promise { const gasPrice = await web3.eth.getGasPrice(); const nonce = await web3.eth.getTransactionCount(WALLET_ADDRESS, 'pending'); const transaction = { from: swapData.tx.from, to: swapData.tx.to, data: swapData.tx.data, value: swapData.tx.value || '0x0', gas: gasLimit, gasPrice: gasPrice.toString(), nonce: Number(nonce), chainId: parseInt(chainId) }; return await web3.eth.accounts.signTransaction(transaction, PRIVATE_KEY); } /** * Broadcast transaction using Onchain Gateway API */ async function broadcastTransaction(signedTx: any, chainId: string, walletAddress: string): Promise { const path = 'dex/pre-transaction/broadcast-transaction'; const url = `${baseUrl}${path}`; const rawTxHex = typeof signedTx.rawTransaction === 'string' ? signedTx.rawTransaction : web3.utils.bytesToHex(signedTx.rawTransaction); const body = { signedTx: rawTxHex, chainIndex: chainId, address: walletAddress }; const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const headers = getHeaders(timestamp, 'POST', `/api/v5/${path}`, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { return response.data.data[0].orderId; } throw new Error(`Broadcast API Error: ${response.data.msg || 'Unknown error'}`); } async function main() { try { console.log('EVM Gas Limit and Broadcast'); console.log('================================'); // Validate environment variables if (!WALLET_ADDRESS || !PRIVATE_KEY) { throw new Error('Missing wallet address or private key in environment variables'); } console.log(`Wallet Address: ${WALLET_ADDRESS}`); console.log(`Chain ID: ${chainId}`); console.log(`RPC URL: ${process.env.EVM_RPC_URL || 'https://mainnet.base.org'}`); // Example parameters const fromToken = ETH_ADDRESS; const toToken = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'; // USDC on Base const amount = '100000000000000'; // 0.0001 ETH in wei const slippage = '0.05'; // 0.5% // Step 1: Get swap data const swapData = await getSwapData(fromToken, toToken, amount, slippage); console.log('Swap data obtained'); // Step 2: Get gas limit const gasLimit = await getGasLimit( swapData.tx.from, swapData.tx.to, swapData.tx.value || '0', swapData.tx.data ); console.log('Gas limit obtained', gasLimit); // Step 3: Build and sign transaction const signedTx = await buildAndSignTransaction(swapData, gasLimit); console.log('Transaction built and signed'); // Step 4: Broadcast transaction try { const orderId = await broadcastTransaction(signedTx, chainId, swapData.tx.from); console.log(`Transaction broadcast successful. Order ID: ${orderId}`); } catch (broadcastError: any) { if (broadcastError.message.includes('API registration and whitelist required')) { console.log('Broadcast failed - API registration and whitelist required'); console.log('Gas limit obtained successfully:', gasLimit); } else { throw broadcastError; } } } catch (error) { console.error('Main execution failed:', (error as Error).message); process.exit(1); } } // Run the script if (require.main === module) { main(); } export { getSwapData, getGasLimit, broadcastTransaction }; ``` Alternative: Broadcasting Transactions Using Standard RPC For developers who prefer using standard blockchain RPC methods or do not have yet requested API whitelisting, you can broadcast transactions directly to the network using Web3 RPC calls. ```typescript /** * Execute token swap * @param fromTokenAddress - Source token address * @param toTokenAddress - Destination token address * @param amount - Amount to swap * @param slippage - Maximum slippage * @returns Transaction hash */ async function executeSwap( fromTokenAddress: string, toTokenAddress: string, amount: string, slippage: string = '0.005' ): Promise { // 1. Check allowance and approve if necessary (skip for native token) if (fromTokenAddress !== ETH_ADDRESS) { await approveToken(fromTokenAddress, amount); } // 2. Get swap transaction data const swapData = await getSwapTransaction(fromTokenAddress, toTokenAddress, amount, WALLET_ADDRESS, slippage); const txData = swapData.tx; console.log("Swap TX data received"); // 3. Get accurate gas limit const gasLimit = await getGasLimit( WALLET_ADDRESS, txData.to, txData.value || '0', txData.data ); console.log("Gas limit received"); // 4. Get current nonce const nonce = await web3.eth.getTransactionCount(WALLET_ADDRESS, 'latest'); console.log("Nonce received"); // 5. Get current gas price and adjust for faster confirmation const gasPrice = await web3.eth.getGasPrice(); const adjustedGasPrice = BigInt(gasPrice) * BigInt(15) / BigInt(10); // 1.5x for faster confirmation console.log("Gas price received"); // 6. Create transaction object const txObject = { from: WALLET_ADDRESS, to: txData.to, data: txData.data, value: txData.value || '0', gas: gasLimit, gasPrice: adjustedGasPrice.toString(), nonce: nonce }; console.log("TX build complete"); // 7. Sign and broadcast transaction using RPC const signedTx = await web3.eth.accounts.signTransaction(txObject, PRIVATE_KEY); console.log("TX signed"); const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction); console.log(`Transaction successful: ${receipt.transactionHash}`); return receipt.transactionHash; } ``` ## 8. Track Transaction Choose the first(section 8.1) for basic transaction confirmation status, and the second(section 8.2) when you need detailed information about the swap execution itself. 8.1 Using Onchain gateway API The Onchain gateway API provides transaction tracking capabilities through the `/dex/post-transaction/orders` endpoint. Use the order ID returned by the broadcast API to track transactions as they progress through OKX's systems with simple status codes (1: Pending, 2: Success, 3: Failed). ```typescript // Define error info interface interface TxErrorInfo { error: string; message: string; action: string; } /** * Tracking transaction confirmation status using the Onchain gateway API * @param orderId - Order ID from broadcast response * @param intervalMs - Polling interval in milliseconds * @param timeoutMs - Maximum time to wait * @returns Final transaction confirmation status */ async function trackTransaction( orderId: string, intervalMs: number = 5000, timeoutMs: number = 300000 ): Promise { console.log(`Tracking transaction with Order ID: ${orderId}`); const startTime = Date.now(); let lastStatus = ''; while (Date.now() - startTime < timeoutMs) { // Get transaction status try { const path = 'dex/post-transaction/orders'; const url = `https://web3.okx.com/api/v5/${path}`; const params = { orderId: orderId, chainIndex: chainId, address: WALLET_ADDRESS, limit: '1' }; // Prepare authentication const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); if (response.data.code === '0' && response.data.data && response.data.data.length > 0) { if (response.data.data[0].orders && response.data.data[0].orders.length > 0) { const txData = response.data.data[0].orders[0]; // Use txStatus to match the API response const status = txData.txStatus; // Only log when status changes if (status !== lastStatus) { lastStatus = status; if (status === '1') { console.log(`Transaction pending: ${txData.txHash || 'Hash not available yet'}`); } else if (status === '2') { console.log(`Transaction successful: https://web3.okx.com/explorer/base/tx/${txData.txHash}`); return txData; } else if (status === '3') { const failReason = txData.failReason || 'Unknown reason'; const errorMessage = `Transaction failed: ${failReason}`; console.error(errorMessage); const errorInfo = handleTransactionError(txData); console.log(`Error type: ${errorInfo.error}`); console.log(`Suggested action: ${errorInfo.action}`); throw new Error(errorMessage); } } } else { console.log(`No orders found for Order ID: ${orderId}`); } } } catch (error) { console.warn('Error checking transaction status:', (error as Error).message); } // Wait before next check await new Promise(resolve => setTimeout(resolve, intervalMs)); } throw new Error('Transaction tracking timed out'); } /** * Comprehensive error handling with failReason * @param txData - Transaction data from post-transaction/orders * @returns Structured error information */ function handleTransactionError(txData: any): TxErrorInfo { const failReason = txData.failReason || 'Unknown reason'; // Log the detailed error console.error(`Transaction failed with reason: ${failReason}`); // Default error handling return { error: 'TRANSACTION_FAILED', message: failReason, action: 'Try again or contact support' }; } ``` 8.2 Track transaction using SWAP API: SWAP API transaction tracking provides comprehensive swap execution details using the `/dex/aggregator/history` endpoint. It offers token-specific information (symbols, amounts), fees paid, and detailed blockchain data. Use this when you need complete swap insight with token-level details. ```typescript /** * Track transaction using SWAP API * @param chainId - Chain ID (e.g., 1 for Ethereum Mainnet) * @param txHash - Transaction hash * @returns Transaction details */ async function trackTransactionWithSwapAPI(chainId: string, txHash: string): Promise { try { const path = 'dex/aggregator/history'; const url = `${baseUrl}${path}`; const params = { chainId: chainId, txHash: txHash, isFromMyProject: 'true' }; // Prepare authentication const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); if (response.data.code === '0') { const txData = response.data.data[0]; const status = txData.status; if (status === 'pending') { console.log(`Transaction is still pending: ${txHash}`); return { status: 'pending', details: txData }; } else if (status === 'success') { console.log(`Transaction successful!`); console.log(`From: ${txData.fromTokenDetails.symbol} - Amount: ${txData.fromTokenDetails.amount}`); console.log(`To: ${txData.toTokenDetails.symbol} - Amount: ${txData.toTokenDetails.amount}`); console.log(`Transaction Fee: ${txData.txFee}`); console.log(`Explorer URL: https://basescan.org/tx/${txHash}`); return { status: 'success', details: txData }; } else if (status === 'failure') { console.error(`Transaction failed: ${txData.errorMsg || 'Unknown reason'}`); return { status: 'failure', details: txData }; } return txData; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to track transaction status:', (error as Error).message); throw error; } } ``` ## 9. Complete Implementation Here's a complete implementation example: ```typescript import { Web3 } from 'web3'; import * as axios from 'axios'; import * as dotenv from 'dotenv'; import * as CryptoJS from 'crypto-js'; // Load environment variables dotenv.config(); // Connect to Base network const web3 = new Web3(process.env.EVM_RPC_URL || 'https://mainnet.base.org'); // Your wallet information - REPLACE WITH YOUR OWN VALUES const WALLET_ADDRESS: string = process.env.EVM_WALLET_ADDRESS || ''; const PRIVATE_KEY: string = process.env.EVM_PRIVATE_KEY || ''; // Token addresses for swap on Base Chain const ETH_ADDRESS: string = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'; // Native ETH // Chain ID for Base Chain const chainId: string = '8453'; // API URL const baseUrl: string = 'https://web3.okx.com/api/v5/'; // Define interfaces interface TokenInfo { tokenSymbol: string; decimal: string; tokenUnitPrice: string; } // Interface for gas limit API response interface GasLimitApiResponse { code: string; msg?: string; data: Array<{ gasLimit: string; }>; } // Interface for simulation API response interface SimulationApiResponse { code: string; msg?: string; data: Array<{ intention: string; gasUsed?: string; failReason?: string; assetChange?: Array<{ assetType: string; name: string; symbol: string; decimals: number; address: string; imageUrl: string; rawValue: string; }>; risks?: Array; }>; } // Interface for broadcast API response interface BroadcastApiResponse { code: string; msg?: string; data: Array<{ orderId: string; }>; } // Define error info interface interface TxErrorInfo { error: string; message: string; action: string; } /** * Generate API authentication headers */ function getHeaders(timestamp: string, method: string, requestPath: string, queryString = "", body = "") { const apiKey = process.env.OKX_API_KEY; const secretKey = process.env.OKX_SECRET_KEY; const apiPassphrase = process.env.OKX_API_PASSPHRASE; const projectId = process.env.OKX_PROJECT_ID; if (!apiKey || !secretKey || !apiPassphrase || !projectId) { throw new Error("Missing required environment variables for API authentication"); } const stringToSign = timestamp + method + requestPath + (queryString || body); return { "Content-Type": "application/json", "OK-ACCESS-KEY": apiKey, "OK-ACCESS-SIGN": CryptoJS.enc.Base64.stringify( CryptoJS.HmacSHA256(stringToSign, secretKey) ), "OK-ACCESS-TIMESTAMP": timestamp, "OK-ACCESS-PASSPHRASE": apiPassphrase, "OK-ACCESS-PROJECT": projectId, }; } /** * Get transaction gas limit from Onchain gateway API * @param fromAddress - Sender address * @param toAddress - Target contract address * @param txAmount - Transaction amount (0 for approvals) * @param inputData - Transaction calldata * @returns Estimated gas limit */ async function getGasLimit( fromAddress: string, toAddress: string, txAmount: string = '0', inputData: string = '' ): Promise { try { console.log('Getting gas limit from Onchain Gateway API...'); const path = 'dex/pre-transaction/gas-limit'; const url = `${baseUrl}${path}`; const body = { chainIndex: chainId, fromAddress: fromAddress, toAddress: toAddress, txAmount: txAmount, extJson: { inputData: inputData } }; // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); console.log('Gas Limit API Response:'); console.log(JSON.stringify(response.data, null, 2)); if (response.data.code === '0') { const gasLimit = response.data.data[0].gasLimit; console.log(`Gas Limit obtained: ${gasLimit}`); return gasLimit; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get gas limit:', (error as Error).message); throw error; } } /** * Get swap data from OKX API */ async function getSwapData( fromTokenAddress: string, toTokenAddress: string, amount: string, slippage = '0.5' ) { try { console.log('Getting swap data from OKX API...'); const path = 'dex/aggregator/swap'; const url = `${baseUrl}${path}`; const params = { chainIndex: chainId, fromTokenAddress: fromTokenAddress, toTokenAddress: toTokenAddress, amount: amount, slippage: slippage, userWalletAddress: WALLET_ADDRESS }; console.log('Swap API Request Parameters:'); console.log(JSON.stringify(params, null, 2)); // Prepare authentication with query string const queryString = "?" + new URLSearchParams(params).toString(); const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(`${url}${queryString}`, { headers }); console.log('Swap API Response:'); console.log(JSON.stringify(response.data, null, 2)); const responseData = response.data as any; if (responseData.code === '0') { return responseData.data[0]; } else { throw new Error(`Swap API Error: ${responseData.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get swap data:', (error as Error).message); throw error; } } /** * Simulate transaction using Onchain Gateway API */ async function simulateTransaction(swapData: any) { try { console.log('Simulating transaction with Onchain Gateway API...'); const path = 'dex/pre-transaction/simulate'; const url = `${baseUrl}${path}`; const body = { chainIndex: chainId, fromAddress: swapData.tx.from, toAddress: swapData.tx.to, txAmount: swapData.tx.value || '0', extJson: { inputData: swapData.tx.data } }; // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); console.log('Simulation API Response:'); console.log(JSON.stringify(response.data, null, 2)); if (response.data.code === '0') { const simulationResult = response.data.data[0]; // Check if simulation was successful (no failReason or empty failReason) if (!simulationResult.failReason || simulationResult.failReason === '') { console.log(`Transaction simulation successful. Gas used: ${simulationResult.gasUsed}`); return simulationResult; } else { throw new Error(`Simulation failed: ${simulationResult.failReason}`); } } else { throw new Error(`Simulation API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Transaction simulation failed:', (error as Error).message); throw error; } } /** * Broadcast transaction using Onchain Gateway API with RPC fallback */ async function broadcastTransaction(signedTx: any, chainId: string, walletAddress: string): Promise { try { console.log('Broadcasting transaction via Onchain Gateway API...'); const path = 'dex/pre-transaction/broadcast-transaction'; const url = `${baseUrl}${path}`; // Convert rawTransaction to hex string const rawTxHex = typeof signedTx.rawTransaction === 'string' ? signedTx.rawTransaction : web3.utils.bytesToHex(signedTx.rawTransaction); const body = { signedTx: rawTxHex, chainIndex: chainId, address: walletAddress // See [MEV Section](#10-mev-protection) for MEV protection settings }; console.log('Broadcast API Request Body:'); console.log(JSON.stringify(body, null, 2)); // Prepare authentication with body included in signature const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); console.log('Broadcast API Response:'); console.log(JSON.stringify(response.data, null, 2)); if (response.data.code === '0') { const orderId = response.data.data[0].orderId; console.log(`Transaction broadcast successful. Order ID: ${orderId}`); return orderId; } else { throw new Error(`Broadcast API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('API broadcast failed, trying RPC fallback:', (error as Error).message); // Fallback to RPC broadcast try { console.log('Broadcasting via RPC fallback...'); const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction); console.log(`RPC broadcast successful. Transaction hash: ${receipt.transactionHash}`); return receipt.transactionHash.toString(); } catch (rpcError) { console.error('RPC broadcast also failed:', (rpcError as Error).message); throw new Error(`Both API and RPC broadcast failed. API Error: ${(error as Error).message}, RPC Error: ${(rpcError as Error).message}`); } } } /** * Execute swap with full transaction flow */ async function executeSwap( fromTokenAddress: string, toTokenAddress: string, amount: string, slippage: string = '0.05' ): Promise { try { console.log('Starting swap execution...'); // Step 1: Get swap data const swapData = await getSwapData(fromTokenAddress, toTokenAddress, amount, slippage); console.log('Swap data obtained'); // Step 2: Simulate transaction const simulationResult = await simulateTransaction(swapData); console.log('Transaction simulation completed'); console.log('Simulation result', simulationResult.intention); // Step 3: Get gas limit const gasLimit = await getGasLimit( swapData.tx.from, swapData.tx.to, swapData.tx.value || '0', swapData.tx.data ); // Step 4: Get current gas price const gasPrice = await web3.eth.getGasPrice(); console.log(`Current gas price: ${web3.utils.fromWei(gasPrice, 'gwei')} gwei`); // Step 5: Get nonce const nonce = await web3.eth.getTransactionCount(WALLET_ADDRESS, 'pending'); console.log(`Nonce: ${nonce}`); // Step 6: Build transaction const transaction = { from: swapData.tx.from, to: swapData.tx.to, data: swapData.tx.data, value: swapData.tx.value || '0x0', gas: gasLimit, gasPrice: gasPrice.toString(), nonce: Number(nonce), chainId: parseInt(chainId) }; console.log('Transaction object:'); console.log(JSON.stringify(transaction, null, 2)); // Step 7: Sign transaction console.log('Signing transaction...'); const signedTx = await web3.eth.accounts.signTransaction(transaction, PRIVATE_KEY); console.log('Transaction signed'); // Step 8: Broadcast transaction const txHash = await broadcastTransaction(signedTx, chainId, WALLET_ADDRESS); console.log(`Transaction broadcast successful. Hash: ${txHash}`); // Step 9: Track transaction console.log('Tracking transaction status...'); const trackingResult = await trackTransaction(txHash); console.log('Transaction tracking completed'); console.log('Tracking result', trackingResult); return txHash; } catch (error) { console.error('Swap execution failed:', (error as Error).message); throw error; } } /** * Execute swap with simulation and detailed logging */ async function executeSwapWithSimulation( fromTokenAddress: string, toTokenAddress: string, amount: string, slippage: string = '0.05' ): Promise { try { console.log('Starting swap execution with simulation...'); const txHash = await executeSwap(fromTokenAddress, toTokenAddress, amount, slippage); console.log('Swap execution completed successfully!'); console.log(`Transaction Hash: ${txHash}`); return { success: true, txHash }; } catch (error) { console.error('Swap execution failed:', (error as Error).message); return { success: false, error: (error as Error).message }; } } /** * Tracking transaction confirmation status using the Onchain gateway API * @param orderId - Order ID from broadcast response * @param intervalMs - Polling interval in milliseconds * @param timeoutMs - Maximum time to wait * @returns Final transaction confirmation status */ async function trackTransaction( orderId: string, intervalMs: number = 5000, timeoutMs: number = 300000 ): Promise { console.log(`Tracking transaction with Order ID: ${orderId}`); const startTime = Date.now(); let lastStatus = ''; while (Date.now() - startTime < timeoutMs) { try { const path = 'dex/post-transaction/orders'; const url = `https://web3.okx.com/api/v5/${path}`; const params = { orderId: orderId, chainIndex: chainId, address: WALLET_ADDRESS, limit: '1' }; const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); const responseData = response.data as any; if (responseData.code === '0' && responseData.data && responseData.data.length > 0) { if (responseData.data[0].orders && responseData.data[0].orders.length > 0) { const txData = responseData.data[0].orders[0]; const status = txData.txStatus; if (status !== lastStatus) { lastStatus = status; if (status === '1') { console.log(`Transaction pending: ${txData.txHash || 'Hash not available yet'}`); } else if (status === '2') { console.log(`Transaction successful: https://web3.okx.com/explorer/base/tx/${txData.txHash}`); return txData; } else if (status === '3') { const failReason = txData.failReason || 'Unknown reason'; const errorMessage = `Transaction failed: ${failReason}`; console.error(errorMessage); const errorInfo = handleTransactionError(txData); console.log(`Error type: ${errorInfo.error}`); console.log(`Suggested action: ${errorInfo.action}`); throw new Error(errorMessage); } } } else { console.log(`No orders found for Order ID: ${orderId}`); } } } catch (error) { console.warn('Error checking transaction status:', (error as Error).message); } await new Promise(resolve => setTimeout(resolve, intervalMs)); } throw new Error('Transaction tracking timed out'); } /** * Comprehensive error handling with failReason * @param txData - Transaction data from post-transaction/orders * @returns Structured error information */ function handleTransactionError(txData: any): TxErrorInfo { const failReason = txData.failReason || 'Unknown reason'; console.error(`Transaction failed with reason: ${failReason}`); return { error: 'TRANSACTION_FAILED', message: failReason, action: 'Try again or contact support' }; } // ======== Main Execution ======== async function simulateOnly( fromTokenAddress: string, toTokenAddress: string, amount: string, slippage: string = '0.5' ): Promise { try { console.log('Starting simulation-only mode...'); console.log(`Simulation Details:`); console.log(` From Token: ${fromTokenAddress}`); console.log(` To Token: ${toTokenAddress}`); console.log(` Amount: ${amount}`); console.log(` Slippage: ${slippage}%`); // Step 1: Get swap data const swapData = await getSwapData(fromTokenAddress, toTokenAddress, amount, slippage); console.log('Swap data obtained'); // Step 2: Simulate transaction const simulationResult = await simulateTransaction(swapData); console.log('Transaction simulation completed'); // Step 3: Get gas limit const gasLimit = await getGasLimit( swapData.tx.from, swapData.tx.to, swapData.tx.value || '0', swapData.tx.data ); return { success: true, swapData, simulationResult, gasLimit, estimatedGasUsed: simulationResult.gasUsed, }; } catch (error) { console.error('Simulation failed:', (error as Error).message); return { success: false, error: (error as Error).message }; } } async function main() { try { console.log('EVM Swap Tools with Onchain Gateway API'); console.log('====================================='); // Validate environment variables if (!WALLET_ADDRESS || !PRIVATE_KEY) { throw new Error('Missing wallet address or private key in environment variables'); } console.log(`Wallet Address: ${WALLET_ADDRESS}`); console.log(`Chain ID: ${chainId}`); console.log(`RPC URL: ${process.env.EVM_RPC_URL || 'https://mainnet.base.org'}`); // Parse command line arguments const args = process.argv.slice(2); const mode = args[0] || 'simulate'; // Default to simulate mode // Example parameters const fromToken = ETH_ADDRESS; const toToken = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'; // USDC on Base const amount = '100000000000000'; // 0.0001 ETH in wei const slippage = '0.05'; // 0.5% console.log('\nConfiguration:'); console.log(` From: ${fromToken} (ETH)`); console.log(` To: ${toToken} (USDC)`); console.log(` Amount: ${web3.utils.fromWei(amount, 'ether')} ETH`); console.log(` Slippage: ${slippage}%`); console.log(` Mode: ${mode}`); let result; switch (mode.toLowerCase()) { case 'simulate': case 'sim': result = await simulateOnly(fromToken, toToken, amount, slippage); break; case 'execute': case 'exec': result = await executeSwapWithSimulation(fromToken, toToken, amount, slippage); break; default: console.log('\nAvailable modes:'); console.log(' simulate/sim - Only simulate the transaction'); console.log(' execute/exec - Execute the full swap'); console.log('\nExample: npm run evm-swap simulate'); return; } if (result.success) { console.log('\nOperation completed successfully!'); if (mode === 'simulate' || mode === 'sim') { console.log(`Gas Limit: ${result.gasLimit}`); } else { console.log(`Transaction Hash: ${result.txHash}`); } } else { console.log('\nOperation failed!'); console.log(`Error: ${result.error}`); } } catch (error) { console.error('Main execution failed:', (error as Error).message); process.exit(1); } } // Run the script if (require.main === module) { main(); } export { executeSwap, executeSwapWithSimulation, simulateOnly, getSwapData, simulateTransaction, getGasLimit, broadcastTransaction, trackTransaction }; ``` You can run this script using `evm-swap.ts sim` or `evm-swap.ts exec`. `sim` simulates a transaction using swap data using the transaction simulation API and retruns `gasLimit` info `exec` executes a transaction using the broadcast API ## 10. MEV Protection ### MEV Protection with Broadcast Transaction API The OKX Broadcast Transaction API provides built-in MEV protection capabilities to help safeguard your transactions from front-running and sandwich attacks. The Broadcast API is available to our whitelisted customers only. Please reach out to dexapi@okx.com to request access. **Disclaimer:** Your end-user's transaction can only be covered by the MEV protection feature if you actually utilise OKX Build's API services for that particular transaction. MEV protection is currently an experimental feature provided by third-parties and OKX Build does not guarantee the effectiveness and quality of such MEV protection. #### Adding MEV Protection To enable MEV protection on EVM chains, add the `extraData` field to your broadcast transaction request with `enableMevProtection: true`: ```tsx /** * Broadcast transaction with MEV protection enabled for EVM chains */ async function broadcastTransactionWithMEV( signedTx: string, chainId: string = "8453", // Base chain walletAddress: string, enableMevProtection: boolean = true ): Promise { try { console.log('Broadcasting transaction with MEV protection...'); const path = 'dex/pre-transaction/broadcast-transaction'; const url = `https://web3.okx.com/api/v5/${path}`; const body = { signedTx: signedTx, chainIndex: chainId, address: walletAddress, extraData: JSON.stringify({ enableMevProtection: enableMevProtection }) }; const bodyString = JSON.stringify(body); const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const headers = getHeaders(timestamp, 'POST', requestPath, "", bodyString); const response = await axios.post(url, body, { headers }); if (response.data.code === '0') { const orderId = response.data.data[0].orderId; console.log(`Transaction broadcast with MEV protection. Order ID: ${orderId}`); return orderId; } else { throw new Error(`Broadcast API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('MEV-protected broadcast failed:', error); throw error; } } ``` #### Usage Examples **Basic swap without MEV protection:** ```tsx // Standard broadcast (no MEV protection) for Base chain const orderId = await broadcastTransaction(signedTx, "8453", walletAddress); ``` **Swap with MEV protection enabled:** ```tsx // With MEV protection on Base chain const orderId = await broadcastTransactionWithMEVOptions(signedTx, "8453", walletAddress, true); ``` #### Integration with Complete Swap Flow Here's how to integrate MEV protection into your complete EVM swap execution: ```tsx /** * Execute EVM swap with MEV protection */ async function executeSwapWithMEVProtection( fromTokenAddress: string, toTokenAddress: string, amount: string, slippage: string = '0.005', enableMevProtection: boolean = true, chainId: string = "8453" // Base chain ): Promise { try { // Step 1: Check allowance and approve if necessary (skip for native token) if (fromTokenAddress !== ETH_ADDRESS) { await approveToken(fromTokenAddress, amount); } // Step 2: Get swap transaction data const swapData = await getSwapTransaction(fromTokenAddress, toTokenAddress, amount, WALLET_ADDRESS, slippage); const txData = swapData.tx; console.log("Swap TX data received"); // Step 3: Get current gas price and nonce const gasPrice = await web3.eth.getGasPrice(); const adjustedGasPrice = BigInt(gasPrice) * BigInt(15) / BigInt(10); // 1.5x for faster confirmation const nonce = await web3.eth.getTransactionCount(WALLET_ADDRESS, 'latest'); // Step 4: Create and sign transaction object const txObject = { from: WALLET_ADDRESS, to: txData.to, data: txData.data, value: txData.value || '0', gas: '300000', // Default gas limit gasPrice: adjustedGasPrice.toString(), nonce: nonce }; const signedTx = await web3.eth.accounts.signTransaction(txObject, PRIVATE_KEY); console.log("Transaction signed"); // Step 5: Broadcast with MEV protection const orderId = await broadcastTransactionWithMEVOptions( signedTx.rawTransaction, chainId, WALLET_ADDRESS, enableMevProtection ); // Step 6: Track transaction const result = await trackTransaction(orderId); return result.txHash; } catch (error) { console.error("MEV-protected swap failed:", error); throw error; } } ``` The MEV protection feature integrates seamlessly with your existing EVM and Solana swap implementation and provides an additional layer of security against MEV attacks across Solana, Base, Ethereum and BSC. ## Method 2: SDK approach Using the OKX DEX SDK provides a much simpler developer experience while retaining all the functionality of the API-first approach. The SDK handles many implementation details for you, including retry logic, error handling, and transaction management. ## 1. Install the SDK ```typescript npm install @okx-dex/okx-dex-sdk # or yarn add @okx-dex/okx-dex-sdk # or pnpm add @okx-dex/okx-dex-sdk ``` ## 2. Setup Your Environment Create a .env file with your API credentials and wallet information: ```typescript # OKX API Credentials OKX_API_KEY=your_api_key OKX_SECRET_KEY=your_secret_key OKX_API_PASSPHRASE=your_passphrase OKX_PROJECT_ID=your_project_id # EVM Configuration EVM_RPC_URL=your_evm_rpc_url EVM_WALLET_ADDRESS=your_evm_wallet_address EVM_PRIVATE_KEY=your_evm_private_key ``` ## 3. Initialize the Client Create a file for your DEX client (e.g., DexClient.ts): ```typescript // DexClient.ts import { OKXDexClient } from '@okx-dex/okx-dex-sdk'; import { createEVMWallet } from '@okx-dex/okx-dex-sdk/core/evm-wallet'; import { createWallet } from '@okx-dex/okx-dex-sdk/core/wallet'; import { Connection } from '@solana/web3.js'; import { ethers } from 'ethers'; import dotenv from 'dotenv'; dotenv.config(); // EVM setup (Ethereum, Base, Arbitrum, etc.) const evmProvider = new ethers.JsonRpcProvider(process.env.EVM_RPC_URL!); const evmWallet = createEVMWallet(process.env.EVM_PRIVATE_KEY!, evmProvider); // Initialize the client const client = new OKXDexClient({ // API credentials (get from OKX Developer Portal) apiKey: process.env.OKX_API_KEY!, secretKey: process.env.OKX_SECRET_KEY!, apiPassphrase: process.env.OKX_API_PASSPHRASE!, projectId: process.env.OKX_PROJECT_ID!, // EVM configuration (works for all EVM chains) evm: { wallet: evmWallet }, }) ``` ## 4. Token Approval With the SDK Create an approval utility function: ```typescript // approval.ts import { client } from './DexClient'; // Helper function to convert human-readable amounts to base units export function toBaseUnits(amount: string, decimals: number): string { // Remove any decimal point and count the decimal places const [integerPart, decimalPart = ''] = amount.split('.'); const currentDecimals = decimalPart.length; // Combine integer and decimal parts, removing the decimal point let result = integerPart + decimalPart; // Add zeros if you need more decimal places if (currentDecimals < decimals) { result = result + '0'.repeat(decimals - currentDecimals); } // Remove digits if you have too many decimal places else if (currentDecimals > decimals) { result = result.slice(0, result.length - (currentDecimals - decimals)); } // Remove leading zeros result = result.replace(/^0+/, '') || '0'; return result; } /** * Example: Approve a token for swapping */ async function executeApproval(tokenAddress: string, amount: string) { try { // Get token information using quote console.log("Getting token information..."); const tokenInfo = await client.dex.getQuote({ chainId: '8453', // Base Chain fromTokenAddress: tokenAddress, toTokenAddress: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // Native token amount: '1000000', // Use a reasonable amount for quote slippage: '0.005' }); const tokenDecimals = parseInt(tokenInfo.data[0].fromToken.decimal); const rawAmount = toBaseUnits(amount, tokenDecimals); console.log(`\nApproval Details:`); console.log(`--------------------`); console.log(`Token: ${tokenInfo.data[0].fromToken.tokenSymbol}`); console.log(`Amount: ${amount} ${tokenInfo.data[0].fromToken.tokenSymbol}`); console.log(`Amount in base units: ${rawAmount}`); // Execute the approval console.log("\nExecuting approval..."); const result = await client.dex.executeApproval({ chainId: '8453', // Base Chain tokenContractAddress: tokenAddress, approveAmount: rawAmount }); if ('alreadyApproved' in result) { console.log("\nToken already approved for the requested amount!"); return { success: true, alreadyApproved: true }; } else { console.log("\nApproval completed successfully!"); console.log("Transaction Hash:", result.transactionHash); console.log("Explorer URL:", result.explorerUrl); return result; } } catch (error) { if (error instanceof Error) { console.error('Error executing approval:', error.message); } throw error; } } // Run if this file is executed directly if (require.main === module) { // Example usage: ts-node approval.ts 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 1000 const args = process.argv.slice(2); if (args.length !== 2) { console.log("Usage: ts-node approval.ts "); console.log("\nExamples:"); console.log(" # Approve 1000 USDC"); console.log(` ts-node approval.ts 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 1000`); process.exit(1); } const [tokenAddress, amount] = args; executeApproval(tokenAddress, amount) .then(() => process.exit(0)) .catch((error) => { console.error('Error:', error); process.exit(1); }); } export { executeApproval }; ``` ## 5. Execute a Swap With the SDK Create a swap execution file: ```typescript // swap.ts import { client } from './DexClient'; /** * Example: Execute a swap from ETH to USDC on Base chain */ async function executeSwap() { try { if (!process.env.EVM_PRIVATE_KEY) { throw new Error('Missing EVM_PRIVATE_KEY in .env file'); } // You can change this to any EVM chain // For example, for Base, use chainId: '8453' // For example, for baseSepolia, use chainId: '84532' // You can also use SUI, use chainId: '784' // When using another Chain, you need to change the fromTokenAddress and toTokenAddress to the correct addresses for that chain const swapResult = await client.dex.executeSwap({ chainId: '8453', // Base chain ID fromTokenAddress: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // Native ETH toTokenAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC on Base amount: String(10 * 10 ** 14), // .0001 ETH slippage: '0.005', // 0.5% slippage userWalletAddress: process.env.EVM_WALLET_ADDRESS! }); console.log('Swap executed successfully:'); console.log(JSON.stringify(swapResult, null, 2)); return swapResult; } catch (error) { if (error instanceof Error) { console.error('Error executing swap:', error.message); // API errors include details in the message if (error.message.includes('API Error:')) { const match = error.message.match(/API Error: (.*)/); if (match) console.error('API Error Details:', match[1]); } } throw error; } } // Run if this file is executed directly if (require.main === module) { executeSwap() .then(() => process.exit(0)) .catch((error) => { console.error('Error:', error); process.exit(1); }); } export { executeSwap }; ``` ## 6. Additional SDK Functionality The SDK provides additional methods that simplify development: Get a quote for a token pair ```typescript const quote = await client.dex.getQuote({ chainId: '8453', // Base Chain fromTokenAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC toTokenAddress: '0x4200000000000000000000000000000000000006', // WETH amount: '1000000', // 1 USDC (in smallest units) slippage: '0.005' // 0.5% }); ``` - [Build Swap Applications on Sui](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-use-swap-sui-quick-start.md) # Build Swap Applications on Sui There are two approaches to building swap applications with OKX DEX on Sui: - The API-first approach directly interacting with OKX DEX API endpoints - The SDK approach using the @okx-dex/okx-dex-sdk package for a simplified developer experience This guide covers both methods to help you choose the approach that best fits your needs. ## Method 1: API-first Approach In this guide, we will provide a use case for Sui token exchange through the OKX DEX. ## 1. Set Up Your Environment Import the necessary Node.js libraries and set up your environment variables: ```javascript // Required libraries import { SuiWallet } from "@okxweb3/coin-sui"; import { getFullnodeUrl, SuiClient } from '@mysten/sui/client'; import { Transaction } from '@mysten/sui/transactions'; import cryptoJS from "crypto-js"; // Install dependencies // npm i @okxweb3/coin-sui // npm i @mysten/sui // npm i crypto-js // Set up environment variables const apiKey = 'your_api_key'; const secretKey = 'your_secret_key'; const apiPassphrase = 'your_passphrase'; const projectId = 'your_project_id'; const userAddress = 'your_sui_wallet_address'; const userPrivateKey = 'your_sui_wallet_private_key'; // Constants const SUI_CHAIN_ID = "784"; const DEFAULT_GAS_BUDGET = 50000000; const MAX_RETRIES = 3; // Initialize Sui client const wallet = new SuiWallet(); const client = new SuiClient({ url: getFullnodeUrl('mainnet') }); // For Sui, you need to use the hexWithoutFlag format of your private key // You can convert your key using sui keytool: // sui keytool convert ``` ## 2. Obtain Token Information and Swap Quote First, create a utility function to handle API authentication headers: ```javascript function getHeaders(timestamp, method, requestPath, queryString = "") { if (!apiKey || !secretKey || !apiPassphrase || !projectId) { throw new Error("Missing required environment variables"); } const stringToSign = timestamp + method + requestPath + queryString; return { "Content-Type": "application/json", "OK-ACCESS-KEY": apiKey, "OK-ACCESS-SIGN": cryptoJS.enc.Base64.stringify( cryptoJS.HmacSHA256(stringToSign, secretKey) ), "OK-ACCESS-TIMESTAMP": timestamp, "OK-ACCESS-PASSPHRASE": apiPassphrase, "OK-ACCESS-PROJECT": projectId, }; } ``` Then, create a function to get token information: ```javascript async function getTokenInfo(fromTokenAddress, toTokenAddress) { const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/aggregator/quote"; const params = { chainId: SUI_CHAIN_ID, fromTokenAddress, toTokenAddress, amount: "1000000", slippage: "0.005",// 0.5% slippage }; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); const response = await fetch( `https://web3.okx.com${requestPath}${queryString}`, { method: "GET", headers } ); if (!response.ok) { throw new Error(`Failed to get quote: ${await response.text()}`); } const data = await response.json(); if (data.code !== "0" || !data.data?.[0]) { throw new Error("Failed to get token information"); } const quoteData = data.data[0]; return { fromToken: { symbol: quoteData.fromToken.tokenSymbol, decimals: parseInt(quoteData.fromToken.decimal), price: quoteData.fromToken.tokenUnitPrice }, toToken: { symbol: quoteData.toToken.tokenSymbol, decimals: parseInt(quoteData.toToken.decimal), price: quoteData.toToken.tokenUnitPrice } }; } ``` Create a function to convert human-readable amounts to base units: ```javascript function convertAmount(amount, decimals) { try { if (!amount || isNaN(parseFloat(amount))) { throw new Error("Invalid amount"); } const value = parseFloat(amount); if (value <= 0) { throw new Error("Amount must be greater than 0"); } return (BigInt(Math.floor(value * Math.pow(10, decimals)))).toString(); } catch (err) { console.error("Amount conversion error:", err); throw new Error("Invalid amount format"); } } ``` ## 3. Get Swap Data 3.1 Define swap parameters ```typescript const swapParams = { chainId: chainId, fromTokenAddress, toTokenAddress, amount, userWalletAddress: userAddress, slippage }; ``` 3.2 Request swap transaction data ```typescript /** * Get swap transaction data from DEX API * @param fromTokenAddress - Source token address * @param toTokenAddress - Destination token address * @param amount - Amount to swap * @param userAddress - User wallet address * @param slippage - Maximum slippage (e.g., "0.5" for 0.5%) * @returns Swap transaction data */ async function getSwapTransaction( fromTokenAddress: string, toTokenAddress: string, amount: string, userAddress: string, slippage: string = '0.5' ): Promise { try { const path = 'dex/aggregator/swap'; const url = `${baseUrl}${path}`; const params = { chainId: chainId, fromTokenAddress, toTokenAddress, amount, userWalletAddress: userAddress, slippage }; // Prepare authentication const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await axios.get(url, { params, headers }); if (response.data.code === '0') { return response.data.data[0]; } else { throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`); } } catch (error) { console.error('Failed to get swap transaction data:', (error as Error).message); throw error; } } ``` ## 4. Simulate Transaction Before executing the actual swap, it's crucial to simulate the transaction to ensure it will succeed and to identify any potential issues: The Simulate API is available to our whitelisted customers only. Please reach out to dexapi@okx.com to request access. ```javascript async function simulateTransaction(txData) { try { if (!txData) { throw new Error('Invalid transaction data format'); } const params = { chainIndex: SUI_CHAIN_ID, txData: txData, includeDebug: true }; const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/pre-transaction/simulate"; const requestBody = JSON.stringify(params); const headers = getHeaders(timestamp, "POST", requestPath, "", requestBody); console.log('Simulating transaction...'); const response = await fetch( `https://web3.okx.com${requestPath}`, { method: 'POST', headers, body: requestBody } ); const data = await response.json(); if (data.code !== "0") { throw new Error(`Simulation failed: ${data.msg || "Unknown simulation error"}`); } const simulationResult = data.data[0]; // Check simulation success if (simulationResult.success === false) { console.error('Transaction simulation failed:', simulationResult.error); throw new Error(`Transaction would fail: ${simulationResult.error}`); } console.log('Transaction simulation successful'); console.log(`Estimated gas used: ${simulationResult.gasUsed || 'N/A'}`); if (simulationResult.logs) { console.log('Simulation logs:', simulationResult.logs); } return simulationResult; } catch (error) { console.error("Error simulating transaction:", error); throw error; } } ``` ## 5. Execute the Transaction First, prepare and sign the transaction: ```javascript async function executeSwap(txData, privateKey) { // Create transaction block const txBlock = Transaction.from(txData); txBlock.setSender(normalizedWalletAddress); // Set gas parameters const referenceGasPrice = await client.getReferenceGasPrice(); txBlock.setGasPrice(BigInt(referenceGasPrice)); txBlock.setGasBudget(BigInt(DEFAULT_GAS_BUDGET)); // Build and sign transaction const builtTx = await txBlock.build({ client }); const txBytes = Buffer.from(builtTx).toString('base64'); const signedTx = await wallet.signTransaction({ privateKey, data: { type: 'raw', data: txBytes } }); if (!signedTx?.signature) { throw new Error("Failed to sign transaction"); } return { builtTx, signature: signedTx.signature }; } ``` Then, send the transaction using RPC method calls Using RPC: ```javascript async function sendTransaction(builtTx, signature) { // Execute transaction const result = await client.executeTransactionBlock({ transactionBlock: builtTx, signature: [signature], options: { showEffects: true, showEvents: true, } }); // Wait for confirmation const confirmation = await client.waitForTransaction({ digest: result.digest, options: { showEffects: true, showEvents: true, } }); console.log("\nSwap completed successfully!"); console.log("Transaction ID:", result.digest); console.log("Explorer URL:", `https://suiscan.xyz/mainnet/tx/${result.digest}`); return result.digest; } ``` ## 6. Track Transaction Track transaction using SWAP API: SWAP API transaction tracking provides comprehensive swap execution details using the `/dex/aggregator/history` endpoint. It offers token-specific information (symbols, amounts), fees paid, and detailed blockchain data. Use this when you need complete swap insight with token-level details. ```javascript async function trackTransactionWithSwapAPI(txHash) { try { const path = 'dex/aggregator/history'; const url = `${baseUrl}${path}`; const params = { chainId: SUI_CHAIN_ID, txHash: txHash, isFromMyProject: 'false' }; const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); console.log('Fetching transaction status...'); const response = await fetch(`${url}${queryString}`, { headers }); const data = await response.json(); if (!data) { throw new Error('No response data received from API'); } if (data.code !== '0') { throw new Error(`API Error: ${data.msg || 'Unknown error'}`); } if (!data.data || !Array.isArray(data.data) || data.data.length === 0) { console.log('Transaction not found in history yet, might be too recent'); return { status: 'pending', details: null }; } const txData = data.data[0]; if (!txData) { console.log('Transaction data not available yet'); return { status: 'pending', details: null }; } const status = txData.status; console.log(`Transaction status: ${status}`); if (status === 'pending') { console.log(`Transaction is still pending: ${txHash}`); return { status: 'pending', details: txData }; } else if (status === 'success') { console.log(`Transaction successful!`); console.log(`From: ${txData.fromTokenDetails.symbol} - Amount: ${txData.fromTokenDetails.amount}`); console.log(`To: ${txData.toTokenDetails.symbol} - Amount: ${txData.toTokenDetails.amount}`); console.log(`Transaction Fee: ${txData.txFee}`); console.log(`Explorer URL: https://suiscan.xyz/mainnet/tx/${txHash}`); return { status: 'success', details: txData }; } else if (status === 'fail') { const errorMsg = txData.errorMsg || 'Unknown reason'; console.error(`Transaction failed: ${errorMsg}`); return { status: 'failure', details: txData, error: errorMsg }; } return { status: 'unknown', details: txData }; } catch (error) { console.error('Failed to track transaction status:', error.message); return { status: 'pending', details: null, error: error.message }; } } ``` ## 7. Complete Implementation Here's a complete implementation putting it all together: ```javascript // swap.ts import { SuiWallet } from "@okxweb3/coin-sui"; import { getFullnodeUrl, SuiClient } from '@mysten/sui/client'; import { Transaction } from '@mysten/sui/transactions'; import cryptoJS from "crypto-js"; import dotenv from 'dotenv'; dotenv.config(); // Environment variables const apiKey = process.env.OKX_API_KEY; const secretKey = process.env.OKX_SECRET_KEY; const apiPassphrase = process.env.OKX_API_PASSPHRASE; const projectId = process.env.OKX_PROJECT_ID; const userAddress = process.env.WALLET_ADDRESS; const userPrivateKey = process.env.PRIVATE_KEY; // Constants const SUI_CHAIN_ID = "784"; const DEFAULT_GAS_BUDGET = 50000000; const MAX_RETRIES = 3; // Initialize clients const wallet = new SuiWallet(); const client = new SuiClient({ url: getFullnodeUrl('mainnet') }); // Normalize wallet address const normalizedWalletAddress = userAddress; function getHeaders(timestamp: string, method: string, requestPath: string, queryString: string = "", requestBody: string = "") { if (!apiKey || !secretKey || !apiPassphrase || !projectId) { throw new Error("Missing required environment variables"); } const stringToSign = timestamp + method + requestPath + queryString + requestBody; return { "Content-Type": "application/json", "OK-ACCESS-KEY": apiKey, "OK-ACCESS-SIGN": cryptoJS.enc.Base64.stringify( cryptoJS.HmacSHA256(stringToSign, secretKey) ), "OK-ACCESS-TIMESTAMP": timestamp, "OK-ACCESS-PASSPHRASE": apiPassphrase, "OK-ACCESS-PROJECT": projectId, }; } async function getTokenInfo(fromTokenAddress: string, toTokenAddress: string) { const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/aggregator/quote"; const params = { chainId: SUI_CHAIN_ID, fromTokenAddress, toTokenAddress, amount: "1000000", slippage: "0.005",// 0.5% slippage }; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); const response = await fetch( `https://web3.okx.com${requestPath}${queryString}`, { method: "GET", headers } ); if (!response.ok) { throw new Error(`Failed to get quote: ${await response.text()}`); } const data = await response.json(); if (data.code !== "0" || !data.data?.[0]) { throw new Error("Failed to get token information"); } const quoteData = data.data[0]; return { fromToken: { symbol: quoteData.fromToken.tokenSymbol, decimals: parseInt(quoteData.fromToken.decimal), price: quoteData.fromToken.tokenUnitPrice }, toToken: { symbol: quoteData.toToken.tokenSymbol, decimals: parseInt(quoteData.toToken.decimal), price: quoteData.toToken.tokenUnitPrice } }; } function convertAmount(amount: string | number, decimals: number) { try { if (!amount || isNaN(parseFloat(amount.toString()))) { throw new Error("Invalid amount"); } const value = parseFloat(amount.toString()); if (value <= 0) { throw new Error("Amount must be greater than 0"); } return (BigInt(Math.floor(value * Math.pow(10, decimals)))).toString(); } catch (err) { console.error("Amount conversion error:", err); throw new Error("Invalid amount format"); } } async function trackTransactionWithSwapAPI(txHash: string) { try { const path = 'dex/aggregator/history'; const url = `https://web3.okx.com/api/v5/${path}`; const params = { chainId: SUI_CHAIN_ID, txHash: txHash, isFromMyProject: 'false' }; const timestamp = new Date().toISOString(); const requestPath = `/api/v5/${path}`; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, 'GET', requestPath, queryString); const response = await fetch(`${url}${queryString}`, { headers }); const data = await response.json(); if (data.code !== '0') { throw new Error(`API Error: ${data.msg || 'Unknown error'}`); } return data.data?.[0] || { status: 'pending' }; } catch (error) { console.error('Failed to track transaction:', error); return { status: 'error', error: error instanceof Error ? error.message : 'Unknown error' }; } } async function main() { try { const args = process.argv.slice(2); if (args.length < 3) { console.log("Usage: ts-node swap.ts "); console.log("Example: ts-node swap.ts 1.5 0x2::sui::SUI 0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC"); process.exit(1); } const [amount, fromTokenAddress, toTokenAddress] = args; if (!userPrivateKey || !userAddress) { throw new Error("Private key or user address not found"); } // Get token information console.log("Getting token information..."); const tokenInfo = await getTokenInfo(fromTokenAddress, toTokenAddress); console.log(`From: ${tokenInfo.fromToken.symbol} (${tokenInfo.fromToken.decimals} decimals)`); console.log(`To: ${tokenInfo.toToken.symbol} (${tokenInfo.toToken.decimals} decimals)`); // Convert amount using fetched decimals const rawAmount = convertAmount(amount, tokenInfo.fromToken.decimals); console.log(`Amount in ${tokenInfo.fromToken.symbol} base units:`, rawAmount); // Get swap quote const quoteParams = { chainId: SUI_CHAIN_ID, amount: rawAmount, fromTokenAddress, toTokenAddress, slippage: "0.005",// 0.5% slippage userWalletAddress: normalizedWalletAddress || "", }; // Get swap data const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/aggregator/swap"; const queryString = "?" + new URLSearchParams(quoteParams).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); console.log("Requesting swap quote..."); const response = await fetch( `https://web3.okx.com${requestPath}${queryString}`, { method: "GET", headers } ); const data = await response.json(); if (data.code !== "0") { throw new Error(`API Error: ${data.msg}`); } const swapData = data.data[0]; // Show estimated output and price impact const outputAmount = parseFloat(swapData.routerResult.toTokenAmount) / Math.pow(10, tokenInfo.toToken.decimals); console.log("\nSwap Quote:"); console.log(`Input: ${amount} ${tokenInfo.fromToken.symbol} ($${(parseFloat(amount) * parseFloat(tokenInfo.fromToken.price)).toFixed(2)})`); console.log(`Output: ${outputAmount.toFixed(tokenInfo.toToken.decimals)} ${tokenInfo.toToken.symbol} ($${(outputAmount * parseFloat(tokenInfo.toToken.price)).toFixed(2)})`); if (swapData.priceImpactPercentage) { console.log(`Price Impact: ${swapData.priceImpactPercentage}%`); } console.log("\nExecuting swap transaction..."); let retryCount = 0; while (retryCount < MAX_RETRIES) { try { // Create transaction block const txBlock = Transaction.from(swapData.tx.data); if (!normalizedWalletAddress) { throw new Error("Wallet address is not defined"); } txBlock.setSender(normalizedWalletAddress); // Set gas parameters const referenceGasPrice = await client.getReferenceGasPrice(); txBlock.setGasPrice(BigInt(referenceGasPrice)); txBlock.setGasBudget(BigInt(DEFAULT_GAS_BUDGET)); // Build and sign transaction const builtTx = await txBlock.build({ client }); const txBytes = Buffer.from(builtTx).toString('base64'); const signedTx = await wallet.signTransaction({ privateKey: userPrivateKey, data: { type: 'raw', data: txBytes } }); if (!signedTx?.signature) { throw new Error("Failed to sign transaction"); } // Execute transaction const result = await client.executeTransactionBlock({ transactionBlock: builtTx, signature: [signedTx.signature], options: { showEffects: true, showEvents: true, } }); // Wait for confirmation const confirmation = await client.waitForTransaction({ digest: result.digest, options: { showEffects: true, showEvents: true, } }); console.log("\nSwap completed successfully!"); console.log("Transaction ID:", result.digest); console.log("Explorer URL:", `https://suiscan.xyz/mainnet/tx/${result.digest}`); // Track transaction const txStatus = await trackTransactionWithSwapAPI(result.digest); console.log("Transaction Status:", txStatus); process.exit(0); } catch (error) { console.error(`Attempt ${retryCount + 1} failed:`, error); retryCount++; if (retryCount === MAX_RETRIES) { throw error; } await new Promise(resolve => setTimeout(resolve, 2000 * retryCount)); } } } catch (error) { console.error("Error:", error instanceof Error ? error.message : "Unknown error"); process.exit(1); } } if (require.main === module) { main(); } ``` ## Method 2: SDK Approach Using the OKX DEX SDK provides a much simpler developer experience while retaining all the functionality of the API-first approach. The SDK handles many implementation details for you, including retry logic, error handling, and transaction management. ## 1. Install the SDK ```javascript npm install @okx-dex/okx-dex-sdk # or yarn add @okx-dex/okx-dex-sdk # or pnpm add @okx-dex/okx-dex-sdk ``` ## 2. Setup Your Environment Create a .env file with your API credentials and wallet information: ```javascript # OKX API Credentials OKX_API_KEY=your_api_key OKX_SECRET_KEY=your_secret_key OKX_API_PASSPHRASE=your_passphrase OKX_PROJECT_ID=your_project_id # Sui Configuration SUI_WALLET_ADDRESS=your_sui_wallet_address SUI_PRIVATE_KEY=your_sui_private_key ``` Remember that you need to use the hexWithoutFlag format of your SUI private key, which you can obtain using the SUI CLI: ```javascript sui keytool convert ``` ## 3. Initialize the Client Create a file for your DEX client (e.g., DexClient.ts): ```javascript // DexClient.ts import { OKXDexClient } from '@okx-dex/okx-dex-sdk'; import 'dotenv/config'; // Validate environment variables const requiredEnvVars = [ 'OKX_API_KEY', 'OKX_SECRET_KEY', 'OKX_API_PASSPHRASE', 'OKX_PROJECT_ID', 'SUI_WALLET_ADDRESS', 'SUI_PRIVATE_KEY' ]; for (const envVar of requiredEnvVars) { if (!process.env[envVar]) { throw new Error(`Missing required environment variable: ${envVar}`); } } // Initialize the client export const client = new OKXDexClient({ apiKey: process.env.OKX_API_KEY!, secretKey: process.env.OKX_SECRET_KEY!, apiPassphrase: process.env.OKX_API_PASSPHRASE!, projectId: process.env.OKX_PROJECT_ID!, sui: { privateKey: process.env.SUI_PRIVATE_KEY!, walletAddress: process.env.SUI_WALLET_ADDRESS!, connection: { rpcUrl: 'https://sui-mainnet.blockvision.org' } } }); ``` ## 4. Create a Token Helper (Optional) You can create a token list helper for easy reference: ```javascript // Common tokens on Sui mainnet export const TOKENS = { SUI: "0x2::sui::SUI", USDC: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC" } as const; ``` ## 5. Execute a Swap With the SDK Create a swap execution file: ```javascript // swap.ts import { client } from './DexClient'; import { TOKENS } from './Tokens'; // Optional, if you created the token helper /** * Example: Execute a swap from SUI to USDC */ async function executeSwap() { try { if (!process.env.SUI_PRIVATE_KEY) { throw new Error('Missing SUI_PRIVATE_KEY in .env file'); } // First, get token information using a quote console.log("Getting token information..."); const fromTokenAddress = TOKENS.SUI; // Or use directly: "0x2::sui::SUI" const toTokenAddress = TOKENS.USDC; // Or use directly: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC" const quote = await client.dex.getQuote({ chainId: '784', // Sui chain ID fromTokenAddress, toTokenAddress, amount: '1000000', // Small amount for quote slippage: '0.005' // 0.5% slippage }); const tokenInfo = { fromToken: { symbol: quote.data[0].fromToken.tokenSymbol, decimals: parseInt(quote.data[0].fromToken.decimal), price: quote.data[0].fromToken.tokenUnitPrice }, toToken: { symbol: quote.data[0].toToken.tokenSymbol, decimals: parseInt(quote.data[0].toToken.decimal), price: quote.data[0].toToken.tokenUnitPrice } }; // Convert amount to base units const humanReadableAmount = 1.5; // 1.5 SUI const rawAmount = (humanReadableAmount * Math.pow(10, tokenInfo.fromToken.decimals)).toString(); console.log("\nSwap Details:"); console.log("--------------------"); console.log(`From: ${tokenInfo.fromToken.symbol}`); console.log(`To: ${tokenInfo.toToken.symbol}`); console.log(`Amount: ${humanReadableAmount} ${tokenInfo.fromToken.symbol}`); console.log(`Amount in base units: ${rawAmount}`); console.log(`Approximate USD value: $${(humanReadableAmount * parseFloat(tokenInfo.fromToken.price)).toFixed(2)}`); // Execute the swap console.log("\nExecuting swap..."); const swapResult = await client.dex.executeSwap({ chainId: '784', // Sui chain ID fromTokenAddress, toTokenAddress, amount: rawAmount, slippage: '0.005', // 0.5% slippage userWalletAddress: process.env.SUI_WALLET_ADDRESS! }); console.log('Swap executed successfully:'); console.log("\nTransaction ID:", swapResult.transactionId); console.log("Explorer URL:", swapResult.explorerUrl); if (swapResult.details) { console.log("\nDetails:"); console.log(`Input: ${swapResult.details.fromToken.amount} ${swapResult.details.fromToken.symbol}`); console.log(`Output: ${swapResult.details.toToken.amount} ${swapResult.details.toToken.symbol}`); if (swapResult.details.priceImpact) { console.log(`Price Impact: ${swapResult.details.priceImpact}%`); } } return swapResult; } catch (error) { if (error instanceof Error) { console.error('Error executing swap:', error.message); // API errors include details in the message if (error.message.includes('API Error:')) { const match = error.message.match(/API Error: (.*)/); if (match) console.error('API Error Details:', match[1]); } } throw error; } } // Run if this file is executed directly if (require.main === module) { executeSwap() .then(() => process.exit(0)) .catch((error) => { console.error('Error:', error); process.exit(1); }); } export { executeSwap }; ``` ## 6. Additional SDK functionality The SDK provides additional methods that simplify development: Get a quote for a token pair ```javascript const quote = await client.dex.getQuote({ chainId: '784', // Sui fromTokenAddress: '0x2::sui::SUI', // SUI toTokenAddress: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC', // USDC amount: '100000000', // In base units slippage: '0.005' // 0.5% slippage }); ``` - [Build Swap Applications on Ton](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-use-swap-ton-quick-start.md) # Build Swap Applications on Ton In this guide, we’ll provide an example token swap through OKX DEX, using Ton from the Ton network to purchase JETTON. The process is as follows: 1. Set up your environment 2. Request the /quote endpoint and get the quote data 3. Request the /swap endpoint send the swap transaction ## 1. Set Up Your Environment ```javascript # --------------------- npm package --------------------- npm install @ton/ton @ton/crypto @ton/core buffer @orbs-network/ton-access ``` ```js const cryptoJS = require('crypto-js'); // Import encryption modules for subsequent encryption calculations const { TonClient, WalletContractV4, internal } = require("@ton/ton"); const { toNano, Cell } = require("@ton/core"); const { mnemonicToPrivateKey } = require("@ton/crypto"); const { getHttpEndpoint } = require("@orbs-network/ton-access"); // --------------------- environment variable --------------------- const apiBaseUrl = 'https://web3.okx.com/api/v6/dex/aggregator'; const chainId = '607'; // Native token contract address const fromTokenAddress = 'EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c'; // JETTON token contract address const toTokenAddress = 'EQAQXlWJvGbbFfE8F3oS8s87lIgdovS455IsWFaRdmJetTon'; // your wallet address const user = 'UQDoI2kiSNQZxxxxxxxxxxxx6lM2ZSxKkEw3k1' const fromAmount = '1000000' // user wallet private key const privateKey = 'xxxxx'; // open api Secret key const secretkey = 'xxxxx' // Get the current time const date = new Date(); // --------------------- util function --------------------- function getAggregatorRequestUrl(methodName, queryParams) { return apiBaseUrl + methodName + '?' + (new URLSearchParams(queryParams)).toString(); } // Check https://web3.okx.com/zh-hans/web3/build/docs/waas/rest-authentication for api-key const headersParams = { 'Content-Type': 'application/json', // The api Key obtained from the previous application 'OK-ACCESS-KEY': 'xxxxx', 'OK-ACCESS-SIGN': cryptoJS.enc.Base64.stringify( // The field order of headersParams should be consistent with the order of quoteParams. // example : quote ==> cryptoJS.HmacSHA256(date.toISOString() + 'GET' + '/api/v6/dex/aggregator/quote?amount=1000000&chainId=607&toTokenAddress=EQAQXlWJvGbbFfE8F3oS8s87lIgdovS455IsWFaRdmJetTon&fromTokenAddress=EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c', secretKey) cryptoJS.HmacSHA256(date.toISOString() + 'GET' + '/api/v6/dex/aggregator/xxx/xxx/xxx', secretKey) ), // Convert the current time to the desired format 'OK-ACCESS-TIMESTAMP': date.toISOString(), // The password created when applying for the key 'OK-ACCESS-PASSPHRASE': 'xxxxxxx', }; ``` **Additional receiving addresses aren’t supported.** ## 2. Request the /quote Endpoint and Get the Quote Data ### 2.1 Define Quote Parameters - Next, define the parameters to get basic information of the quote and the router list. ```js const quoteParams = { amount: fromAmount, chainId: chainId, toTokenAddress: toTokenAddress, fromTokenAddress: fromTokenAddress, }; ``` ### 2.2 Define helper functions - Define helper functions to interact with the DEX API. ```js const getQuote = async () => { const apiRequestUrl = getAggregatorRequestUrl('/quote', quoteParams); return fetch(apiRequestUrl, { method: 'get', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` ## 3. Request the /swap Endpoint and Send the Transaction ### 3.1 Define Swap Parameters - Next, define the parameters of the swap, and get the tx information. ```js const swapParams = { chainId: 1, fromTokenAddress: 'fromTokenAddress', toTokenAddress: 'toTokenAddress', amount: '1000000', slippage: '0.03', // 3% slippage userWalletAddress: user }; ``` ### 3.2 Define Helper Functions Define helper functions to interact with the DEX API ```js const getSwapData = async () => { const apiRequestUrl = getAggregatorRequestUrl('/swap', swapParams); return fetch(apiRequestUrl, { method: 'get', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` ### 3.3 Request Swap Data and Send the Transaction ```js let tx = { "data": "te6cckEBBAEAwAABsA+KfqUAALgW1FkYQkBfXhAIAK3+NxydEq8Qc4csyQ7botOnBqxp3L54Fn7Zof9EjDx5ADoI2kiSNQZdnOIVsRSLrVMtiBySHg0Lt6lM2ZSxKkEwyC592wEBAZ8RMwAAAvrwgIALyzu3/eo7h8wFCa+0XsOg6z0IG/43fUuMnumWS8xS91AD0F/w35CTWUxTWRjefoV+400KRA2jX51X4ezIgmUUY/0AX5sDCAIBAQwDABgAAAABAAAAAAAAA+cKUcDO", "from": "UQDoI2kiSNQZdnOIVsRSLrVMtiBySHg0Lt6lM2ZSxKkEw3k1", "gas": "80234000", "gasPrice": "5000", "maxPriorityFeePerGas": "", "minReceiveAmount": "25062412", "to": "UQBXp1W7_UJWvsBrbaO8s-9i8O53s7hNNeZ0XqEEz12i0oDS", "value": "440000000" } // This is the response of the /swap endpoint async function sendTx() { const endpoint = await getHttpEndpoint(); const client = new TonClient({ endpoint }); const mnemonic = ['range', 'xxxxxx']; // Your mnemonic words Decimal conversion const keyPair = await mnemonicToPrivateKey(mnemonic); const wallet = WalletContractV4.create({workchain: 0, publicKey: keyPair.publicKey}); const contract = client.open(wallet) let seqno = await contract.getSeqno(); const body = Cell.fromBase64(tx.data); const value = tx.value / Math.pow(10, 9); // Decimal conversion const to = tx.to; await contract.sendTransfer({ seqno, secretKey: keyPair.secretKey, messages: [internal({ value: toNano(value), to, body: body, })] }); } ``` - [Introduction](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-swap-api-introduction.md) # Introduction OKX DEX is an aggregator of various decentralized exchanges (also known as DEXs, such as Uniswap, Curve, Balancer, etc.) on different blockchains, allowing multi-chain and cross-chain trading. Our goal is to provide users with the best possible prices through intelligent routing. |OKX DEX inquiry and transaction process| |:-| |![image](../images/Swap_API_EN.jpg)| - Comprehensively calculate price, slippage, and transaction costs - Select the best quote for users based on a comprehensive comparison of quotes from various DEXs and PMMs through the smart order splitting algorithm | OKX DEX Swap trading process | |:--------------------------------------------| | ![image](../images/single-swap-english.png) | 1. Get information of the supported networks through /supported/chain. 2. Get information of the supported tokens through /aggregator/all-tokens. 3. Build the request for /quote data based on information of the supported networks and tokens. 4. Following the quote request, obtain the user’s authorization to allow the OKX DEX router to perform asset operations on their wallet. 5. Build the request for /approve-transaction to get the user’s wallet authorization. 6. Build /swap information based on the returned quote router data and obtain the transaction data required for the swap. 7. Broadcast the returned swap transaction information to the blockchain. - [Swap API Reference](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-api-reference.md) # Swap API Reference - [Get Supported Chains](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-get-aggregator-supported-chains.md) {/* api-page */} # Get Supported Chains Retrieve information on chains supported for single-chain exchanges. The request returns supported target chains for cross-chain transactions. ### Request URL GET `https://web3.okx.com/api/v5/dex/aggregator/supported/chain` ## Request Parameters | Parameter | Type | Required | Description | |---------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | No | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). |
## Response Parameters | Parameter | Type | Description | |-----------------------|---------|----------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Unique identifier for the chain. | | chainName | String | Chain name (e.g., `Optimism`). | | dexTokenApproveAddress| String | DEX authorization contract address; if no authorization has been made, this field will be empty. |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/supported/chain?chainIndex=1' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code":"0", "data":[ { "chainIndex":"1", "chainName":"Ethereum", "dexTokenApproveAddress": "0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f" }, ], "msg":"" } ```
- [Get Tokens](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-get-tokens.md) {/* api-page */} # Get Tokens It fetches a list of tokens. This interface returns a list of tokens that belong to major platforms or are deemed significant enough by OKX. However, you can still quote and swap other tokens outside of this list on OKX DEX. ### Request URL GET `https://web3.okx.com/api/v5/dex/aggregator/all-tokens` ## Request Parameters | Parameter | Type | Required | Description | |-----------|--------|----------|--------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). |
## Response Parameters | Parameter | Type | Description | |----------------------|--------|--------------------------| | decimals | String | The precision of tokens (e.g., `18`) | | tokenContractAddress | String | Token contract address (e.g., `0x382bb369d343125bfb2117af9c149795c6c65c50`) | | tokenLogoUrl | String | Token logo (e.g., `https://static.okx.com/cdn/wallet/logo/USDT-991ffed9-e495-4d1b-80c2-a4c5f96ce22d.png`) | | tokenName | String | Token full name (e.g., `Tether`) | | tokenSymbol | String | Token symbol (e.g., `USDT`) |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/all-tokens?chainIndex=1' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "decimals": "18", "tokenContractAddress": "0x382bb369d343125bfb2117af9c149795c6c65c50", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/USDT-991ffed9-e495-4d1b-80c2-a4c5f96ce22d.png", "tokenName": "Tether", "tokenSymbol": "USDT" }, { "decimals": "18", "tokenContractAddress": "0xc946daf81b08146b1c7a8da2a851ddf2b3eaaf85", "tokenLogoUrl": "https://static.okx.com/cdn/explorer/okexchain/exchain_usdc.png", "tokenName": "USD Coin", "tokenSymbol": "USDC" }, { "decimals": "18", "tokenContractAddress": "0xdf54b6c6195ea4d948d03bfd818d365cf175cfc2", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/okb.png", "tokenName": "OKB", "tokenSymbol": "OKB" }, { "decimals": "18", "tokenContractAddress": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/okt.png", "tokenName": "OKTC", "tokenSymbol": "OKT" }, { "decimals": "18", "tokenContractAddress": "0x218c3c3d49d0e7b37aff0d8bb079de36ae61a4c0", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/BNB-20220308.png", "tokenName": "Binance Coin", "tokenSymbol": "BNB" }, { "decimals": "18", "tokenContractAddress": "0x332730a4f6e03d9c55829435f10360e13cfa41ff", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/BUSD-20220308.png", "tokenName": "Binance USD", "tokenSymbol": "BUSD" }, { "decimals": "18", "tokenContractAddress": "0xdcac52e001f5bd413aa6ea83956438f29098166b", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/eth_usdk.png", "tokenName": "USDK", "tokenSymbol": "USDK" } ], "msg": "" } ``` [//]: # () [//]: # (//移动端页面布局(注释迁移时忽略)) [//]: # () [//]: # (//下一行填写 API名称) [//]: # (# 获取币种列表) [//]: # () [//]: # (获取欧易DEX聚合器协议支持兑换的币种列表) [//]: # () [//]: # () [//]: # () [//]: # () [//]: # (## 请求地址) [//]: # (「GET」https://web3.okx.com/api/v5/dex/aggregator/all-tokens) [//]: # () [//]: # (## 请求参数) [//]: # (// 下方填写请求参数表格(如果存在path 和 query 则分别分点描述)) [//]: # () [//]: # (| 参数名 | 类型 | 是否必须 | 描述 |) [//]: # (|---------|--------|------|---------------------------------|) [//]: # (| chainId | String | 是 | 链 ID (如`1`: Ethereum,更多可查看数据字典) |) [//]: # () [//]: # () [//]: # () [//]: # (## 请求示例) [//]: # () [//]: # () [//]: # (//下方填写shell 代码) [//]: # () [//]: # (```shell) [//]: # (curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/all-tokens?chainId=1') [//]: # (```) [//]: # () [//]: # () [//]: # (//下方填写java 代码) [//]: # () [//]: # () [//]: # () [//]: # (//此区域可写其他补充性内容) [//]: # () [//]: # () [//]: # (## 响应参数) [//]: # (// 下方填写响应参数表格) [//]: # () [//]: # () [//]: # (## 响应示例) [//]: # () [//]: # () [//]: # () [//]: # () [//]: # (```json) [//]: # ({) [//]: # ( "code": "0",) [//]: # ( "data": [) [//]: # ( {) [//]: # ( "decimals": 18,) [//]: # ( "tokenContractAddress": "0xdf54b6c6195ea4d948d03bfd818d365cf175cfc2",) [//]: # ( "tokenLogoUrl": "https://static.coinall.ltd/cdn/wallet/logo/okb.png",) [//]: # ( "tokenName": "OKB",) [//]: # ( "tokenSymbol": "OKB") [//]: # ( },) [//]: # ( {) [//]: # ( "decimals": 6,) [//]: # ( "tokenContractAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7",) [//]: # ( "tokenLogoUrl": "https://static.coinall.ltd/cdn/wallet/logo/usdt.png",) [//]: # ( "tokenName": "Tether",) [//]: # ( "tokenSymbol": "USDT") [//]: # ( },) [//]: # ( {) [//]: # ( "decimals": 6,) [//]: # ( "tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",) [//]: # ( "tokenLogoUrl": "https://static.oklink.com/cdn/explorer/okexchain/exchain_usdc.png",) [//]: # ( "tokenName": "USD Coin",) [//]: # ( "tokenSymbol": "USDC") [//]: # ( },) [//]: # ( {) [//]: # ( "decimals": 18,) [//]: # ( "tokenContractAddress": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",) [//]: # ( "tokenLogoUrl": "https://static.coinall.ltd/cdn/wallet/logo/eth01.png",) [//]: # ( "tokenName": "Ethereum",) [//]: # ( "tokenSymbol": "ETH") [//]: # ( }) [//]: # ( ],) [//]: # ( "msg": "") [//]: # (}) [//]: # (```) [//]: # () [//]: # () [//]: # () [//]: # (//此区域可写其他补充性内容) [//]: # () [//]: # () [//]: # () [//]: # ()
- [Get Liquidity Sources](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-get-liquidity.md) {/* api-page */} # Get Liquidity Sources Get a list of liquidity that are available for swap in the OKX aggregation protocol. ### Request URL GET `https://web3.okx.com/api/v5/dex/aggregator/get-liquidity` ## Request Parameters | Parameter | Type | Required | Description | |-----------|--------|----------|--------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). |
## Response Parameters | Parameter | Type | Description | |----------------------|--------|--------------------------| | id | String | The id of liquidity (e.g., `34`) | | name | String | The name of liquidity (e.g., `Uniswap V2`) | | logo | String | Liquidity Logo URL (e.g., `https://static.okx.com/cdn/wallet/logo/UNI.png`) |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/get-liquidity?chainIndex=1' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "id": "34", "logo": "https://static.okx.com/cdn/wallet/logo/UNI.png", "name": "Uniswap V2" }, { "id": "29", "logo": "https://static.okx.com/cdn/wallet/logo/SUSHI.png", "name": "SushiSwap" }, { "id": "47", "logo": "https://static.okx.com/cdn/explorer/dex/logo/Dex_DefiSwap.png", "name": "DeFi Swap" }, { "id": "49", "logo": "https://static.okx.com/cdn/wallet/logo/convxswap.png", "name": "Convergence" }, { "id": "48", "logo": "https://static.okx.com/cdn/wallet/logo/luaswap.png", "name": "LuaSwap" }, { "id": "40", "logo": "https://static.okx.com/cdn/wallet/logo/SHIB.png", "name": "ShibaSwap" }, { "id": "30", "logo": "https://static.okx.com/cdn/wallet/logo/pancake.png", "name": "PancakeSwap" }, { "id": "53", "logo": "https://static.okx.com/cdn/wallet/logo/UNI.png", "name": "Uniswap V3" }, { "id": "54", "logo": "https://static.okx.com/cdn/wallet/logo/balancer.png", "name": "Balancer V1" }, { "id": "51", "logo": "https://static.okx.com/cdn/wallet/logo/balancer.png", "name": "Balancer V2" }, { "id": "55", "logo": "https://static.okx.com/cdn/wallet/logo/Curve.png", "name": "Curve V1" }, { "id": "259", "logo": "https://static.okx.com/cdn/wallet/logo/Curve.png", "name": "Curve" }, { "id": "58", "logo": "https://static.okx.com/cdn/wallet/logo/Curve.png", "name": "Curve V2" }, { "id": "52", "logo": "https://static.okx.com/cdn/wallet/logo/bancor.png", "name": "Bancor" }, { "id": "59", "logo": "https://static.okx.com/cdn/wallet/logo/Kyber.png", "name": "Kyber" }, { "id": "81", "logo": "https://static.okx.com/cdn/wallet/logo/Synapse.png", "name": "Synapse" }, { "id": "83", "logo": "https://static.okx.com/cdn/wallet/logo/Wombat.png", "name": "Wombat" }, { "id": "80", "logo": "https://static.okx.com/cdn/wallet/logo/DODO.png", "name": "DODO" }, { "id": "82", "logo": "https://static.okx.com/cdn/wallet/logo/Shell.png", "name": "Shell" }, { "id": "88", "logo": "https://static.okx.com/cdn/wallet/logo/DODO.png", "name": "DODO V2" }, { "id": "264", "logo": "https://static.okx.com/cdn/wallet/logo/DODO.png", "name": "DODO V3" }, { "id": "91", "logo": "https://static.okx.com/cdn/wallet/logo/Smoothy.png", "name": "Smoothy" }, { "id": "92", "logo": "https://static.okx.com/cdn/wallet/logo/RadioShack.png", "name": "RadioShack" }, { "id": "90", "logo": "https://static.okx.com/cdn/wallet/logo/ORION.png", "name": "Orion" }, { "id": "89", "logo": "https://static.okx.com/cdn/wallet/logo/FraxFinance.png", "name": "FraxSwap" }, { "id": "99", "logo": "https://static.okx.com/cdn/wallet/logo/okb.png", "name": "OKX DEX" }, { "id": "28", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Hashflow.png", "name": "HashFlow" }, { "id": "101", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Swapr.png", "name": "Swapr" }, { "id": "351", "logo": "https://static.okx.com/cdn/wallet/logo/dex_DFX.png", "name": "DFX Finance V3" }, { "id": "104", "logo": "https://static.okx.com/cdn/wallet/logo/dex_bancor.png", "name": "Bancor V3" }, { "id": "105", "logo": "https://static.okx.com/cdn/wallet/logo/dex_PSM.png", "name": "PSM" }, { "id": "106", "logo": "https://static.okx.com/cdn/wallet/logo/balancer.png", "name": "Balancer" }, { "id": "108", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Verse.png", "name": "Verse" }, { "id": "110", "logo": "https://static.okx.com/cdn/wallet/logo/dex_1inch_limit_order.png", "name": "1inch Limit Order" }, { "id": "248", "logo": "https://static.okx.com/cdn/wallet/logo/okb.png", "name": "OKX Limit Order" }, { "id": "132", "logo": "https://static.okx.com/cdn/wallet/logo/dex_defiplaza.png", "name": "DefiPlaza" }, { "id": "114", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Swerve.png", "name": "Swerve" }, { "id": "113", "logo": "https://static.okx.com/cdn/wallet/logo/Kyber.png", "name": "Kyber Elastic" }, { "id": "131", "logo": "https://static.okx.com/cdn/wallet/logo/dex_defiplaza.png", "name": "StablePlaza" }, { "id": "130", "logo": "https://static.okx.com/cdn/wallet/logo/dex_0x_limit_order.png", "name": "0x Limit Order" }, { "id": "133", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Clipper.png", "name": "Clipper" }, { "id": "134", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Lido.png", "name": "Lido" }, { "id": "135", "logo": "https://static.okx.com/cdn/wallet/logo/dex_NOMISWAP.png", "name": "Nomiswap Stable" }, { "id": "136", "logo": "https://static.okx.com/cdn/explorer/dex/logo/solidly.png", "name": "Solidly" }, { "id": "215", "logo": "https://static.okx.com/cdn/wallet/logo/traderjoexyz.png", "name": "Trader Joe V2.1" }, { "id": "153", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Cafe_Swap.png", "name": "Cafe Swap" }, { "id": "141", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_ELK.png", "name": "ELK" }, { "id": "102", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Unifi.png", "name": "Unifi" }, { "id": "159", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_LINKSWAP.png", "name": "LINKSWAP" }, { "id": "160", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Sake_Swap.png", "name": "Sake Swap" }, { "id": "27", "logo": "https://static.okx.com/cdn/wallet/logo/Curve.png", "name": "Curve 3CRV" }, { "id": "202", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Aave.png", "name": "Aave V2" }, { "id": "230", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Aave.png", "name": "Aave V3" }, { "id": "199", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Compound.png", "name": "Compound" }, { "id": "266", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Compound.png", "name": "Compound V3" }, { "id": "184", "logo": "https://static.okx.com/cdn/wallet/logo/dex_logo_Frax.png", "name": "sfrxETH" }, { "id": "356", "logo": "https://static.okx.com/cdn/wallet/logo/dex_logo_Frax.png", "name": "sFRAX" }, { "id": "186", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Lido.png", "name": "stMatic" }, { "id": "200", "logo": "https://static.okx.com/cdn/wallet/logo/pancake.png", "name": "PancakeSwap V3" }, { "id": "203", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Rocketpool.png", "name": "RocketPool" }, { "id": "207", "logo": "https://static.okx.com/cdn/wallet/logo/dex_kronos.png", "name": "Kronos" }, { "id": "204", "logo": "https://static.okx.com/cdn/wallet/logo/dex_1inch_limit_order.png", "name": "1inch LP v1.1" }, { "id": "210", "logo": "https://static.okx.com/cdn/wallet/logo/Curve.png", "name": "Curve TNG" }, { "id": "330", "logo": "https://static.okx.com/cdn/wallet/logo/Curve.png", "name": "CurveNG" }, { "id": "214", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Mooniswap.png", "name": "Mooniswap" }, { "id": "213", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Integral.png", "name": "Integral" }, { "id": "218", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Maverick.png", "name": "Maverick V1" }, { "id": "226", "logo": "https://static.okx.com/cdn/wallet/logo/Curve.png", "name": "Curve LLAMMA" }, { "id": "234", "logo": "https://static.okx.com/cdn/explorer/dex/logo/Dex_xSigma.png", "name": "xSigma" }, { "id": "239", "logo": "https://static.okx.com/cdn/explorer/dex/logo/Dex_Sushiswap_V3.png", "name": "Sushiswap V3" }, { "id": "257", "logo": "https://static.okx.com/cdn/explorer/dex/logo/Synthetix.png", "name": "Wrapped Synthetix" }, { "id": "262", "logo": "https://static.okx.com/cdn/explorer/dex/logo/solidly.png", "name": "Solidly V3" }, { "id": "265", "logo": "https://static.okx.com/cdn/explorer/dex/logo/SmarDex.png", "name": "SmarDex" }, { "id": "328", "logo": "https://static.okx.com/cdn/web3/dex/logo/sDai.png", "name": "sDai" }, { "id": "365", "logo": "https://static.okx.com/cdn/web3/dex/logo/Angle.png", "name": "Angle" }, { "id": "352", "logo": "https://static.okx.com/cdn/web3/dex/logo/Angle.png", "name": "Angle Stake" }, { "id": "258", "logo": "https://static.okx.com/cdn/wallet/logo/okb.png", "name": "OKX Pre Limit Order" }, { "id": "354", "logo": "https://static.okx.com/cdn/web3/dex/logo/Origin.png", "name": "Origin Wrapper" }, { "id": "355", "logo": "https://static.okx.com/cdn/web3/dex/logo/Origin.png", "name": "Origin" }, { "id": "368", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Aave.png", "name": "Bgd Aave Static" }, { "id": "379", "logo": "https://static.okx.com/cdn/web3/dex/logo/Unicly.png", "name": "Unicly" }, { "id": "394", "logo": "https://static.okx.com/cdn/web3/dex/logo/novabits.png", "name": "Novabits V3" } ], "msg": "" } ```
- [Approve Transactions](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-approve-transaction.md) {/* api-page */} # Approve Transactions According to the [ERC-20 standard ](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/), we need to make sure that the OKX router has permission to spend funds with the user's wallet before making a transaction. This API will generate the relevant data for calling the contract. ### Request URL GET `https://web3.okx.com/api/v5/dex/aggregator/approve-transaction` ## Request Parameters | Parameter | Type | Required | Description | |----------------------|--------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). | | tokenContractAddress | String | Yes | Token contract address (e.g., `0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`) | | approveAmount | String | Yes | The amount of token that needs to be permitted (set in minimal divisible units, e.g., `1.00` USDT set as `1000000`, `1.00` DAI set as `1000000000000000000`) |
## Response Parameters | Parameter | Type | Description | |--------------------|--------|----------------------------------------| | data | String | Call data | | dexContractAddress | String | The contract address of OKX DEX approve (e.g., `0x6f9ffea7370310cd0f890dfde5e0e061059dcfd9`) | | gasLimit | String | Gas limit (e.g., `50000`).
To get accurate data, please take a look at [/gas-limit](dex-onchain-gateway-api-gas-limit) API | | gasPrice | String | Gas price in wei (e.g., `110000000`) |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/approve-transaction?chainIndex=1&tokenContractAddress=0x6f9ffea7370310cd0f890dfde5e0e061059dcfd9&approveAmount=1000000' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "data": "0x095ea7b3000000000000000000000000c67879f4065d3b9fe1c09ee990b891aa8e3a4c2f00000000000000000000000000000000000000000000000000000000000f4240", "dexContractAddress": "0xc67879F4065d3B9fe1C09EE990B891Aa8E3a4c2f", "gasLimit": "50000", "gasPrice": "110000000" } ], "msg": "" } ```
- [Get Quotes](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-get-quote.md) {/* api-page */} # Get Quotes Get the best quote for a swap through OKX DEX. ### Request URL GET `https://web3.okx.com/api/v5/dex/aggregator/quote` ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). | | amount | String | Yes | The input amount of a token to be sold (if swapMode=exactIn) or buy (if swapMode=exactOut) ,set in minimal divisible units, e.g., 1.00 USDT set as 1000000, 1.00 DAI set as 1000000000000000000, you could get the minimal divisible units from [Tokenlist](https://web3.okx.com/web3/build/docs/waas/dex-get-tokens). | | swapMode | String | Yes | Possible values: [exactIn, exactOut],Default: exactIn,ExactOut is for supporting use cases where you need an exact output amount. In this case the slippage is on the input token. | | fromTokenAddress | String | Yes | The contract address of a token to be sold (e.g., `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`) | | toTokenAddress | String | Yes | The contract address of a token to be bought (e.g., `0xa892e1fef8b31acc44ce78e7db0a2dc610f92d00`) | | dexIds | String | No | DexId of the liquidity pool for limited quotes, multiple combinations separated by `,` (e.g.,`1,50,180`, see liquidity list for more) | | directRoute | Boolean | No | The default setting is false. When enabled, Direct Routes restrict our routing to a single liquidity pool only. Currently, this feature is only active for Solana swaps. | | priceImpactProtectionPercentage | String | No | (Optional. The default is 90%.) The percentage (between 0 - 1.0) of the price impact allowed.

When the priceImpactProtectionPercentage is set, if the estimated price impact is above the percentage indicated, an error will be returned. For example, if PriceImpactProtectionPercentage = .25 (25%), any quote with a price impact higher than 25% will return an error.
This is an optional feature, and the default value is 0.9. When it’s set to 1.0 (100%), the feature will be disabled, which means that every transaction will be allowed to pass.
Note: If we’re unable to calculate the price impact, we’ll return null, and the price impact protection will be disabled. | | feePercent | String | No | The percentage of fromTokenAmount will be sent to the referrer's address, the rest will be set as the input amount to be sold. `min percentage`> 0
`max percentage`: 10 for Solana, 3 for all other chains
By configuring this parameter, you can obtain the final amount of `totoken` provided to the user after deducting the commission from `fromtoken`.
A maximum of two decimal places is allowed. If more decimals are entered, the system will automatically round up.|
## Response Parameters | Parameter | Type | Description | |-----------------|--------|-------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Unique identifier for the chain. | | swapMode | String | Swap mode of this quote. | | ***dexRouterList*** | ***Array*** | ***Quote path data set*** | | fromTokenAmount | String | The input amount of a token to be sold (e.g., `500000000000000000000000`) | | toTokenAmount | String | The resulting amount of a token to be bought (e.g., `168611907733361`) | | tradeFee | String | Estimated network fee (USD) of the quote route | | estimateGasFee | String | Estimated gas consumption is returned in the smallest units of each chain, such as wei. | | router | String | One of the main paths for the token swap | | routerPercent | String | The percentage of assets handled by the main path (e.g., `5`) | | ***subRouterList*** | ***Array*** | ***DEX Router information*** | | ***dexProtocol*** | ***Array*** | ***Liquidity protocols used on the main path*** (e.g., `Verse`) | | percent | String | The percentage of assets handled by the protocol (e.g., `100`)| | dexName | String | The name of the liquidity protocol | | ***fromToken*** | ***Object*** | ***The information of a token to be sold*** | | tokenContractAddress | String | Token contract address (e.g., `0xa892e1fef8b31acc44ce78e7db0a2dc610f92d00`) | | tokenSymbol | String | Token symbol (e.g., `0xa892e1fef8b31acc44ce78e7db0a2dc610f92d00`) | | tokenUnitPrice | String | The token unit price returned by this interface is a general USD real time price based on data from on-chain sources. Note: This price is only a recommended price. For some special cases, the token unit price may be 'null' | | decimal | String | The decimal number defines the smallest unit into which a single currency token can be divided. For example, if the decimal number of a token is 8, it means that a single such token can be divided into 100,000,000 of its smallest units. ***Note: This parameter is for reference only. It may change due to reasons such as settings adjustments by the contract owner.*** | | isHoneyPot | Boolean | If the token is a honeypot token. `yes:true` `no:false ` | | taxRate | String | Token tax rate for selling: Applicable to tokens with configurable tax mechanisms (e.g., SafeMoon, SPL2022 tokens). Returns 0 for regular tokens without tax. The value ranges from 0 to 1, where 0.01 represents 1%. | | ***toToken*** | ***Object*** | ***The information of a token to be bought*** | | tokenContractAddress | String | Token contract address (e.g., `0xa892e1fef8b31acc44ce78e7db0a2dc610f92d00`) | | tokenSymbol | String | Token symbol (e.g., `0xa892e1fef8b31acc44ce78e7db0a2dc610f92d00`) | | tokenUnitPrice | String | The token unit price returned by this interface is a general USD price based on data from on-chain, exchange, and other third-party sources. Note: This price is only a recommended price. For some special cases, the token unit price may be 'null' | | decimal | String | The decimal number defines the smallest unit into which a single currency token can be divided. For example, if the decimal number of a token is 8, it means that a single such token can be divided into 100,000,000 of its smallest units. ***Note: This parameter is for reference only. It may change due to reasons such as settings adjustments by the contract owner.*** | | isHoneyPot | Boolean | If the token is a honeypot token. `yes:true` `no:false ` | | taxRate | String | Token tax rate for buying: Applicable to tokens with configurable tax mechanisms (e.g., SafeMoon, SPL2022 tokens). Returns 0 for regular tokens without tax. The value ranges from 0 to 1, where 0.01 represents 1%. | | ***quoteCompareList*** | ***Array*** | ***Comparison of quote routes*** | | dexName | String | DEX name of the quote route | | dexLogo | String | DEX logo of the quote route | | tradeFee | String | Estimated network fee (USD) of the quote route | | amountOut | String | Received amount of the quote route | | priceImpactPercentage | String | Percentage = (Received value – Paid value) / Paid value. The swap amount will affect the depth of the liquidity pool, causing a value difference. This percentage can be positive if the received value exceeds the paid value. |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/quote?amount=10000000000000000000&chainIndex=1&toTokenAddress=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48&fromTokenAddress=0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "chainIndex": "1", "dexRouterList": [ { "router": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee--0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "routerPercent": "100", "subRouterList": [ { "dexProtocol": [ { "dexName": "Uniswap V3", "percent": "100" } ], "fromToken": { "decimal": "18", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "tokenSymbol": "WETH", "tokenUnitPrice": "3606.94" }, "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "tokenSymbol": "USDC", "tokenUnitPrice": "0.9999" } } ] } ], "estimateGasFee": "135000", "fromToken": { "decimal": "18", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", "tokenSymbol": "ETH", "tokenUnitPrice": "3606.94" }, "fromTokenAmount": "1000000000000000", "originToTokenAmount": "3608628", "priceImpactPercentage": "0.04", "quoteCompareList": [ { "amountOut": "35984", "dexLogo": "https://static.okx.com/cdn/wallet/logo/DODO.png", "dexName": "DODO", "tradeFee": "13.609993622490384" }, { "amountOut": "3586381", "dexLogo": "https://static.okx.com/cdn/wallet/logo/balancer.png", "dexName": "Balancer V1", "tradeFee": "16.319948104844664" }, { "amountOut": "3580447", "dexLogo": "https://static.okx.com/cdn/wallet/logo/UNI.png", "dexName": "Uniswap V1", "tradeFee": "8.018574649654157568" }, { "amountOut": "3585311", "dexLogo": "https://static.okx.com/cdn/web3/dex/logo/Fluid.png", "dexName": "Fluid", "tradeFee": "7.957841558644062204" }, { "amountOut": "3591031", "dexLogo": "https://static.okx.com/cdn/wallet/logo/balancer.png", "dexName": "Balancer V2", "tradeFee": "7.286766496997064" } ], "swapMode": "exactIn", "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "tokenSymbol": "USDC", "tokenUnitPrice": "0.9999" }, "toTokenAmount": "3608628", "tradeFee": "4.1057406791269083" } ], "msg": "" } ```
- [Get Solana Swap Instructions](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-solana-swap-instruction.md) {/* api-page */} # Get Solana Swap Instructions Obtain transaction instruction data for redemption or custom assembly in Solana. ### Request URL GET `https://web3.okx.com/api/v5/dex/aggregator/swap-instruction` ## Request Parameters | Parameter | Type | Required | Description | |----------------------------------|---------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `501`: Solana.
See more [here](./dex-supported-chain). | | amount | String | Yes | Token amount for the quote.
(The amount must include its precision. For example, exchanging 1.00 USDT requires inputting `1000000`, while exchanging 1.00 DAI requires `1000000000000000000`. Token precision can be obtained from the token list.) | | fromTokenAddress | String | Yes | Address of the token contract being swapped from (e.g., `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`). | | toTokenAddress | String | Yes | Address of the token contract being swapped to (e.g., `0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`). | | slippage | String | Yes | Slippage limit.
**Note:**
On Solana, the minimum is `0`, and the maximum must be less than `1`.
(e.g., `0.005` means a max slippage of `0.5%`, `1` means `100%`). | | autoSlippage | Boolean | No | Default is false. When set to true, the original slippage (if set) will be covered by the autoSlippage and the API will calculate and return auto slippage recommendations based on current market data. | | maxAutoSlippage | String | No | When autoSlippage is set to true, this value is the maximum auto slippage returned by the API. We recommend that users adopt this value to ensure risk control. | | userWalletAddress | String | Yes | User’s wallet address (e.g., `0x3f6a3f57569358a512ccc0e513f171516b0fd42a`). | | swapReceiverAddress | String | No | Recipient address for the purchased asset. If not set, the asset will be sent to the `userWalletAddress`. (e.g., `0x3f6a3f57569358a512ccc0e513f171516b0fd42a`). | | feePercent | String | No | Percentage of the `fromToken` or `toToken` amount sent to the referral address. Minimum: `0%`, Maximum: `10%`, supports up to two decimal places (e.g., input `1.326%`, but only `1.32%` will be used). | | fromTokenReferrerWalletAddress | String | No | Wallet address receiving the referral fee in `fromToken`.
**Must be used with `feePercent`**, and a single transaction can only apply **either `fromToken` or `toToken` referral fees**.

**Note:**
**Solana:** The referral address must hold some SOL for activation. | | toTokenReferrerWalletAddress | String | No | Wallet address receiving the referral fee in `toToken`.
**Must be used with `feePercent`**, and a single transaction can only apply **either `fromToken` or `toToken` referral fees**.

**Note:**
**Solana:** The referral address must hold some SOL for activation. | | positiveSlippagePercent | String | No | This feature is open to **whitelist or enterprise clients** only. If you want to access it , please contact dexapi.okx.com

Once configured, a fee can be charged on the quote improvement portion, capped at 10% of the total trade amount.

The cap can be adjusted by specifying a custom percentage parameter.The default setting is 0. `Min percentage`: 0 ,`Max percentage`: 10 , Maximum of 1 decimal point.
Currently, this parameter is only supported on the **Solana chain**. | | positiveSlippageFeeAddress | string | No | This feature is open to **whitelist or enterprise clients** only. If you want to use it , please contact dexapi.okx.com

The wallet address that receives positive slippage. You must set positiveSlippagePercent parameter together to specify the proportion. If provided, all positive slippage earnings will be sent to this address; if not provided, the wallet address used for collecting referral fees will be used instead. | | dexIds | String | No | Restrict the quote to specific liquidity pools by `dexId`. Multiple IDs should be comma-separated (e.g., `1,50,180`. See liquidity list for more details). | | excludeDexIds | String | No | The dexId of the liquidity pool will not be used, multiple combinations separated by `,` (e.g.,`1,50,180`, see liquidity list for more) | | disableRFQ | Boolean| No | Disable all liqudity source classified as RFQs that have dependencies on time-sensitive quotes. The default setting is false. | | directRoute | Boolean | No | The default setting is false. When enabled, Direct Routes restrict our routing to a single liquidity pool only. Currently, this feature is only active for Solana swaps. | | priceImpactProtectionPercentage | String | No | (Optional, default: `90%`) Allowed price impact percentage (between `0` and `1.0`).
If the estimated price impact exceeds the specified percentage, an error will be returned.
Example: If `priceImpactProtectionPercentage = 0.25 (25%)`, any quote exceeding `25%` price impact will return an error.

**This is an optional feature**, defaulting to `0.9`. Setting it to `1.0 (100%)` disables this protection, allowing all trades to proceed.

**Note:** If price impact cannot be calculated, it will return `null`, and this feature will be disabled. | | computeUnitPrice | String | No | Used for transactions on the Solana network and similar to gasPrice on Ethereum. This price determines the priority level of the transaction. The higher the price, the more likely that the transaction can be processed faster. | | computeUnitLimit | String | No | Used for transactions on the Solana network and analogous to gasLimit on Ethereum, which ensures that the transaction won’t take too much computing resource. |
## Response parameterseter | Parameter | Type | Description | |------------------------------------|-----------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | addressLookupTableAccount | Array | Address Lookup Table Account. A data structure in the Solana blockchain used to optimize the management and referencing of addresses in transactions. It allows developers to store a group of related addresses in a table and reference them in transactions via index values (instead of the full 32-byte address), significantly improving transaction efficiency and scalability. | | instructionLists | Array | Detailed transaction instruction information | | data | String | Instruction data | | accounts | Array | Instruction account information | | isSigner | Boolean | Whether the account is a signer | | isWritable | Boolean | Whether the account is writable | | pubkey | Boolean | Public key address of the account | | programId | String | Program ID for instruction execution | | ***routerResult*** | ***Object*** | ***Quote path data*** | | chainIndex | String | Unique identifier for the chain. | | swapMode | String | Swap mode of this quote. | | fromTokenAmount | String | The input amount of a token to be sold ( e.g.,`500000000000000000000000`) | | toTokenAmount | String | The resulting amount of a token to be bought ( e.g.,`168611907733361`) | | tradeFee | String | Estimated network fee (USD) of the quote route | | estimateGasFee | String | Estimated gas consumption is returned in the smallest units of each chain, such as wei. | | ***dexRouterList*** | ***Array*** | ***Quote path data set*** | | router | String | One of the main paths for the token swap | | routerPercent | String | The percentage of assets handled by the main path (e.g.,`5`) | | ***subRouterList*** | ***Array*** | ***Quote path sub data set*** | | ***dexProtocol*** | ***Array*** | ***Liquidity protocols used on the main path*** | | dexName | String | The name of the liquidity protocol (e.g.,`Verse`) | | percent | String | The percentage of assets handled by the protocol (e.g.,`100`) | | ***fromToken*** | ***Object*** | ***The information of a token to be sold*** | | tokenContractAddress | String | Token contract address (e.g.,`0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`) | | tokenSymbol | String | Token symbol (e.g.,`USDC`) | | tokenUnitPrice | String | The token unit price returned by this interface is a general USDis a general USD real time price based on data from on-chain sources. Note: This price is only a recommended price. For some special cases, the token unit price may be 'null' | | decimal | String | The decimal number defines the smallest unit into which a single currency token can be divided. For example, if the decimal number of a token is 8, it means that a single such token can be divided into 100,000,000 of its smallest units. ***Note: This parameter is for reference only. It may change due to reasons such as settings adjustments by the contract owner.*** | | isHoneyPot | Boolean | If the token is a honeypot token. `yes:true` `no:false ` | | taxRate | String | Token tax rate for selling: Applicable to tokens with configurable tax mechanisms (e.g., SafeMoon, SPL2022 tokens). Returns 0 for regular tokens without tax. The value ranges from 0 to 1, where 0.01 represents 1%. | | ***toToken*** | ***Object*** | ***The information of a token to be bought*** | | tokenContractAddress | String | Token contract address (e.g.,`0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`) | | tokenSymbol | String | Token symbol (e.g.,`USDC`) | | tokenUnitPrice | String | The token unit price returned by this interface is a general USD price based on data from on-chain, exchange, and other third-party sources. Note: This price is only a recommended price. For some special cases, the token unit price may be 'null' | | decimal | String | The decimal number defines the smallest unit into which a single currency token can be divided. For example, if the decimal number of a token is 8, it means that a single such token can be divided into 100,000,000 of its smallest units. ***Note: This parameter is for reference only. It may change due to reasons such as settings adjustments by the contract owner.*** | | isHoneyPot | Boolean | If the token is a honeypot token. `yes:true` `no:false ` | | taxRate | String | Token tax rate for buying: Applicable to tokens with configurable tax mechanisms (e.g., SafeMoon, SPL2022 tokens). Returns 0 for regular tokens without tax. The value ranges from 0 to 1, where 0.01 represents 1%. | | ***quoteCompareList*** | ***Array*** | ***Comparison of quote routes*** | | dexName | String | DEX name of the quote route | | dexLogo | String | DEX logo of the quote route | | tradeFee | String | Estimated network fee (USD) of the quote route | | amountOut | String | Received amount of the quote route | | priceImpactPercentage | String | Percentage = (Received value – Paid value) / Paid value. The swap amount will affect the depth of the liquidity pool, causing a value difference. This percentage can be positive if the received value exceeds the paid value. | | ***tx*** | ***Object*** | ***contract data model*** | | from | String | User's wallet address (e.g.,`0x3f6a3f57569358a512ccc0e513f171516b0fd42a`) | | to | String | The contract address of OKX DEX router (e.g.,`0x3b3ae790Df4F312e745D270119c6052904FB6790`) | | minReceiveAmount | String | The minimum amount of a token to buy when the price reaches the upper limit of slippage (e.g.,`900645839798`) | | slippage | String | The value of current transaction slippage |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/swap-instruction?chainIndex=501&amount=350000000&fromTokenAddress=11111111111111111111111111111111&toTokenAddress=Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB&slippage=0.4&userWalletAddress=FvUDkjR1STZ3c6g3DjXwLsiQ477t2HGH4LQ81xMKWJZk \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": { "addressLookupTableAccount": [ "AUEghuJaUr4qshAQoSDvV8kfv7xz2kQGeR13G3FihMum", "94jzMYK5NBoExhtdwzfVNVim6Y8b95JJ9xavKHGSns8R" ], "instructionLists": [ { "data": "AkCKAwA=", "accounts": [], "programId": "ComputeBudget111111111111111111111111111111" }, { "data": "A/EHCAAAAAAA", "accounts": [], "programId": "ComputeBudget111111111111111111111111111111" }, { "data": "AwAAAPwNLKvNGLxaIoVvQDDuyL46JSWpUG7CLB02dQ/9KzWaDQAAAAAAAAAxNzQ5MjU5NDU1OTU28B0fAAAAAAClAAAAAAAAAAbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCp", "accounts": [ { "isSigner": true, "isWritable": false, "pubkey": "HxuPhmAYQwM4CvdJREL8ad3DgDWGVq4xBfy1vgGev5X7" }, { "isSigner": false, "isWritable": false, "pubkey": "DyWu8Q3aKuuDnzmgSBPGdczPsf5UixkJcGNr3zeyBqvW" } ], "programId": "11111111111111111111111111111111" }, { "data": "AQ==", "accounts": [ { "isSigner": false, "isWritable": true, "pubkey": "DyWu8Q3aKuuDnzmgSBPGdczPsf5UixkJcGNr3zeyBqvW" }, { "isSigner": false, "isWritable": false, "pubkey": "So11111111111111111111111111111111111111112" }, { "isSigner": false, "isWritable": false, "pubkey": "HxuPhmAYQwM4CvdJREL8ad3DgDWGVq4xBfy1vgGev5X7" }, { "isSigner": false, "isWritable": false, "pubkey": "SysvarRent111111111111111111111111111111111" } ], "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" }, { "data": "AgAAAOAPlwAAAAAA", "accounts": [ { "isSigner": true, "isWritable": true, "pubkey": "HxuPhmAYQwM4CvdJREL8ad3DgDWGVq4xBfy1vgGev5X7" }, { "isSigner": false, "isWritable": true, "pubkey": "DyWu8Q3aKuuDnzmgSBPGdczPsf5UixkJcGNr3zeyBqvW" } ], "programId": "11111111111111111111111111111111" }, { "data": "EQ==", "accounts": [ { "isSigner": false, "isWritable": true, "pubkey": "DyWu8Q3aKuuDnzmgSBPGdczPsf5UixkJcGNr3zeyBqvW" } ], "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" }, { "data": "AQ==", "accounts": [ { "isSigner": true, "isWritable": true, "pubkey": "HxuPhmAYQwM4CvdJREL8ad3DgDWGVq4xBfy1vgGev5X7" }, { "isSigner": false, "isWritable": true, "pubkey": "52WMDiGUj8UEzSzWjguGGnaWmnjeQobuB4qYdyKdmx4W" }, { "isSigner": false, "isWritable": false, "pubkey": "HxuPhmAYQwM4CvdJREL8ad3DgDWGVq4xBfy1vgGev5X7" }, { "isSigner": false, "isWritable": false, "pubkey": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" }, { "isSigner": false, "isWritable": false, "pubkey": "11111111111111111111111111111111" }, { "isSigner": false, "isWritable": false, "pubkey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" } ], "programId": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" }, { "data": "Rcj+9yg0dsrgD5cAAAAAACkhFgAAAAAA5wUVAAAAAAABAAAA4A+XAAAAAAABAAAAAQAAAAEAAAAiAQAAAGSAlpiAAAAAAAAhkAEAAAAAAA==", "accounts": [ { "isSigner": true, "isWritable": true, "pubkey": "HxuPhmAYQwM4CvdJREL8ad3DgDWGVq4xBfy1vgGev5X7" }, { "isSigner": false, "isWritable": true, "pubkey": "DyWu8Q3aKuuDnzmgSBPGdczPsf5UixkJcGNr3zeyBqvW" }, { "isSigner": false, "isWritable": true, "pubkey": "52WMDiGUj8UEzSzWjguGGnaWmnjeQobuB4qYdyKdmx4W" }, { "isSigner": false, "isWritable": false, "pubkey": "So11111111111111111111111111111111111111112" }, { "isSigner": false, "isWritable": false, "pubkey": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" }, { "isSigner": false, "isWritable": true, "pubkey": "HxuPhmAYQwM4CvdJREL8ad3DgDWGVq4xBfy1vgGev5X7" }, { "isSigner": false, "isWritable": false, "pubkey": "6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma" }, { "isSigner": false, "isWritable": false, "pubkey": "6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma" }, { "isSigner": false, "isWritable": false, "pubkey": "6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma" }, { "isSigner": false, "isWritable": false, "pubkey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" }, { "isSigner": false, "isWritable": false, "pubkey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" }, { "isSigner": false, "isWritable": false, "pubkey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" }, { "isSigner": false, "isWritable": false, "pubkey": "11111111111111111111111111111111" }, { "isSigner": false, "isWritable": false, "pubkey": "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA" }, { "isSigner": true, "isWritable": true, "pubkey": "HxuPhmAYQwM4CvdJREL8ad3DgDWGVq4xBfy1vgGev5X7" }, { "isSigner": false, "isWritable": true, "pubkey": "DyWu8Q3aKuuDnzmgSBPGdczPsf5UixkJcGNr3zeyBqvW" }, { "isSigner": false, "isWritable": true, "pubkey": "52WMDiGUj8UEzSzWjguGGnaWmnjeQobuB4qYdyKdmx4W" }, { "isSigner": false, "isWritable": false, "pubkey": "ZiVoyhTDNKdceMF4Vt7X4VgSN9r8imBuJZRkUa9rWB7" }, { "isSigner": false, "isWritable": false, "pubkey": "ADyA8hdefvWN2dbGGWFotbzWxrAvLW83WG6QCVXvJKqw" }, { "isSigner": false, "isWritable": false, "pubkey": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" }, { "isSigner": false, "isWritable": false, "pubkey": "So11111111111111111111111111111111111111112" }, { "isSigner": false, "isWritable": true, "pubkey": "AAbcQKNDfbMxd7VRjK2x3UX3wQ4omoeNjAybrV89Ayx6" }, { "isSigner": false, "isWritable": true, "pubkey": "9UgcBXUvLBuJkEHXhewVVCvrMtttUXQvbjm18z8ZT9Nf" }, { "isSigner": false, "isWritable": false, "pubkey": "62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV" }, { "isSigner": false, "isWritable": true, "pubkey": "94qWNrtmfn42h3ZjUZwWvK1MEo9uVmmrBPd2hpNjYDjb" }, { "isSigner": false, "isWritable": false, "pubkey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" }, { "isSigner": false, "isWritable": false, "pubkey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" }, { "isSigner": false, "isWritable": false, "pubkey": "11111111111111111111111111111111" }, { "isSigner": false, "isWritable": false, "pubkey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" }, { "isSigner": false, "isWritable": false, "pubkey": "GS4CU59F31iL7aR2Q8zVS8DRrcRnXX1yjQ66TqNVQnaR" }, { "isSigner": false, "isWritable": true, "pubkey": "Ei6iux5MMYG8JxCTr58goADqFTtMroL9TXJityF3fAQc" }, { "isSigner": false, "isWritable": false, "pubkey": "8N3GDaZ2iwN65oxVatKTLPNooAVUJTbfiVJ1ahyqwjSk" } ], "programId": "6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma" }, { "data": "CQ==", "accounts": [ { "isSigner": false, "isWritable": true, "pubkey": "DyWu8Q3aKuuDnzmgSBPGdczPsf5UixkJcGNr3zeyBqvW" }, { "isSigner": false, "isWritable": true, "pubkey": "HxuPhmAYQwM4CvdJREL8ad3DgDWGVq4xBfy1vgGev5X7" }, { "isSigner": true, "isWritable": true, "pubkey": "HxuPhmAYQwM4CvdJREL8ad3DgDWGVq4xBfy1vgGev5X7" } ], "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" } ], "routerResult": { "chainIndex": "501", "dexRouterList": [ { "router": "11111111111111111111111111111111--es9vmfrzacermjfrf4h2fyd4kconky11mcce8benwnyb", "routerPercent": "100", "subRouterList": [ { "dexProtocol": [ { "dexName": "PumpSwap", "percent": "100" } ], "fromToken": { "decimal": "9", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "So11111111111111111111111111111111111111112", "tokenSymbol": "wSOL", "tokenUnitPrice": "148.133239619335163594" }, "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", "tokenSymbol": "USDT", "tokenUnitPrice": "1.000673318734823276" } } ] } ], "estimateGasFee": "212000", "fromToken": { "decimal": "9", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "11111111111111111111111111111111", "tokenSymbol": "SOL", "tokenUnitPrice": "148.133239619335163594" }, "fromTokenAmount": "10000000", "priceImpactPercentage": "-1.04", "quoteCompareList": [ { "amountOut": "1.450281", "dexLogo": "https://static.okx.com/cdn/web3/dex/logo/Pumpfun.png", "dexName": "PumpSwap", "tradeFee": "0.0000001571238" } ], "swapMode": "exactIn", "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", "tokenSymbol": "USDT", "tokenUnitPrice": "1.000673318734823276" }, "toTokenAmount": "1450281", "tradeFee": "0.00074115" }, "tx": { "from": "HxuPhmAYQwM4CvdJREL8ad3DgDWGVq4xBfy1vgGev5X7", "minReceiveAmount": "1377767", "slippage": "0.05", "to": "6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma" } }, "msg": "" } ```
- [Swap](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-swap.md) {/* api-page */} # Swap Generate the data to call the OKX DEX router to execute a swap. In Uni v3 pools, the following scenario may occur:
If the liquidity for the desired token pair in the pool is depleted, the pool will only consume part of the payment token, leaving a remainder.
As a fully decentralized smart contract, the OKX DEX Router will automatically refund the remainder.
During your integration, please ensure compatibility with this scenario by configuring your contract to support token refunds, thereby ensuring a smooth user experience.
### Request URL GET `https://web3.okx.com/api/v5/dex/aggregator/swap` ## Request Parameters | Parameter | Type | Required | Description | |-------------------|--------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | No | Unique identifier for the chain. | | amount | String | Yes | The input amount of a token to be sold
(set in minimal divisible units, e.g., 1.00 USDT set as 1000000, 1.00 DAI set as 1000000000000000000), you could get the minimal divisible units from [Tokenlist](./dex-get-tokens). | | swapMode | String | Yes | Possible values: [`exactIn`, `exactOut`] Default: `exactIn` `ExactOut` is for supporting use cases where you need an exact output amount.

Note:
1.ExactOut feature currently only support **Ethereum、Base、BSC 、Arbitrum chain**.
2.ExactOut feature currently support only **Uni v2 and v3 protocols**
3. In this case the slippage is on the input token. | | fromTokenAddress | String | Yes | The contract address of a token you want to send (e.g.,`0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`) | | toTokenAddress | String | Yes | The contract address of a token you want to receive (e.g.,`0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`) | | slippage | String | Yes | Slippage limit.

Note:
1. For EVM networks, the slippage setting has a minimum value of `0` and a maximum value of `1`.
2. For Solana, the slippage setting has a minimum value of `0` and a maximum value of less than `1`.
(For example: `0.005` means that the maximum slippage for this transaction is `0.5%`, while `1` means that the maximum slippage of this transaction is `100%`.) | | userWalletAddress | String | Yes | User's wallet address (e.g.,`0x3f6a3f57569358a512ccc0e513f171516b0fd42a`) | | swapReceiverAddress | String | No | Recipient address of a purchased token if not set, `userWalletAddress` will receive a purchased token (e.g.,`0x3f6a3f57569358a512ccc0e513f171516b0fd42a`) | | feePercent | String | No | The percentage of fromTokenAmount or toTokenAmount will be sent to the referrer’s address, the rest will be set as the input amount to be sold.
**Min percentage** >`0`.
**Max percentage**: `10 for Solana, 3 for all other chains.`
Maximum 9 decimal points. Longer sections will be automatically omitted. | | fromTokenReferrerWalletAddress | String | No | The wallet address that receives the commission fee for the fromToken.
When using the API, **you must set the commission rate together with feePercent, and for each transaction, you can only choose either fromToken commission or toToken commission**.

Note:
1. For **Solana**: The referrer wallet must have some SOL deposited in advance to activate the address.
2. For **TON**: Only commission through liquidity pools of Stonfi V2 and Dedust is supported; commission through Stonfi V1 liquidity pools is not supported.
3.For **BSC Chain**: Commission split for swaps via Four.meme is not supported| | toTokenReferrerWalletAddress | String | No | The wallet address that receives the commission fee for the toToken.
When using the API, **you must set the commission rate together with feePercent, and for each transaction, you can only choose either fromToken commission or toToken commission**.

Note:
1. For **Solana**: The referrer wallet must have some SOL deposited in advance to activate the address.
2. For **TON**: Only commission through liquidity pools of Stonfi V2 is supported.
3.For **BSC Chain**: Commission split for swaps via Four.meme is not supported | | positiveSlippagePercent | String | No | This feature is open to **whitelist or enterprise clients** only. If you want to access it , please contact dexapi.okx.com

Once configured, a fee can be charged on the quote improvement portion, capped at 10% of the total trade amount.

The cap can be adjusted by specifying a custom percentage parameter.The default setting is 0. `Min percentage`: 0 ,`Max percentage`: 10 , Maximum of 1 decimal point.
Currently, this parameter is only supported on the **Solana chain**. | | positiveSlippageFeeAddress | String | No | This feature is open to **whitelist or enterprise clients** only. If you want to use it , please contact dexapi.okx.com

The wallet address that receives positive slippage. You must set positiveSlippagePercent parameter together to specify the proportion. If provided, all positive slippage earnings will be sent to this address; if not provided, the wallet address used for collecting referral fees will be used instead. | | gasLimit | String | No | The gas(In smallest units : wei) for the swap transaction. If the value is too low to achieve the quote, an error will be returned.
Only applicable to EVM| | gasLevel | String | No | ( defaults to `average`) The target gas price level for the swap transaction,set to `average` or `fast` or `slow` | | computeUnitPrice | String | No | Used for transactions on the Solana network and similar to gasPrice on Ethereum. This price determines the priority level of the transaction. The higher the price, the more likely that the transaction can be processed faster. | | computeUnitLimit | String | No | Used for transactions on the Solana network and analogous to gasLimit on Ethereum, which ensures that the transaction won’t take too much computing resource.
If the parameter `tips` is not 0, then `computeUnitPrice` should be set to 0. Otherwise, the fee is wasted. | | tips | String | No | Jito tips in SOL. The maximum is "2" and the minimum is "0.0000000001".
This is used for MEV protection. Specify `tips` to obtain calldata and call the [broadcast transaction API](./dex-onchain-gateway-api-broadcast-transaction)。 | dexIds | String | No | DexId of the liquidity pool for limited quotes, multiple combinations separated by `,` (e.g., `1,50,180`, see liquidity list for more) | | excludeDexIds | String | No | The dexId of the liquidity pool will not be used, multiple combinations separated by `,` (e.g.,`1,50,180`, see liquidity list for more) | | disableRFQ | Boolean| No | Disable all liqudity source classified as RFQs that have dependencies on time-sensitive quotes. The default setting is false. | | directRoute | Boolean | No | The default setting is false. When enabled, Direct Routes restrict our routing to a single liquidity pool only. Currently, this feature is only active for Solana swaps. | | priceImpactProtectionPercentage | String | No | ( The default is 90%.) The percentage (between 0 - 1.0) of the price impact allowed.

When the priceImpactProtectionPercentage is set, if the estimated price impact is above the percentage indicated, an error will be returned. For example, if PriceImpactProtectionPercentage = .25 (25%), any quote with a price impact higher than 25% will return an error.
When it’s set to 1.0 (100%), the feature will be disabled, which means that every transaction will be allowed to pass.
Note: If we’re unable to calculate the price impact, we’ll return null, and the price impact protection will be disabled. | | callDataMemo | String | No | You can customize the parameters to be sent on the blockchain in callData by encoding the data into a 128-character 64-bytes hexadecimal string. For example, the string “0x...111” needs to keep the “0x” at its start. | | autoSlippage | Boolean | No | Default is false. When set to true, the original slippage (if set) will be covered by the autoSlippage and the API will calculate and return auto slippage recommendations based on current market data. | | maxAutoSlippage | String | No | When autoSlippage is set to true, this value is the maximum auto slippage returned by the API. We recommend that users adopt this value to ensure risk control. |
## Response Parameters | Parameter | Type | Description | |------------------|--------|---------------------------------------------------------------------------------------------------------------------------------------| | ***routerResult*** | ***Object*** | ***Quote path data*** | | chainIndex | String | Unique identifier for the chain. | | swapMode | String | Swap mode of this quote. | | fromTokenAmount | String | The input amount of a token to be sold ( e.g.,`500000000000000000000000`) | | toTokenAmount | String | The resulting amount of a token to be bought ( e.g.,`168611907733361`) | | tradeFee | String | Estimated network fee (USD) of the quote route | | estimateGasFee | String | Estimated gas consumption is returned in the smallest units of each chain, such as wei. | | ***dexRouterList*** | ***Array*** | ***Quote path data set*** | | router | String | One of the main paths for the token swap | | routerPercent | String | The percentage of assets handled by the main path (e.g.,`5`) | | ***subRouterList*** | ***Array*** | ***Quote path sub data set*** | | ***dexProtocol*** | ***Array*** | ***Liquidity protocols used on the main path*** | | dexName | String | The name of the liquidity protocol (e.g.,`Verse`) | | percent | String | The percentage of assets handled by the protocol (e.g.,`100`) | | ***fromToken*** | ***Object*** | ***The information of a token to be sold*** | | tokenContractAddress | String | Token contract address (e.g.,`0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`) | | tokenSymbol | String | Token symbol (e.g.,`USDC`) | | tokenUnitPrice | String | The token unit price returned by this interface is a general USDis a general USD real time price based on data from on-chain sources. Note: This price is only a recommended price. For some special cases, the token unit price may be 'null' | | decimal | String | The decimal number defines the smallest unit into which a single currency token can be divided. For example, if the decimal number of a token is 8, it means that a single such token can be divided into 100,000,000 of its smallest units. ***Note: This parameter is for reference only. It may change due to reasons such as settings adjustments by the contract owner.*** | | isHoneyPot | Boolean | If the token is a honeypot token. `yes:true` `no:false ` | | taxRate | String | Token tax rate for selling: Applicable to tokens with configurable tax mechanisms (e.g., SafeMoon, SPL2022 tokens). Returns 0 for regular tokens without tax. The value ranges from 0 to 1, where 0.01 represents 1%. | | ***toToken*** | ***Object*** | ***The information of a token to be bought*** | | tokenContractAddress | String | Token contract address (e.g.,`0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`) | | tokenSymbol | String | Token symbol (e.g.,`USDC`) | | tokenUnitPrice | String | The token unit price returned by this interface is a general USD price based on data from on-chain, exchange, and other third-party sources. Note: This price is only a recommended price. For some special cases, the token unit price may be 'null' | | decimal | String | The decimal number defines the smallest unit into which a single currency token can be divided. For example, if the decimal number of a token is 8, it means that a single such token can be divided into 100,000,000 of its smallest units. ***Note: This parameter is for reference only. It may change due to reasons such as settings adjustments by the contract owner.*** | | isHoneyPot | Boolean | If the token is a honeypot token. `yes:true` `no:false ` | | taxRate | String | Token tax rate for buying: Applicable to tokens with configurable tax mechanisms (e.g., SafeMoon, SPL2022 tokens). Returns 0 for regular tokens without tax. The value ranges from 0 to 1, where 0.01 represents 1%. | | ***quoteCompareList*** | ***Array*** | ***Comparison of quote routes*** | | dexName | String | DEX name of the quote route | | dexLogo | String | DEX logo of the quote route | | tradeFee | String | Estimated network fee (USD) of the quote route | | amountOut | String | Received amount of the quote route | | priceImpactPercentage | String | Percentage = (Received value – Paid value) / Paid value. The swap amount will affect the depth of the liquidity pool, causing a value difference. This percentage can be positive if the received value exceeds the paid value. | | ***tx*** | ***Object*** | ***contract data model*** | | signatureData | ***Array*** | If this parameter is returned, it indicates that the transaction requires additional signing data. Developers should use this parameter as one of the inputs for the transaction signature and ensure it is correctly applied during the signing process.
When you specify the `tips` request parameter, this parameter value represents the calldata of the jito tips transfer. Use it to broadcast transactions, refer to [this API](./dex-onchain-gateway-api-broadcast-transaction) | | from | String | User's wallet address (e.g.,`0x3f6a3f57569358a512ccc0e513f171516b0fd42a`) | | gas | String | estimated amount of the gas limit, increase this value by 50% (e.g.,`1173250`).
To get accurate data, please take a look at [/gas-limit](dex-onchain-gateway-api-gas-limit) API | | gasPrice | String | Gas price in wei (e.g.,`58270000000`) | | maxPriorityFeePerGas | String | EIP-1559: Recommended priority cost of gas per unit (e.g.,`500000000`) | | to | String | The contract address of OKX DEX router (e.g.,`0x3b3ae790Df4F312e745D270119c6052904FB6790`) | | value | String | The amount of native tokens (in wei) that will be sent to the contract address (e.g.,`0`) | | maxSpendAmount | String | The maximum amount of a token to spend when the price reaches the upper limit of slippage (applies to the exactOut mode) | | minReceiveAmount | String | The minimum amount of a token to buy when the price reaches the upper limit of slippage (e.g.,`900645839798`) | | data | String | Call data | | slippage | String | The value of current transaction slippage |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/swap?chainIndex=1&amount=10000000000000&toTokenAddress=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48&fromTokenAddress=0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee&slippage=0.05&userWalletAddress=0x6f9ffea7370310cd0f890dfde5e0e061059dcfb8' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "routerResult": { "chainIndex":"1", "dexRouterList": [ { "router": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee--0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "routerPercent": "100", "subRouterList": [ { "dexProtocol": [ { "dexName": "Uniswap V3", "percent": "100" } ], "fromToken": { "decimal": "18", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "tokenSymbol": "WETH", "tokenUnitPrice": "3342.87" }, "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "tokenSymbol": "USDC", "tokenUnitPrice": "0.9995" } } ] } ], "estimateGasFee": "135000", "fromToken": { "decimal": "18", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", "tokenSymbol": "ETH", "tokenUnitPrice": "3342.87" }, "fromTokenAmount": "10000000000000", "priceImpactPercentage": "0.001", "quoteCompareList": [ { "amountOut": "32990", "dexLogo": "https://static.okx.com/cdn/wallet/logo/balancer.png", "dexName": "Balancer V1", "tradeFee": "44.32919149271585462" }, { "amountOut": "334", "dexLogo": "https://static.okx.com/cdn/wallet/logo/DODO.png", "dexName": "DODO", "tradeFee": "36.96825563599181972" }, { "amountOut": "33023", "dexLogo": "https://static.okx.com/cdn/wallet/logo/balancer.png", "dexName": "Balancer V2", "tradeFee": "19.79273863696907162" }, { "amountOut": "32980", "dexLogo": "https://static.okx.com/cdn/explorer/dex/logo/Dex_Sushiswap_V3.png", "dexName": "Sushiswap V3", "tradeFee": "15.70332982767794112" }, { "amountOut": "32964", "dexLogo": "https://static.okx.com/cdn/wallet/logo/SHIB.png", "dexName": "ShibaSwap", "tradeFee": "15.70332982767794112" } ], "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "tokenSymbol": "USDC", "tokenUnitPrice": "0.9995" }, "toTokenAmount": "33474", "tradeFee": "4.3491690602723664" }, "tx": { "data": "0x0d5f0e3b00000000000000000001881f6f9ffea7370310cd0f890dfde5e0e061059dcfb8000000000000000000000000000000000000000000000000000009184e72a0000000000000000000000000000000000000000000000000000000000000007c3800000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001800000000000000000000000e0554a476a092703abdb3ef35c80e0d76d32939f", "from": "0x6f9ffea7370310cd0f890dfde5e0e061059dcfb8", "gas": "202500", "gasPrice": "32657616776", "maxPriorityFeePerGas": "2086453233", "minReceiveAmount": "31800", "signatureData": [ "" ], "to": "0x7D0CcAa3Fac1e5A943c5168b6CEd828691b46B36", "value": "10000000000000" } } ], "msg": "" } ```
- [Get Transaction Status](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-swap-history.md) {/* api-page */} # Get Transaction Status Get the final transaction status of a single-chain swap using `txhash`. ### Request URL GET `https://web3.okx.com/api/v5/dex/aggregator/history` ## Request Parameters | Parameter | Type | Required | Description | |--------------------|--------|----------|----------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). | | txHash | String | Yes | Transaction hash for a swap initiated via OKX DEX API | | isFromMyProject | Boolean| No | Set `true` to check if the transaction is under the current API Key. Set `false` or omit to query any OKX DEX API transaction. |
## Response Parameters | Parameter | Type | Description | |---------------------|---------|-----------------------------------------------------------------------------| | chainIndex | String | Unique identifier for the chain. | | txHash | String | Transaction hash. | | height | String | Block height where the transaction occurred. | | txTime | String | Transaction time in Unix timestamp (milliseconds). | | status | String | Transaction status: `pending` (In Progress), `success` (Success), `fail` (Failure). | | txType | String | Transaction action: `Approve`, `Wrap`, `Unwrap`, `Swap`. | | fromAddress | String | Sender's address. | | dexRouter | String | Interaction address. | | toAddress | String | Receiver's address. | | fromTokenDetails | Array | Details of the token being swapped. | | >symbol | String | Symbol of the token being swapped. | | >amount | String | Swap amount in the smallest unit (e.g., wei for Ethereum). | | >tokenAddress | String | Contract address of the token being swapped (e.g., `0xEeeeeEeeeEeEee...`). | | toTokenDetails | Array | Details of the token received in the swap. | | >symbol | String | Symbol of the token received. | | >amount | String | Amount received in the smallest unit. | | >tokenAddress | String | Contract address of the received token (e.g., `0xa0b86991c6218b36...`). | | referalAmount | String | Referral fee amount. | | errorMsg | String | Error message. | | gasLimit | String | Gas limit for the transaction. | | gasUsed | String | Gas used in the transaction, in the smallest unit (e.g., wei). | | gasPrice | String | Gas price in the smallest unit (e.g., wei). | | txFee | String | Transaction fee, response in the native token amount.Applied in Solana and Sui chain |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/history?chainIndex=784&txHash=5GePcvqEakoUtArW8PHULDSQds95vcgeiTznvbnb8hCV' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": { "chainIndex": "784", "dexRouter": "0x51159f25f262ae01e87532b673de3b38df8f0ecc2dc0581f1033df6b84b84955", "errorMsg": "", "fromAddress": "0x4b9df646075d8621e2578f14818427e4c708709744ea3b827136056f85f88da7", "fromTokenDetails": { "amount": "892919000000.000", "symbol": "HIPPO", "tokenAddress": "0x8993129d72e733985f7f1a00396cbd055bad6f817fee36576ce483c8bbb8b87b::sudeng::SUDENG" }, "gasLimit": "", "gasPrice": "", "gasUsed": "", "height": "99502953", "referralAmount": "892919000", "status": "success", "toAddress": "0x4b9df646075d8621e2578f14818427e4c708709744ea3b827136056f85f88da7", "toTokenDetails": { "amount": "1532443840.00000000", "symbol": "SUI", "tokenAddress": "0x2::sui::SUI" }, "txFee": "7976416", "txHash": "5GePcvqEakoUtArW8PHULDSQds95vcgeiTznvbnb8hCV", "txTime": "1736390263909", "txType": "swap" }, "msg": "" } ```
- [Adding Fees ](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-api-addfee.md) # Adding Fees The OKX DEX API supports configuring referral fees and fee-receiving addresses for token swaps You can extend the implementation to include fee parameters in your swap quotes and charge up to 3% per swap from your users for most supported networks; while for Solana you can charge up to 10% per swap. The OKX DEX API plans to take a certain percentage of the referral fee charged by you to your users. For details, please visit the [API fee](./dex-api-fee) page. ```json // Extended quoteParams with fee support const quoteParams = { chainId: SOLANA_CHAIN_ID, amount: rawAmount, fromTokenAddress, toTokenAddress, slippage: "0.005", // 0.5% slippage userWalletAddress: userAddress, // Fee-related parameters fromTokenReferrerWalletAddress: "Your_REFERRER_WALLET_ADDRESS", // Optional: fee receiving address based on fromToken toTokenReferrerWalletAddress: "Your_REFERRER_WALLET_ADDRESS", // Optional: fee receiving address based on toToken feePercent: "1.5", // Optional: referrer fee percentage (max 9 decimal points) } as Record; ``` Important Fee Configuration Notes for feePercent parameter: - Min percentage > 0. Max percentage: 10 for Solana, 3 for all other chains - Maximum 9 decimal points, E.g. 1.3269018736% is the actual input, but the final calculation will only adopt 1.326901873% - For Solana, the fee receiving address must have some SOL deposited for activation - Each transaction can only choose referrer fee from either the fromToken or the toToken Example Usage with Fees: ```json // .. Previous code implementation // Get swap quote const quoteParams = { chainId: SOLANA_CHAIN_ID, amount: rawAmount, fromTokenAddress, toTokenAddress, slippage: "0.005", // 0.5% slippage userWalletAddress: userAddress, // Additional Fee params fromTokenReferrerWalletAddress: "fee-recipient-wallet-address", feePercent: "1", // The wallet addresses to receive the referrer fee (Each transaction can only choose referrer fee from either the fromToken or the toToken) // toTokenReferrerWalletAddress: "Fee receiving address, // fromTokenReferrerWalletAddress: "Fee receiving address", } as Record; const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/aggregator/swap"; const queryString = "?" + new URLSearchParams(quoteParams).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); const response = await fetch( `https://web3.okx.com${requestPath}${queryString}`, { method: "GET", headers } ); const data = await response.json(); // .. Continue code implementation ``` Command Line Usage with Fees: ```json # Example: Swap .01 SOL to USDC with 1.5% referrer fee npx ts-node swap.ts .01 11111111111111111111111111111111 EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v --referrer YOUR_FEE_RECEIVING_ADDRESS --fee 1.5 ``` Fee Calculation Example: For a trade of 100 USDC with a 1.5% fee: - Fee amount: 1.5 USDC (1.5% of 100 USDC) - Actual swap amount: 98.5 USDC - The fee (1.5 USDC) will be sent to the fee receiving address - [Market Maker Integration](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-api-market-maker.md) # Market Maker Integration ## Overview OKX DEX’s RFQ system is built on-chain and designed for professional market makers to offer efficient, competitive pricing across supported chains. By leveraging off-chain quoting with on-chain settlement, we aim to deliver the best execution for traders in DeFi. Market makers integrate with OKX DEX to continuously provide pricing data, which is then processed by our smart order router to help users achieve optimal trades. ## Market Making on OKX DEX To operate as a market maker on OKX DEX, you must connect via our dedicated API suite and fulfill the following requirements: - Able to stream live price levels once every 10 seconds - Maintain a RFQ response time below 500 ms - Return signature for the taker execution ## Order Execution Modes OKX DEX only supports taker-executed orders. Users receive a firm and executable quote from the market maker. The taker signs and submits the transaction directly. Taker-executed orders contain the following characteristics: - The maker is not required to provide a gas fee estimation - The quote and signature are submitted together - The taker is responsible for the execution ## Price Levels Makers are required to stream price levels to OKX DEX servers at least once every 10 seconds for each token pair. Any price level older than 10 seconds is considered a stale quote and will be ignored. - Quotes must be non-cumulative and level-by-level - Quotes must a cumulative value of over 200 USD. Otherwise, they will be ignored by the system - OKX DEX will request price levels every second on each chain, so quotes must be updated frequently to ensure responsiveness and accuracy ## Aggregation and Smart Routing OKX DEX aggregates liquidity across multiple makers, AMM pools and routes orders based on optimal price and fillability. Our router dynamically splits orders across sources to minimize cost and maximize execution quality. - Unified order book across all makers - Partial fills may be requested based on your streamed depth ## Approvals OKX DEX enables asset transfers through user and market maker token allowances. We support two approval methods: approving via Permit2 or approving the OKX DEX settlement contract directly. Market makers must ensure they have granted sufficient approvals to the OKX DEX settlement contract or permit2 contract to cover the size of the levels they stream and the quotes they provide. ## Signing OKX DEX on EVM supports 2 signature schemes: - EIP-712 - EIP-1271

OKX DEX on Solana currently only supports Base58-encoded signatures.

## Transaction expiry time We enforce a fixed transaction expiry timing: 60 seconds for EVM and 40 seconds for Solana. This simplifies integration by removing the need for market makers to specify custom expiry times in quote requests, providing consistent behavior across all quotes and transactions, and establishing clear timeout boundaries at different stages of the flow. ## Performance Requirements 1. You must maintain a rate of 200 RPS in firm-order, and 50 RPS in pricing 2. For the /pricing endpoint, market makers must update price quotes for each token pair within 10 seconds. We will ping your endpoint every second. If the 10-second window is exceeded, the quote for that token pair on the corresponding chain will be considered invalid. 3. The firm-order response time is 200 ms, and the maximum response time is 500 ms. Any responses above this will be dropped and marked as a failed response. 4. You must keep a successful response rate of over 90%, with at least 90% of orders successfully executed on-chain. ## Settlement Contract Address ```js const contractAddress = { ETH: '0xf0bc45115dd1e609aef685f828f2ace209abd0c6' ARB: '0x11939393f0cadfc06194ae983dafba2dcdf7308b' Base: '0x52bb195bc89a660073d890ff9edc6726f97a981b' Solana: 'RFQ1uATMXfRXemLnbYCF8JZhVfELp2K53jSEAGbsAKX' }; ``` ## Permit2 Contract Address ```js const contractAddress = { ETH: '0x000000000022D473030F116dDEE9F6B43aC78BA3' ARB: '0x000000000022D473030F116dDEE9F6B43aC78BA3' Base: '0x000000000022D473030F116dDEE9F6B43aC78BA3' }; ``` ## RFQ API Schema To facilitate the integration into OKX DEX RFQ module, you will need to provide a endpoint for us to return the pricing and firm-order endpoints with the corresponding request and response format. | Endpoint | Method | URL | Description| |--------------|--------|--------------------------------------------------------------------|------------| | Base URL | - | | Example URL that we will register into our API. | | pricing | GET | | The pricing endpoint get prices from market makers. Your levels will be used to determine if there is a path for a user order | | firm-order | POST | | Whenever a trader makes an quote request, the OKX DEX servers determine the best way to route that RFQ among the existing Market Makers. The winning Market Maker(s) receive messages and return the order and the signature. | ## API Key We would require an API key to access your endpoints. Please provide it to us during the registration process. The API Key will be passed to the endpoint as a header X-API-KEY. - [Pricing](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-api-market-maker-pricing.md) {/* api-page */} # Pricing OKX DEX will request relevant data using the parameters below and requires the following token and pricing information to obtain complete quote data: - Market makers must provide independent (non-cumulative) pricing - Pricing consists of from/to token amounts and prices - Includes: trading pair info, each price level, and depth Example: A taker wants to swap 1.26 WETH to USDT. The market maker would buy 0.2635658632112683 WETH at the price of 4257.065884207436. The remaining 0.9964341368 WETH would need to be fulfilled by other PMMs or AMMs. Another taker wants to swap 2000 USDT to WETH. The market maker would buy 1277.8023761262712 USDT at the price of 0.00023477808901049835 and buy 722.1976238737 USDT at a price of 0.00023474489972208067. ## Request Parameters | Parameter | Type | Required | Description | |--------------|--------|---------------------------------------------------------------|------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). | | levelData | Object[]| Yes | Levels[] are used to distinguish depth, where the first value is the quantity and the second value is the takerTokenRate, representing the taker/maker token exchange rate.
Note: We do not require a minimum liquidity. | | >takerTokenAddress| String | Yes | The contract address of the token being sold by the taker and purchased by the maker (e.g., 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2) | | >makerTokenAddress| String | Yes | The contract address of the token being sold by the maker and purchased by the taker (e.g., 0xa892e1fef8b31acc44ce78e7db0a2dc610f92d00) | | >levels | String[]| Yes | Levels are a list of how much quantity is available at what price, quotes must be non-cumulative, level-by-level |
## Request Example ```shell curl --location --request GET 'https://your-api-endpoint.com/OKXDEX/rfq/pricing?chainIndex=501' \ --header 'X-API-KEY: 37c541a1-****-****-****-10fe7a038418' \ ``` ## Response Example ```json { "code": "0", "msg": "", "data": { "chainIndex": "1", "levelData": [ { "takerTokenAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // WETH "makerTokenAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7", // USDT "levels": [ [ "0.2635658632112683", // Maker is willing to buy 0.2635658632112683 ETH "4257.065884207436" // takerTokenRate 1 WETH = 4257.065884207436 USDT ] ] }, { "takerTokenAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7", // USDT "makerTokenAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // WETH "levels": [ [ "1277.8023761262712", // Maker is willing to buy 1277.8023761262712 USDT "0.00023477808901049835"//takerTokenRate 1 USDT = 0.00023477808901049835 WETH ], [ "961.3366422965815", "0.00023474489972208067" ] ] } ] } } ```
- [Firm order](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-api-market-maker-firm-order.md) {/* api-page */} # Firm order OKX DEX will request relevant data using the parameters below. ## Request Parameters | Parameter | Type | Required | Description| |--------------|--------|---------------------------------------------------------------|-----| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). | | takerAsset | Array | Yes | Address of takerToken | | makerAsset | String | Yes | Address of makerToken | | takerAmount | String | Yes | Trade quantity of takerToken | | takerAddress | String | Yes | Address of Taker | | rfqId | Long | Yes | A unique identifier assigned to each quote request. | | expiryDuration | Integer | Yes | This parameter sets the validity duration of a quote or request, indicating the time interval from when the quote/request is generated until it expires. | | callData | String | No | The transaction needs to be signed, this requirement applies to Solana only. |
## Response Parameters | Parameter | Type | Required | Description | |--------------|--------|---------------------------------------------------------------|------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). | | makerAmount | Array | Yes | Trade quantity of makerToken | | makerAddress | String | Yes | Address of order signer | | takerAsset | String | Yes | Address of takerToken | | makerAsset | String | Yes | Address of makerToken | | takerAmount | String | Yes | Trade quantity of takerToken | | takerAddress | String | Yes | Address of Taker | | rfqId | String | Yes | A unique identifier assigned to each quote request. | | expiry | Timestamp | Yes | Expiration time. | | signature | String | Yes | The signature of market maker. | | callData | String | No | The signed transaction and the modified calldata.(required for solana) | | signatureScheme | String | No | EIP-712 or EIP-1271(required for EVM) | | usePermit2 | Boolean | No | Use Permit2 to approve, default is false.(required for EVM) |
## Request Example ```json `firm-order` Solana Example { "chainIndex" : "501", "takerAsset": "11111111111111111111111111111111", // Address of takerToken "makerAsset": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", // Address of makerToken "takerAmount": "6000000000000000", // Quantity of takerToken "takerAddress": "taker address", // Address of order taker "rfqId": "12345678", // uniqueId for the rfq "expiryDuration": 60, "callData": "d1KVBN6xw6sF1YzS5gDGGEp64jSmoB54umQyZeuHU8Mgctmok5vVvekq8DNUoPHDnb7Ydr42CyiQHAgkr8TnGFjk1AVr7yYF5MadmGPuLLRrn7KgMd7VHXccReChopuK8iJ2Co7CNmKULx75VtcZj7UMN2qeSQAPeMeAS2deNny3qiKnHXDYKFZRDyeZWnQrRPeSiithSiqc2fLb3XsN7S82Ho2M2D2Y5VbZnGZrJ7XVuPmTQrA5VXwGZpEYZg9QsqR6biy811YFHhvHTMTzMVbUhG988xyJSdxmVRkXBwbvLM2WCfr1Dppewg9pej9sqTG3zKx4NYSW27H9n5fV6SjgLReZCsX1RosN6Wk9ZpkUUHoWDfiGBCQWNdfaMD1mk8eFYXcgReCG2JDwQw8VRoVMhpUAf31Xyt7Ec2e9ug2X6XpXCctk4Adh9UMEJRqs7agEEzZwx638Cm99WfnDh7scDLBMYp4UaAkSmDVvnT8UpQoehrSxJefdzawFXhxVifkfPxi1VNKc4uinyHc4UWdhn9FFp37qJq2WsiACbRwEBmV8SQrZ77AL7MwcUPD8RqyR57Pxezk8KpH9PgEj7g6yRQjUzowDmesP5U9uVPSywUtgKDbtWVJXq4SgQUuSXY5YGWwxkQ6HYkPe6ga7ntziGfBQFbb7t9z1MDw6KAZcP7YPwGC9biEjgQxMyEaCBWzXDHWSvpYdrcLX4HRRLp8cWA3QBPcTZ6JFLFnRHLtn9fBwhz9G8v2544VzdNoVCj3pMsS9UZapDSnzbTFi2xKcyNQtDnRnnumUdz7pS4XtGz8V4tnfNozWCRC4TRg77vcCk81r8dPGrXKZQa2vusp7EvjtUyinmEuEhJvbwuvmRc1YsbrqibrRD2r6XEWFKLFE5adWz8gSZWwTj6ZWZDZtBw2QqVd1cSkuR1tEEaDs91nNGcgRitXeTJTuRNpGJWhcgNotEmK3NWTSmJZCiL7qaZeoatnYcVd6X3axxnyr2Dz4SwQePnVi5wVwJPtNiaWZ1V9kqpNwjTfuuk1aRyaWT55LGL71wSBWBgVuNxUYu9jTQ6cpyXxQiHYMHdhEcpdxYPzwe4gEx2EbPVSgL5mazUJHJoTwwhj9CFSsaXeiMaH2QsBw1TZVvLJboMw7Sa7eeAF6S9Q4CYyh4YSyjL6oLMmutz1a3X4xw3HkJHeEn3M2syP7GVP1xHreS9sso92MWHo3v7PyNgUwm3HyzgMNjXd" } `firm-order` EVM Example { "chainIndex" : "1", "takerAsset": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // Address of takerToken "makerAsset": "0xdac17f958d2ee523a2206206994597c13d831ec7", // Address of makerToken "takerAmount": "6000000000000000", // Quantity of takerToken "takerAddress": "taker address", // Address of order taker "rfqId": "12345678", // uniqueId for the rfq "expiryDuration": 60 } ``` ## Response Example ```json `firm-order` Solana Example { "code": "0", "msg": "", "data": { "chainIndex" : "501", "rfqId" : "12345678", "expiry": 172120120102, "makerAsset": "11111111111111111111111111111111", //Address of makerToken "takerAsset": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", //Address of takerToken "makerAddress": "DmTcmrZ7Dz8asHuuvk2G419JMzqdx58brUBidAegaevp", //Address of order signer "takerAddress": "3owrzVrYU5bpWH6LpTRiG5BQ8F4szDtFXavrBWXRohgW", //Address of trading user "makerAmount": 100000000, //Trade quantity of makerToken. TakerAmount * takerTokenRate "takerAmount": "6000000000000000", //Trade quantity of takerToken "signature": "c64bf62b7619edda019fe491da256b9fbe892fbfeac91f9d1fce168478ad53053dde038584f063fe21e267fcb4e758bcf420036cd2838fe5cbd993ec6d3dde561b", "callData": "d1KVBN6xw6sF1YzS5gDGGEp64jSmoB54umQyZeuHU8Mgctmok5vVvekq8DNUoPHDnb7Ydr42CyiQHAgkr8TnGFjk1AVr7yYF5MadmGPuLLRrn7KgMd7VHXccReChopuK8iJ2Co7CNmKULx75VtcZj7UMN2qeSQAPeMeAS2deNny3qiKnHXDYKFZRDyeZWnQrRPeSiithSiqc2fLb3XsN7S82Ho2M2D2Y5VbZnGZrJ7XVuPmTQrA5VXwGZpEYZg9QsqR6biy811YFHhvHTMTzMVbUhG988xyJSdxmVRkXBwbvLM2WCfr1Dppewg9pej9sqTG3zKx4NYSW27H9n5fV6SjgLReZCsX1RosN6Wk9ZpkUUHoWDfiGBCQWNdfaMD1mk8eFYXcgReCG2JDwQw8VRoVMhpUAf31Xyt7Ec2e9ug2X6XpXCctk4Adh9UMEJRqs7agEEzZwx638Cm99WfnDh7scDLBMYp4UaAkSmDVvnT8UpQoehrSxJefdzawFXhxVifkfPxi1VNKc4uinyHc4UWdhn9FFp37qJq2WsiACbRwEBmV8SQrZ77AL7MwcUPD8RqyR57Pxezk8KpH9PgEj7g6yRQjUzowDmesP5U9uVPSywUtgKDbtWVJXq4SgQUuSXY5YGWwxkQ6HYkPe6ga7ntziGfBQFbb7t9z1MDw6KAZcP7YPwGC9biEjgQxMyEaCBWzXDHWSvpYdrcLX4HRRLp8cWA3QBPcTZ6JFLFnRHLtn9fBwhz9G8v2544VzdNoVCj3pMsS9UZapDSnzbTFi2xKcyNQtDnRnnumUdz7pS4XtGz8V4tnfNozWCRC4TRg77vcCk81r8dPGrXKZQa2vusp7EvjtUyinmEuEhJvbwuvmRc1YsbrqibrRD2r6XEWFKLFE5adWz8gSZWwTj6ZWZDZtBw2QqVd1cSkuR1tEEaDs91nNGcgRitXeTJTuRNpGJWhcgNotEmK3NWTSmJZCiL7qaZeoatnYcVd6X3axxnyr2Dz4SwQePnVi5wVwJPtNiaWZ1V9kqpNwjTfuuk1aRyaWT55LGL71wSBWBgVuNxUYu9jTQ6cpyXxQiHYMHdhEcpdxYPzwe4gEx2EbPVSgL5mazUJHJoTwwhj9CFSsaXeiMaH2QsBw1TZVvLJboMw7Sa7eeAF6S9Q4CYyh4YSyjL6oLMmutz1a3X4xw3HkJHeEn3M2syP7GVP1xHreS9sso92MWHo3v7PyNgUwm3HyzgMNjXd" } } `firm-order` EVM Example { "chainIndex" : "1", "takerAsset": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // Address of takerToken "makerAsset": "0xdac17f958d2ee523a2206206994597c13d831ec7", // Address of makerToken "takerAmount": "6000000000000000", // Quantity of takerToken "takerAddress": "taker address", // Address of order taker "rfqId": "12345678", // uniqueId for the rfq "expiryDuration": 60 } ```
- [EVM Signature](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-api-market-maker-sdk.md) # EVM Signature ## EVM Signature SDK ```javascript // signOrderRFQ.js import { Wallet, ethers } from "ethers"; /** * Sign an OrderRFQ-typed struct and return the signature string * * @param {string} privateKey - Signer's private key (EOA) * @param {string} verifyingContract - Address of the contract used for signature verification * @param {number} chainId - Current chain ID * @param {object} order - Order object containing fields like rfqId, expiration, etc. * @returns {Promise} - EIP-712 signature string */ export async function signOrderRFQ({ privateKey, verifyingContract, chainId, order }) { const wallet = new Wallet(privateKey); const domain = { name: "OKX Lab PMM Protocol", version: "1.0", chainId, verifyingContract, }; const types = { OrderRFQ: [ { name: "rfqId", type: "uint256" }, { name: "expiry", type: "uint256" }, { name: "makerAsset", type: "address" }, { name: "takerAsset", type: "address" }, { name: "makerAddress", type: "address" }, { name: "makerAmount", type: "uint256" }, { name: "takerAmount", type: "uint256" }, { name: "usePermit2", type: "bool" }, ], }; const signature = await wallet.signTypedData(domain, types, order); return signature; } ``` ## EVM Signing Example ```javascript import { signOrderRFQ } from "./signOrderRFQ.js"; import { ethers } from "ethers"; const currentTime = Math.floor(Date.now() / 1000); const expiry = currentTime + 90; const sig = await signOrderRFQ({ // foundry local public test account privateKey: "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", // PMM settlement contract (`pool` as adapter's perspective) verifyingContract: "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", chainId: 31337, order: { rfqId: 1, expiry: expiry, makerAsset: "0x111111111117dC0aa78b770fA6A738034120C302", takerAsset: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", makerAddress: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", // 100000000000000000000 makerAmount: ethers.parseUnits("100", 18), // 500000000000000000 takerAmount: ethers.parseUnits("0.5", 18), usePermit2: false, }, }); console.log("Signature:", sig); ``` - [Smart Contract](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-smart-contract.md) # Smart Contract The contract addresses of OKX DEX router and ABI ## Contract Address The contract addresses of the DEX router and token approval may be subject to replacement due to contract upgrades. To ensure uninterrupted use of the API, we recommend using the contract addresses returned by the response parameters: `/approve-transaction` API and `/swap` API for approvals and transactions. ### DEX Router The contract addresses of OKX DEX router.Ton and Solana chains do not require authorization. | Chain | DEX router address | |----------------|----------------------------------------------| | Ethereum | 0x2E1Dee213BA8d7af0934C49a23187BabEACa8764 | | Solana | 6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma | | SUI | 0xafff5502633f670a64328813b66fa08bc7a642ac9c81ed6c4b7ec5448e3b23ad
extended: 0xab71c2c2c37f973e28b2d28847046615bf47acc85ffc3ba2eb3d9a6442b18422(Due to the SUI package ID size limitation, an extended contract was deployed to support liquidity for Momentum, Scallop, Haedal, Alphafi, and others.)| | Sonic | 0x8feB9E84b7E9DC86adc6cD6Eb554C5B4355c8405 | | Tron | TVbYrdupAymaF5ibPo2WREho7g23rQcqC7 | | Ton | EQBjfOGw4Iq6FYZplhwZ5rRNb7Htac7WJh8g_eQcGTswxVqP | | zkSync Era | 0x010BC6B1014E5ed8284ab0667b116AAb99588159 | | Optimism | 0x86F752f1F662f39BFbcBeF95EE56B6C20d178969 | | Polygon | 0xF5402CCC5fC3181B45D7571512999D3Eea0257B6 | | BNB Chain | 0x6015126d7D23648C2e4466693b8DeaB005ffaba8 | | OKC | 0x69C236E021F5775B0D0328ded5EaC708E3B869DF | | Avalanche C | 0x79f7C6C6dc16Ed3154E85A8ef9c1Ef31CEFaEB19 | | Fantom | 0x5e2F47bD7D4B357fCfd0Bb224Eb665773B1B9801 | | Arbitrum | 0x5e2F47bD7D4B357fCfd0Bb224Eb665773B1B9801 | | Linea | 0x6f7c20464258c732577c87a9B467619e03e5C158 | | Conflux eSpace | 0xF5402CCC5fC3181B45D7571512999D3Eea0257B6 | | Base | 0x5e2F47bD7D4B357fCfd0Bb224Eb665773B1B9801 | | Mantle | 0x69C236E021F5775B0D0328ded5EaC708E3B869DF | | Scroll | 0x86F752f1F662f39BFbcBeF95EE56B6C20d178969 | | Manta | 0xd30D8CA2E7715eE6804a287eB86FAfC0839b1380 | | Metis | 0xcF76984119C7f6ae56fAfE680d39C08278b7eCF4 | | Blast | 0x69C236E021F5775B0D0328ded5EaC708E3B869DF | | Zeta | 0xd30D8CA2E7715eE6804a287eB86FAfC0839b1380 | | Polygon zkEvm | 0xF5402CCC5fC3181B45D7571512999D3Eea0257B6 | | Merlin | 0x69C236E021F5775B0D0328ded5EaC708E3B869DF | | X Layer | 0x69C236E021F5775B0D0328ded5EaC708E3B869DF | | UniChain | 0x411d2C093e4c2e69Bf0D8E94be1bF13DaDD879c6 | | Cronos | 0xC589a4eD6A9fc3354d7eeF88bA87b51AFC272783 | DEX Router Addresses for OKX DEX used in signing exactOut transactions | Chain Name | DEX Router Contract Address | |----------------|--------------------------------------------------| | Ethereum | 0xa875Fb2204cE71679BE054d97f7fAFFeb6536D67 | | Base | 0x77449Ff075C0A385796Da0762BCB46fd5cc884c6 | | BNB Chain | 0x5cb43Bae4f36E2f9f858232B4Dce0dbE27bb85e3 | | Arbitrum | 0x9736d9a45115E33411390EbD54e5A5C3A6E25aA6 | ### Token Approval A list of smart contracts for ERC-20 token approval | Chain | Approval contract address | |----------------|--------------------------------------------| | Ethereum | 0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f | | Tron | THRAE2VhGNAcvPKtT96AqyXtSQwhiU1XL8 | | Sonic | 0xcc96b656b6dff0B5318d53271b82B7E7183b95D2 | | zkSync Era | 0xc67879F4065d3B9fe1C09EE990B891Aa8E3a4c2f | | Optimism | 0x68D6B739D2020067D1e2F713b999dA97E4d54812 | | Polygon | 0x3B86917369B83a6892f553609F3c2F439C184e31 | | BNB Chain | 0x2c34A2Fb1d0b4f55de51E1d0bDEfaDDce6b7cDD6 | | OKC | 0x70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58 | | Avalanche C | 0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f | | Fantom | 0x70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58 | | Arbitrum | 0x70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58 | | Linea | 0x57df6092665eb6058DE53939612413ff4B09114E | | Conflux eSpace | 0x68D6B739D2020067D1e2F713b999dA97E4d54812 | | Base | 0x57df6092665eb6058DE53939612413ff4B09114E | | Mantle | 0x57df6092665eb6058DE53939612413ff4B09114E | | Scroll | 0x57df6092665eb6058DE53939612413ff4B09114E | | Manta | 0x57df6092665eb6058DE53939612413ff4B09114E | | Metis | 0x57df6092665eb6058DE53939612413ff4B09114E | | Blast | 0x5fD2Dc91FF1dE7FF4AEB1CACeF8E9911bAAECa68 | | Zeta | 0x03B5ACdA01207824cc7Bc21783Ee5aa2B8d1D2fE | | Polygon zkEvm | 0x57df6092665eb6058DE53939612413ff4B09114E | | Merlin | 0x8b773D83bc66Be128c60e07E17C8901f7a64F000 | | X Layer | 0x8b773D83bc66Be128c60e07E17C8901f7a64F000 | | UniChain | 0x2e28281Cf3D58f475cebE27bec4B8a23dFC7782c | | Cronos | 0x70cbb871e8f30fc8ce23609e9e0ea87b6b222f58 | ## Contract Application Binary Interface (ABI) Please refer to: https://github.com/okx/OKX-DEX-Aggregator-ABI - [Error Codes](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-error-code.md) # Error Codes ## Swap API | Code | HTTP status | Message | | ----- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 0 | 200 | Succeeded | | 50011 | 429 | Rate limit reached. Please refer to API documentation and throttle requests accordingly | | 50014 | 400 | Parameter param0 cannot be empty | | 50026 | 500 | System error. Try again later | | 50103 | 401 | Request header "OK-ACCESS-KEY" cannot be empty | | 50104 | 401 | Request header "OK-ACCESS-PASSPHRASE" cannot be empty | | 50105 | 401 | Request header "OK-ACCESS-PASSPHRASE" incorrect | | 50106 | 401 | Request header "OK-ACCESS-SIGN" cannot be empty | | 50107 | 401 | Request header "OK-ACCESS-TIMESTAMP" cannot be empty | | 50111 | 401 | Invalid OK-ACCESS-KEY | | 50112 | 401 | Invalid OK-ACCESS-TIMESTAMP | | 50113 | 401 | Invalid signature | | 51000 | 400 | Parameter param0 error | | 80000 | 200 | Repeated request | | 80001 | 200 | CallData exceeds the maximum limit. Try again in 5 minutes. | | 80002 | 200 | Requested token Object count has reached the limit. | | 80003 | 200 | Requested native token Object count has reached the limit. | | 80004 | 200 | Timeout when querying SUI Object. | | 80005 | 200 | Not enough Sui objects under the address for swapping | | 82000 | 200 | Insufficient liquidity | | 82001 | 500 | The commission service is not available during the upgrade | | 82003 | 200 | toTokenReferrerWalletAddress address is not valid | | 82102 | 200 | Less than the minimum quantity limit,the minimum amount is 0 | | 82103 | 200 | Exceeds than the maximum quantity limit,the maximum amount is 0 | | 82104 | 200 | This token is not supported | | 82105 | 200 | This chain is not supported | | 82112 | 200 | The value difference from this transaction’s quote route is higher than num, which may cause asset loss,The default value is 90%. It can be adjusted using the string priceImpactProtectionPercentage. | | 82116 | 200 | callData exceeds the maximum limit. Try again in 5 minutes. | | 82130 | 200 | The chain does not require authorized transactions and can be exchanged directly. | | 82004 | 200 | Commission split for swaps via Four.meme is not supported | | 82005 | 200 | Commission split for swaps via aspecta is not supported | ## RFQ API Market makers should return appropriate HTTP status codes along with error messages. | Code | HTTP status | Message | | ----- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | 0 | 200 | The request was successful, and the endpoint will return a quote. | | 404 | 404 | The endpoint will not return a quote for this request (e.g. the pair or the size are not supported). | | 400 | 400 | The request sent to the endpoint is malformed (e.g. missing an expected parameter). | | 401 | 401 | Authorization failed. For example the X-API-KEY is missing or incorrect. | | 50x | 50x | The endpoint is offline or unable to respond. If the status persist, the endpoint will be temporarily suspended and will not receive requests. | | 82000 | 200 | Liquidity too low for this quote | | 82001 | 200 | The quote does not exceed the minimum size of the maker | | 82002 | 200 | The maker is unavailable to handle the quote | | 82003 | 200 | The maker rejects to respond to this user | - [FAQ](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-aggregation-faq.md) # FAQ ## What Is the Native Token Address for Each Chain? We have defined the native tokens for each chain. Please refer to the table below for details: | Chain Name | Native Token Address | |------------|----------------------------------------------------| | EVM | 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee | | Solana | 11111111111111111111111111111111 | | Sui | 0x2::sui::SUI | | Tron | T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb | | Ton | EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c | ## What Is “Transfer amount exceeds allowance”? This error message indicates that the amount you're trying to transfer exceeds the approved limit. Set your approval limit higher than the amount you wish to transfer to resolve this error. ## What Is “min return not reached”? This means that the expected minimum return was not met during trade execution. This usually happens when there is a significant slippage or high market volatility. If the expected minimum return is not met, the trade will not be executed.
You may increase slippage to raise the chances of the order going through as a higher slippage allows a greater price fluctuation at execution. However, please note that too high a slippage may lead to results that are worse than expected. ## Which Tokens Require an Approval Transaction? 1. EVM + Tron: Typically, non-native tokens (such as ERC-20/TRC-20 tokens on Ethereum or Tron) require an approval transaction. This ensures that you are allowing the smart contract to transfer these tokens from your account. 2. Other heterogeneous chains: On some other chains, such as Solana, approval transactions are not required for tokens. - [Introduction](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-onchain-gateway-api-introduction.md) # Introduction The Onchain gateway API offers on-chain simulation and on-chain transaction broadcasting services, supporting both self-developed RPC nodes and external premium RPC nodes. By leveraging OKX Web3's advanced node management infrastructure and expertise, it enables intelligent transaction broadcasting, significantly reducing failure rates and accelerating confirmation speeds. Developers can seamlessly integrate the Onchain gateway API with the Swap/Cross chain API to create a comprehensive DEX experience to their users, eliminating the need for additional external resources. **Key capabilities** 1. **High-availability hybrid node architecture** - Self-developed multi-chain node clusters for robust performance. - Intelligent integration of third-party premium node resources to build a redundant and resilient network. - Dynamic load balancing with real-time node health monitoring and sub-second failover for uninterrupted services. 2. **Intelligent multi-broadcasting engine** - Breakthrough capability to broadcast transactions across multiple node networks simultaneously. - Enhanced on-chain success rates through advanced distributed propagation algorithms. - Priority block packaging acceleration for major chains like ETH, BNB Chain, and Solana and more. - [Onchain gateway API Reference](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-onchain-gateway-reference.md) # Onchain gateway API Reference - [Get Supported Chains](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-onchain-gateway-api-chains.md) {/* api-page */} # Get Supported Chains Retrieve information on chains supported by Onchain gateway API ### Request URL GET `https://web3.okx.com/api/v5/dex/pre-transaction/supported/chain` ## Request Parameters None ## Response Parameters | Parameter | Type | Description | |-----------|--------|-------------------| | name | String | Chain name | | logoUrl | String | Chain logo URL | | shortName | String | Chain short name | | chainIndex| String | Chain unique identifier | ## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/pre-transaction/supported/chain' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "name": "Ethereum", "logoUrl": "http://www.eth.org/eth.png", "shortName": "ETH", "chainIndex": "1" } ], "msg": "" } ``` - [Get Gas Price](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-onchain-gateway-api-gas-price.md) {/* api-page */} # Get Gas Price Dynamically obtain estimated gas prices for various chains. ### Request URL GET `https://web3.okx.com/api/v5/dex/pre-transaction/gas-price` ## Request Parameters | Parameter | Type | Required | Description | |------------|--------|----------|-----------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). |
## Response Parameters ### EVM & Tron | Parameter | Type | Description | |------------------|---------|-----------------------------------| | normal | String | Medium gas price. For EVM, it is in wei. For Tron,it is in SUN | | min | String | Low gas price. For EVM, it is in wei. For Tron,it is in SUN | | max | String | High gas price. For EVM, it is in wei. For Tron,it is in SUN | | supporteip1559 | Boolean | Whether supports 1559 | | eip1559Protocol | Object | 1559 protocol | ### eip1559 Protocol | Parameter | Type | Description | |---------------------|--------|--------------------------------------| | eip1559Protocol | Object | Structure of 1559 protocol | | >suggestBaseFee | String | Suggested base fee = base fee * 1.25, in wei | | >baseFee | String | Base fee, in wei | | >proposePriorityFee | String | Medium priority fee, in wei | | >safePriorityFee | String | Low priority fee, in wei | | >fastPriorityFee | String | High priority fee, in wei | ### Solana | Parameter | Type | Description | |------------------|---------|-------------------| | priorityFee | String | Priority fee per compute unit. Only applicable to Solana | | >proposePriorityFee | String | Medium priority fee in microlamports.( it is also called Medium compute unit price ) 80th percentile| | >safePriorityFee | String | Low priority fee in microlamports.( it is also called Low compute unit price ) 60th percentile| | >fastPriorityFee | String | High priority fee in microlamports.( it is also called High compute unit price ) 95th percentile| | >extremePriorityFee | String | Extreme High priority fee in microlamports.( it is also called Extreme High compute unit price ) 99th percentile |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/pre-transaction/gas-price?chainIndex=1' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "normal" : "21289500000", // Medium gas price "min" : "15670000000", // Low gas price "max" : "29149000000", // High gas price "supportEip1559" : true, // Whether supports 1559 "eip1599Protocol": { "suggestBaseFee" : "15170000000", // Suggested base fee "baseFee" : "15170000000", // Base fee "proposePriorityFee" : "810000000", // Medium priority fee "safePriorityFee" : "500000000", // Low priority fee "fastPriorityFee" : "3360000000" // High priority fee }, "priorityFee":{} } ], "msg": "" } ```
- [Get Gas Limit](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-onchain-gateway-api-gas-limit.md) {/* api-page */} # Get Gas Limit Retrieve estimated Gas Limit consumption through pre-execution of transaction information. ### Request URL POST `https://web3.okx.com/api/v5/dex/pre-transaction/gas-limit` ## Request Parameters | Parameter | Type | Required | Description | |------------|--------|----------|-----------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). | | fromAddress| String | Yes | From address. For `transfer`,`Swap`, `Approve`, it is a wallet address | | toAddress | String | Yes | To address.
For `transfer`, it can be a token address or wallet address.
For `Swap`, it should be OKX DEX router address.
For `Approve`, it is a token address | | txAmount | String | No | Transaction amount. Default value: `0`.
1. For **Native token transactions** ( where the `fromToken` is native token. e.g., Ethereum), the txAmount can be set to the native token quantity, or retrieved from [/swap](./dex-swap) api(e.g., `txAmount = swapResponse.tx.value`).
2.For **non-native token transactions**, set `txAmount` to `0`.
The valle must use base unit of the native token, e.g., wei for ETH | | extJson | Object | No | Additional parameters for calldata and other information | extJson | Parameter | Type | Required | Description | |-----------|--------|----------|-------------| | inputData | String | No | Calldata |
## Response Parameters | Parameter | Type | Description | |-----------|--------|-------------------| | gasLimit | String | Estimated gas limit |
## Request Example ``` shell curl --location --request POST 'https://web3.okx.com/api/v5/dex/pre-transaction/gas-limit' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '{ "fromAddress": "0x383c8208b4711256753b70729ba0cf0cda55efad", "toAddress": "0x4ad041bbc6fa102394773c6d8f6d634320773af4", "txAmount": "31600000000000000", "chainIndex": "1", "extJson": { "inputData":"041bbc6fa102394773c6d8f6d634320773af4" } }' ``` ## Response Example ```json { "code": "0", "data": [ { "gasLimit": "652683" } ], "msg": "" } ```
- [Simulate Transactions](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-onchain-gateway-api-simulate-transaction.md) {/* api-page */} # Simulate Transactions Simulate a blockchain transaction before executing it to see the expected outcomes and potential risks.
Transaction simulate API is available to our whitelisted customers only. If you are interested, please contact us dexapi@okx.com. ### Request URL GET `https://web3.okx.com/api/v5/dex/pre-transaction/simulate` ## Request Parameters | Parameter | Type | Required | Description | |--------------|--------|----------|---------------------------------------------------------------------------------------| | fromAddress | String | Yes | Source address. For `Swap`, `Approve`, it is a wallet address | | toAddress | String | Yes | Destination address.
For `Swap`, it should be OKX DEX router address.
For `Approve`, it is a token address | | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum
See [Supported Chains](./dex-supported-chain.mdx) for more.
It supports EVM、SOL、SUI, more chains will be supported soon. | | txAmount | String | No | Transaction amount. Default value: `0`.
1. For **Native token transactions** ( where the `fromToken` is native token. e.g., Ethereum), the txAmount can be set to the native token quantity, or retrieved from [/swap](./dex-swap) api(e.g., `txAmount = swapResponse.tx.value`).
2.For **non-native token transactions**, set `txAmount` to `0`.
The valle must use base unit of the native token, e.g., wei for ETH | | extJson | Object | Yes | Extended information object containing the following fields: | | > inputData | String | Yes | Call data for the transaction. The encoding rule require `base58`. | | priorityFee | String | No | Priority fee. Only applicable to Solana. | | gasPrice | String | No | Gas price for the transaction. |
## Response Parameters | Parameter | Type | Description | |--------------|--------|--------------------------------------------------------------------| | intention | String | Transaction purpose. Valid values: "Swap", "Token Approval" | | assetChange | Array | Details of asset changes resulting from the transaction | | > assetType | String | Asset type. Valid values: "NATIVE", "ERC20", "SPLTOKEN","SUITOKEN"| | > name | String | Asset name (e.g., "Ethereum") | | > symbol | String | Asset symbol (e.g., "ETH") | | > decimals | Number | Asset decimal precision | | > address | String | Asset contract address | | > imageUrl | String | URL to the asset's image | | > rawValue | String | Asset amount. Positive values indicate receiving assets, negative values indicate sending assets. | | gasUsed | String | Gas consumed by the transaction | | failReason | String | Human-friendly explanation if the transaction would fail | | risks | Array | Potential risks identified in the transaction | | > address | String | Address associated with the risk | | > addressType| String | Type of address. Valid values: "contract", "eoa" |
## Request Example ```shell curl --location --request POST 'https://web3.okx.com/api/v5/dex/pre-transaction/simulate' \ --header 'OK-ACCESS-KEY: your-access-key' \ --header 'OK-ACCESS-SIGN: your-access-sign' \ --header 'OK-ACCESS-PASSPHRASE: your-passphrase' \ --header 'OK-ACCESS-TIMESTAMP: 2025-05-19T10:00:00.000Z' \ --header 'Content-Type: application/json' \ --data-raw '{ "fromAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "toAddress": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", "chainIndex": "1", "txAmount": "0", "extJson": { "inputData": "0x38ed1739000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000000000000000000000000000000000000042ab52c000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000742d35cc6634c0532925a3b844bc454e4438f44e0000000000000000000000000000000000000000000000000000000064794b4b0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" }, "gasPrice": "12000000000" }' ``` ## Response Example ```json { "code": "0", "data": [ { "intention": "SWAP", "assetChange": [ { "assetType": "NATIVE", "name": "Ether", "symbol": "ETH", "decimals": 18, "address": "", "imageUrl": "", "rawValue": "-1000000000000000" }, { "assetType": "ERC20", "name": "USD Coin", "symbol": "USDC", "decimals": 6, "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "imageUrl": "", "rawValue": "1000000000000000" } ], "gasUsed": "180000", "failReason": "", "risks": [] } ], "msg": "success" } ```
- [Broadcast Transactions](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-onchain-gateway-api-broadcast-transaction.md) {/* api-page */} # Broadcast Transactions Broadcast transactions to the specified blockchain.
Transaction Broadcast API is available to our whitelisted customers only. If you are interested, please contact us dexapi@okx.com. Your end-user's transaction can only be covered by the MEV protection feature if you actually utilise OKX Build's API services for that particular transaction. MEV protection is currently an experimental feature provided by third-parties and OKX Build does not guarantee the effectiveness and quality of such MEV protection. ### Request URL POST `https://web3.okx.com/api/v5/dex/pre-transaction/broadcast-transaction` ## Request Parameters | Parameter | Type | Required | Description | |------------ |-------- |----------|------------------------------------------------------------------------| | signedTx | String | Yes | The transaction string after being signed | | chainIndex | String | Yes | Unique identifier for the chain.
e.g., ETH=1.
See more [here](./dex-supported-chain). | | address | String | Yes | Address. | | extraData | String | No | Additional parameters for calldata and other information | | > enableMevProtection | Boolean | No | Enable MEV protection. Not enabled by default. Valid values: `false`:not enabled, `true`:enabled
It supports only `ETH`、`BSC`、`SOL`、`BASE`, more chains will be supported soon. | | > jitoSignedTx | String | No | The transaction string after being signed that will send to Jito. The encoding rule require `base58`, applicable to `SOL`. For SOL, `signedTx` and `jitoSignedTx` must be passed at the same time |
## Response Parameters | Parameter | Type | Description | |-----------|--------|--------------------| | orderId | String | Unique transaction identifier | | txHash | String | Transaction Hash.
It supports only `ETH`、`BSC`、`SOL`、`BASE`, more chains will be supported soon. |
## Request Example ``` shell curl --location --request POST 'https://web3.okx.com/api/v5/dex/pre-transaction/broadcast-transaction' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '{ "signedTx":"0x08b47112567534ad041bbc6fa102394773c6d8f6d634320773af4da55efa", "address": "0x383c8208b4711256753b70729ba0cf0cda55efad", "chainIndex": "1", "extraData":"{\"enableMevProtection\":true,\"jitoSignedTx\":\"0x123456\"}" }' ``` ## Response Example ```json { "code": "0", "data": [ { "orderId": "0x383c8208b4711256753b70729ba0cf0cda55efad", "txHash": "0xd394f356a16b618ed839c66c935c9cccc5dde0af832ff9b468677eea38759db5" } ], "msg": "" } ```
- [Get Transaction Orders](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-onchain-gateway-api-orders.md) {/* api-page */} # Get Transaction Orders Get the list of orders sent from transaction broadcasting API. This supports querying transactions sorted in descending order by time. ### Request URL GET `https://web3.okx.com/api/v5/dex/post-transaction/orders` ## Request Parameters | Parameter | Type | Required | Description | |------------ |-------- |----------|----------------------------------------------------| | address | String | Yes | Address | | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). | | txStatus | String | No | Transaction status:
`1`: Pending
`2`: Success
`3`: Failed | | orderId | String | No | Unique identifier for the transaction order | | cursor | String | No | Cursor | | limit | String | No | Number of records returned, default is the most recent 20, maximum is 100 |
## Response Parameters | Parameter | Type | Description | |------------ |-------- |-----------------------------------------------------| | chainIndex | String | Unique identifier for the chain | | address | String | Address | | orderId | String | Order ID | | txStatus | String | Transaction status:
`1`: Pending
`2`: Success
`3`: Failed | | failReason | String | The reason for failed transaction | | txHash | String | Transaction hash |
## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/post-transaction/orders?address=0x238193be9e80e68eace3588b45d8cf4a7eae0fa3&chainIndex=1' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ``` json { "code": "0", "msg": "success", "data": [ { "cursor": "1", "orders":[ { "chainIndex": "1", "orderId": "016cf21d020be6c2f071dad9bbd8ec5cb9342fa8", "address": "0x238193be9e80e68eace3588b45d8cf4a7eae0fa3", "txHash": "0xb240e65dd9156b4a450be72f6c9fe41be6f72397025bb465b21a96ee9871a589", "failReason": "", "txstatus": "2" }, { "chainIndex": "1", "orderId": "592051a92a744627022955be929ecb5c9e777705", "address": "0x238193be9e80e68eace3588b45d8cf4a7eae0fa3", "txHash": "0xc401ffcd2a2b4b1db42ce68dfde8e63c0a1e9653484efb2873dbf5d0cbeb227a", "txstatus": "1", "failReason": "", } ] } ] } ```
- [Error Codes](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-onchain-gateway-error-code.md) # Error Codes | Code | HTTP status | Message | |-------|-------------|-----------------------------------------------------------------------------------------| | 50001 | 200 | Service temporarily unavailable. Try again later | | 81001 | 200 | Incorrect parameter | | 81108 | 200 | Wallet type does not match the required type | | 81104 | 200 | Chain not support | | 81152 | 200 | Coin not exist | | 81451 | 200 | node return failed | - [Market API](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-market-api-introduction.md) # Market API Our Market API is a suite of high-performance Restful JSON endpoints and real-time websocket channels to provide comprehensive multi-market and onchain data for cryptocurrency tokens, trades, transactions, accounts and more, pulling information from hundreds of decentralized exchanges (DEX) and centralized exchanges (CEX) across different blockchain ecosystems. Developers can utilize the Market API and the Trade API to build complete DEX experience with insightful market and portfolio dashboards, allowing users to monitor token performance across different exchange types in real-time, analyze portfolio changes and identify trading opportunities. - [Market Price API Reference](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-market-price-reference.md) # Market Price API Reference - [Get supported chains](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-market-price-chains.md) {/* api-page */} # Get supported chains Retrieve information on chains supported by Market API. ### Request URL GET `https://web3.okx.com/api/v6/dex/market/supported/chain` ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | No | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). |
## Response Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Unique identifier for the chain | | chainName | String | Chain name (e.g.,`Optimism`) | | chainLogoUrl | String | Chain icon | | chainSymbol | String | Chain symbol (e.g., ETH). |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/supported/chain?chainIndex=1' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code":"0", "data":[ { "chainIndex":"1", "chainName":"Ethereum", "chainSymbol":"ETH" }, ], "msg":"" } ```
- [Get Price](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-market-price.md) {/* api-page */} # Get Price Retrieve the latest price of a token. ### Request URL POST `https://web3.okx.com/api/v6/dex/market/price` ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). | | tokenContractAddress | String | Yes | Token contract address,for EVM please pass all-lowercase addresses (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) |
## Response Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | chainIndex | String| Unique identifier for the chain | | tokenContractAddress | String | Token contract address | | time | String | Timestamp of the price, Unix timestamp format in milliseconds | | price | String | Latest token price |
## Request Example ```shell curl --location --request POST 'https://web3.okx.com/api/v6/dex/market/price' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '[ { "chainIndex": "66", "tokenContractAddress":"0x382bb369d343125bfb2117af9c149795c6c65c50" } ]' ``` ## Response Example ```json { "code":"0", "data":[ { "chainIndex": "1", "tokenContractAddress": "0x382bb369d343125bfb2117af9c149795c6c65c50", "time": "1716892020000", "price": "26.458143090226812" } ], "msg":"" } ```
- [Get Trades](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-market-trades.md) {/* api-page */} # Get Trades Retrieve the recent transactions of a token. ### Request URL GET `https://web3.okx.com/api/v6/dex/market/trades` ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./walletapi-resources-supported-networks). | | tokenContractAddress | String | Yes | Token contract address,for EVM please pass all-lowercase addresses (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | after | String | No | Pagination of data to return records earlier than the requested id. | | limit | String | No | Number of results per request. The maximum is 500 and default is 100. |
## Response Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | id | String | Unique trade id | | chainIndex | String | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](./dex-supported-chain)) | | tokenContractAddress | String | Token contract address | | txHashUrl | String | On-chain txhash of the transactions | | userAddress | String | Authorizer of the transaction | | dexName | String | Name of the dex where the trade occured | | poolLogoUrl | String | Pool logo url | | type | String | trade Type. `buy` `sell` | | changedTokenInfo | String | exchanged info | | > amount | String | token exchanged amount in this trade | | > tokenSymbol | String | Token symbol | | > tokenContractAddress | String | Token contract address | | price | String | Latest token price | | volume | String | USD value of this trade | | time | String | Timestamp of the price, Unix timestamp format in milliseconds | | isFiltered | String | If the trade is filtered for price and k-line calculation.
`0`: not filtered `1`: filtered" |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/trades?chainIndex=501&tokenContractAddress=HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code":"0", "data":[ { "id":"1739439633000!@#120!@#14731892839", "chainIndex": "501", "tokenContractAddress": "HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC", "txHashUrl": "https://solscan.io/tx/zgDzoiVG4XuDgQcoEg9vhpRyfyk5thNUQuTeTCeF289Qec5iraeCrUzPLyiE2UCviox2ebbTcsagGvzYF7M5uqs", "userAddress": "2kCm1RHGJjeCKL4SA3ZJCLyXqUD7nEJ7GMtVaP7c6jQ8", "dexName": "Orca Whirlpools", "poolLogoUrl": "https://static.okx.com/cdn/wallet/logo/dex_orcaswap.png", "type": "sell", "changedTokenInfo": [ { "amount":"100.396595878", "tokenSymbol":"ai16z", "tokenContractAddress": "HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC" }, { "amount":"2.482831", "tokenSymbol":"SOL", "tokenContractAddress": "So11111111111111111111111111111111111111112" } ] "price": "26.458143090226812", "volume": "519.788163", "time": "1739439633000", "isFiltered": "0" } ], "msg":"", } ```
- [Get Candlesticks](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-market-candlesticks.md) {/* api-page */} # Get Candlesticks Retrieve the candlestick charts. This endpoint can retrieve the latest 1,440 data entries. Charts are returned in groups based on the requested bar. ### Request URL GET `https://web3.okx.com/api/v6/dex/market/candles` ## Request Parameters | Parameter | Type | Required | Description | | -------------------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). | | tokenContractAddress | String | Yes | Token contract address,for EVM please pass all-lowercase addresses (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | after | String | No | Pagination of data to return records earlier than the requested ts. | | before | String | No | Pagination of data to return records newer than the requested ts. The latest data will be returned when using before individually | | bar | String | No | Bar size, the default is 1m
e.g. [1s/1m/3m/5m/15m/30m/1H/2H/4H]
Hong Kong time opening price k-line:[6H/12H/1D/1W/1M/3M]
UTC time opening price k-line:[/6Hutc/12Hutc/1Dutc/1Wutc/1Mutc/3Mutc] | | limit | String | No | Number of results per request. The maximum is 299. The default is 100. |
## Response Parameters | Parameter | Type | Description | | --------- | ------ | ---------------------------------------------------------------------------------------------------- | | ts | String | Opening time of the candlestick, Unix timestamp format in milliseconds, e.g. 1597026383085 | | o | String | Open price | | h | String | Highest price | | l | String | Lowest price | | c | String | Close price | | vol | String | Trading volume, with a unit of base currency. | | volUsd | String | Trading volume, with a unit of usd. | | confirm | String | The state of candlesticks.
`0` represents that it is uncompleted, `1` represents that it is completed. | The first candlestick data may be incomplete, and should not be polled repeatedly. The data returned will be arranged in an array like this: [ts,o,h,l,c,vol,volUsd,confirm]. Use the closing price of the last candle as the opening price of the following candle.
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/candles?chainIndex=66&tokenContractAddress=0x382bb369d343125bfb2117af9c149795c6c65c50' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ [ "1597026383085", "3.721", "3.743", "3.677", "3.708", "22698348.04828491", "226348.0482", "0" ], [ "1597026383085", "3.731", "3.799", "3.494", "3.72", "67632347.24399722", "6767.2439", "1" ] ], "msg": "" } ```
- [Get Candlesticks History](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-market-candlesticks-history.md) {/* api-page */} # Get Candlesticks History Retrieve historical candlestick charts. Historical candlestick data does not include unfinished candlesticks ### Request URL GET `https://web3.okx.com/api/v6/dex/market/historical-candles` ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). | | tokenContractAddress | String | Yes | Token contract address ,for EVM please pass all-lowercase addresses(e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | after | String | No | Pagination of data to return records earlier than the requested ts. | | before | String | No | Pagination of data to return records newer than the requested ts. The latest data will be returned when using before individually | | bar | String | No | Bar size, the default is 1m
e.g. [1s/1m/3m/5m/15m/30m/1H/2H/4H]
Hong Kong time opening price k-line:[6H/12H/1D/1W/1M/3M]
UTC time opening price k-line:[/6Hutc/12Hutc/1Dutc/1Wutc/1Mutc/3Mutc] | | limit | String | No | Number of results per request. The maximum is 299. The default is 100. |
## Response Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | ts | String | Opening time of the candlestick, Unix timestamp format in milliseconds, e.g. 1597026383085 | | o | String | Open price | | h | String | Highest price | | l | String | Lowest price | | c | String | Close price | | vol | String | Trading volume, with a unit of base currency. | | volUsd | String | Trading volume, with a unit of usd. | | confirm | String | The state of candlesticks.
`0` represents that it is uncompleted, `1` represents that it is completed. | The first candlestick data may be incomplete, and should not be polled repeatedly. The data returned will be arranged in an array like this: [ts,o,h,l,c,vol,volUsd,confirm]. Use the closing price of the last candle as the opening price of the following candle.
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/historical-candles?chainIndex=66&tokenContractAddress=0x382bb369d343125bfb2117af9c149795c6c65c50' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code":"0", "data":[ [ "1597026383085", "3.721", "3.743", "3.677", "3.708", "22698348.04828491", "226348.0482", "0" ], [ "1597026383085", "3.731", "3.799", "3.494", "3.72", "67632347.24399722", "6767.2439", "1" ] ], "msg":"" } ```
- [Error Codes](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-market-price-error-code.md) # Error Codes | Code | HTTP status | Message | |-------|-------------|-----------------------------------------------------------------------------------------| | 0 | 200 | Succeeded | | 50011 | 429 | Rate limit reached. Please refer to API documentation and throttle requests accordingly | | 50014 | 400 | Parameter \{param0\} cannot be empty | | 50026 | 500 | System error. Try again later | | 50103 | 401 | Request header "OK-ACCESS-KEY" cannot be empty | | 50104 | 401 | Request header "OK-ACCESS-PASSPHRASE" cannot be empty| | 50105 | 401 | Request header "OK-ACCESS-PASSPHRASE" incorrect | | 50106 | 401 | Request header "OK-ACCESS-SIGN" cannot be empty | | 50107 | 401 | Request header "OK-ACCESS-TIMESTAMP" cannot be empty | | 50111 | 401 | Invalid OK-ACCESS-KEY | | 50112 | 401 | Invalid OK-ACCESS-TIMESTAMP | | 50113 | 401 | Invalid signature | | 51000 | 400 | Parameter \{param0\} error | - [Websocket](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-websocket.md) # Websocket Websocket service is available to our whitelisted customers only. If you are interested, please contact us dexapi@okx.com. WebSocket is a new HTML5 protocol that achieves full-duplex data transmission between the client and server, allowing data to be transferred effectively in both directions. A connection between the client and server can be established with just one handshake. The server will then be able to push data to the client according to preset rules. Its advantages include: - The WebSocket request header size for data transmission between client and server is only 2 bytes. - Either the client or server can initiate data transmission. - There's no need to repeatedly create and delete TCP connections, saving resources on bandwidth and server. ## Connect **Connection limit**: 3 requests per second (based on API KEY)
When subscribing to a private channel, use the address of the private service **Request limit** The total number of 'subscribe'/'unsubscribe'/'login' requests per connection is limited to 480 times per hour. If there’s a network problem, the system will automatically disable the connection. The connection will break automatically if the subscription is not established or data has not been pushed for more than 30 seconds. To keep the connection stable: 1. Set a timer of N seconds whenever a response message is received, where N is less than 30. 2. If the timer is triggered, which means that no new message is received within N seconds, send the String 'ping'. 3. Expect a 'pong' as a response. If the response message is not received within N seconds, please raise an error or reconnect. ## Notification WebSocket has introduced a new message type (event = notice). Client will receive the information in the following scenarios: - Websocket disconnect for service upgrade 30 seconds prior to the upgrade of the WebSocket service, the notification message will be sent to users indicating that the connection will soon be disconnected. Users are encouraged to establish a new connection to prevent any disruptions caused by disconnection. Response Example ```json { "event": "notice", "code": "64008", "msg": "The connection will soon be closed for a service upgrade. Please reconnect.", "connId": "a4d3ae55" } ``` - [Login](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-websocket-login.md) {/* api-page */} # Login ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | op | String | Yes | Operation, `login` | | args | Array | Yes | List of subscribed channels | | > apiKey | String | Yes | API Key | | > passphrase | String | Yes | API Key password | | > timestamp | String | Yes | Unix Epoch time, the unit is seconds | | > sign | String | Yes | Signature string | ## Response Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | event | String | Operation.`login` or `error` | | code | String | Error code | | msg | String | Error message | | connId | String | WebSocket connection ID |

**apiKey**: Unique identification for invoking API. Requires users to apply one manually in the [developer portal](https://web3.okx.com/zh-hans/build/dev-portal).
**passphrase**: API Key password
**timestamp**: the Unix Epoch time, the unit is seconds, e.g. 1704876947
**sign**: signature string, the signature algorithm is as follows: First concatenate timestamp, method, requestPath, strings, then use HMAC SHA256 method to encrypt the concatenated string with SecretKey, and then perform Base64 encoding.
**secretKey**: The security key generated when the user applies for API Key, e.g. : 22582BD0CFF14C41EDBF1AB98506286D
**Example of timestamp**: const timestamp = '' + Date.now() / 1,000
**Among sign example**: sign=CryptoJS.enc.Base64.stringify(CryptoJS.HmacSHA256(timestamp +'GET'+'/users/self/verify', secretKey))
**method**: always 'GET'.
**requestPath**: always '/users/self/verify'

The request will expire 30 seconds after the timestamp. If your server time differs from the API server time, we recommend using the REST API to query the API server time and then set the timestamp.
## Request Example ```json { "op": "login", "args": [{ "apiKey": "985d5b66-57ce-40fb-b714-afc0b9787083", "passphrase": "123456", "timestamp": "1538054050", "sign": "7L+zFQ+CEgGu5rzCj4+BdV2/uUHGqddA9pI6ztsRRPs=" }] } ``` ## Response Example Successful Response Example ```json { "event": "login", "code": "0", "msg": "", "connId": "a4d3ae55" } ``` Failure Response Example ```json { "event": "error", "code": "60009", "msg": "Login failed.", "connId": "a4d3ae55" } ```
- [Subscribe](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-websocket-subscribe.md) {/* api-page */} # Subscribe

Users can choose to subscribe to one or more channels, with the total length of all channels not exceeding 64 KB. Price channels and trading channels require authentication before subscription. K-line (candlestick) channels do not require authentication. Below is an example of request parameters. Each channel has different parameter requirements, so please subscribe according to the specific requirements of each channel.

## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | op | String | Yes | Operation, `subscribe` | | args | Array | Yes | List of subscribed channels | | > channel | String | Yes | Channel name | | > chainIndex | String | Yes | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](./dex-supported-chain)) | | > timestamp | String | Yes | Unix Epoch time, the unit is seconds | | > tokenContractAddress | String | Yes | Token contract address,for EVM please pass all-lowercase addresses (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | ## Response Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | event | String | Operation.`subscribe` or `error` | | arg | String | Subscribed channel | | > channel | String | Channel name | | > chainIndex | String | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](./dex-supported-chain)) | | > tokenContractAddress | String | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | code | String | Error code | | msg | String | Error message | | connId | String | WebSocket connection ID | Request format description ```json {"op": "subscribe","args": ["SubscriptionTopic"]} ```
## Request Example ```json { "op": "subscribe", "args": [{ "channel": "price", "chainIndex": "1", "tokenContractAddress": "0x382bb369d343125bfb2117af9c149795c6c65c50" }] } ``` ## Response Example ```json { "event": "subscribe", "arg": { "channel": "price", "chainIndex": "1" "tokenContractAddress":"0x382bb369d343125bfb2117af9c149795c6c65c50" }, "connId": "accb8e21" } ```
- [Unsubscribe](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-websocket-unsubscribe.md) {/* api-page */} # Unsubscribe Unsubscribe from one or more channels. ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | op | String | Yes | Operation, `unsubscribe` | | args | Array | Yes | List of subscribed channels | | > channel | String | Yes | Channel name | | > chainIndex | String | Yes | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](./dex-supported-chain)) | | > timestamp | String | Yes | Unix Epoch time, the unit is seconds | | > tokenContractAddress | String | Yes | Token contract address,for EVM please pass all-lowercase addresses (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | ## Response Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | event | String | Operation.`unsubscribe` or `error` | | arg | String | Subscribed channel | | > channel | String | Channel name | | > chainIndex | String | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](./dex-supported-chain)) | | > tokenContractAddress | String | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | code | String | Error code | | msg | String | Error message | | connId | String | WebSocket connection ID | Request format description ```json { "op": "unsubscribe", "args": ["SubscriptionTopic"] } ``` ## Request Example ```json { "op": "unsubscribe", "args": [{ "channel": "price", "chainIndex": "1", "tokenContractAddress": "0x382bb369d343125bfb2117af9c149795c6c65c50" }] } ``` ## Response Example ```json { "event": "unsubscribe", "arg": { "channel": "price", "chainIndex": "1", "tokenContractAddress":"0x382bb369d343125bfb2117af9c149795c6c65c50" }, "connId": "d0b44253" } ``` - [Websocket Channels](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-websocket-channels.md) # Websocket Channels - [Price Channel](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-websocket-price-channel.md) {/* api-page */} # Price Channel Retrieve the latest price data of a token. The fastest push frequency updates in real time. A push will only occur if there is a trade and the price is not filtered out by the candlestick (K-line) price filter.
**Request URL** Please contact us dexapi@okx.com. ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | op | String | Yes | Operation, `subscribe` `unsubscribe` | | args | Array | Yes | List of subscribed channels | | channel | String | Yes | Channel name,`price` | | chainIndex | String | Yes | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](./dex-supported-chain)) | | tokenContractAddress | String | Yes | Token contract address,for EVM please pass all-lowercase addresses (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | ## Response Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | event | String | Event, `subscribe` `unsubscribe` `error` | | arg | Object | Token contract address | | channel | String | Channel name | | chainIndex| String | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](./dex-supported-chain)) | | tokenContractAddress| String | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | code | String | Error code | | msg | String | Error message | ## Push Data Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | arg | Object | Successfully subscribed channel | | > channel | String | Channel name | | > chainIndex | String | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](./dex-supported-chain)) | | > tokenContractAddress| String | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | data | Array | Subscribed data | | > time | String | Timestamp of the price, Unix timestamp format in milliseconds | | > price | String | Latest token price |
## Request Example ```json { "op": "subscribe", "args": [ { "channel": "price", "chainIndex": "1", "tokenContractAddress":"0x382bb369d343125bfb2117af9c149795c6c65c50" } ] } ``` ## Response Example Successful response example ```json { "event": "subscribe", "arg": { "channel": "price", "chainIndex": "1" "tokenContractAddress":"0x382bb369d343125bfb2117af9c149795c6c65c50" }, "connId": "a4d3ae55" } ``` Failure response example ```json { "event": "error", "code": "60012", "msg": "Invalid request: {\"op\": \"subscribe\", \"argss\":[{ \"channel\" : \"price\", \"chainIndex\" : \"1\", \"tokenContractAddress\" : \"0x382bb369d343125bfb2117af9c149795c6c65c50\"}]}", "connId": "a4d3ae55" } ``` Push data example ```json { "arg": { "channel": "price", "chainIndex": "1" "tokenContractAddress":"0x382bb369d343125bfb2117af9c149795c6c65c50" }, "data": [ { "time": "1716892020000", "price": "26.458143090226812", } ] } ```
- [Candlesticks Channel](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-websocket-candlesticks-channel.md) {/* api-page */} # Candlesticks Channel Retrieve the candlesticks data of a token. The fastest push frequency is 1 push per second.
**Request URL** Please contact us dexapi@okx.com. ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | op | String | Yes | Operation, `subscribe` `unsubscribe` | | args | Array | Yes | List of subscribed channels | | channel | String | Yes | Channel name. `dex-token-candle1s` `dex-token-candle1m` `dex-token-candle3m` `dex-token-candle5m` `dex-token-candle15m` `dex-token-candle30m` `dex-token-candle1H` `dex-token-candle2H` `dex-token-candle4H` `dex-token-candle6H` `dex-token-candle12H` `dex-token-candle1M` `dex-token-candle3M` `dex-token-candle1W` `dex-token-candle1D` `dex-token-candle2D` `dex-token-candle3D` `dex-token-candle5D` `dex-token-candle6Hutc` `dex-token-candle12Hutc` `dex-token-candle1Dutc` `dex-token-candle2Dutc` `dex-token-candle3Dutc` `dex-token-candle5Dutc` `dex-token-candle1Wutc` `dex-token-candle1Mutc` `dex-token-candle3Mutc` | | chainIndex | String | Yes | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](./dex-supported-chain)) | | tokenContractAddress | String | Yes | Token contract address,for EVM please pass all-lowercase addresses (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | ## Response Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | event | String | Event, `subscribe` `unsubscribe` `error` | | arg | Object | Token contract address | | channel | String | Channel name | | chainIndex| String | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](./dex-supported-chain)) | | tokenContractAddress| String | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | code | String | Error code | | msg | String | Error message | ## Push Data Parameters | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | arg | Object | Successfully subscribed channel | | > channel | String | Channel name | | > chainIndex | String | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](./dex-supported-chain)) | | > tokenContractAddress| String | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | data | Array | Subscribed data | | > ts | String | Opening time of the candlestick, Unix timestamp format in milliseconds, e.g. 1597026383085 | | > o | String | Open price | | > h | String | highest price | | > l | String | Lowest price | | > c | String | Close price | | > vol | String | Trading volume, with a unit of base currency | | > volUsd | String | Trading volume, with a unit of usd. | | > confirm | String | The state of candlesticks.
`0`: represents that it is uncompleted `1`: represents that it is completed. |
## Request Example ```json { "op": "subscribe", "args": [ { "channel": "dex-token-candle1s", "chainIndex": "1", "tokenContractAddress":"0x382bb369d343125bfb2117af9c149795c6c65c50" } ] } ``` ## Response Example Successful response example ```json { "event": "subscribe", "arg": { "channel": "dex-token-candle1s", "chainIndex": "1" "tokenContractAddress":"0x382bb369d343125bfb2117af9c149795c6c65c50" }, "connId": "a4d3ae55" } ``` Failure response example ```json { "event": "error", "code": "60012", "msg": "Invalid request: {\"op\": \"subscribe\", \"argss\":[{ \"channel\" : \"dex-token-candle1s\", \"chainIndex\" : \"1\", \"tokenContractAddress\" : \"0x382bb369d343125bfb2117af9c149795c6c65c50\"}]}", "connId": "a4d3ae55" } ``` Push data example ```json { "arg": { "channel": "dex-token-candle1s", "chainIndex": "1" "tokenContractAddress":"0x382bb369d343125bfb2117af9c149795c6c65c50" }, "data": [ [ "1597026383085", "8533.02", "8553.74", "8527.17", "8548.26", "529.5858061", "226348.0482", "0" ] ] } ```
- [Trades Channel](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-websocket-trades-channel.md) {/* api-page */} # Trades Channel Retrieve the recent trades data. Data will be pushed whenever there is a trades.
**Request URL** Please contact us dexapi@okx.com. ## Request Parameters | Parameter | Type | Required | Description | | -------------------- | ------ | -------- | ------------------------------------------------------------------------------------------------ | | op | String | Yes | Operation, `subscribe` `unsubscribe` | | args | Array | Yes | List of subscribed channels | | channel | String | Yes | Channel name,`trades` | | chainIndex | String | Yes | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](./dex-supported-chain)) | | tokenContractAddress | String | Yes | Token contract address,for EVM please pass all-lowercase addresses (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | ## Response Parameters | Parameter | Type | Description | | -------------------- | ------ | ------------------------------------------------------------------------------------------------ | | event | String | Event, `subscribe` `unsubscribe` `error` | | arg | Object | Token contract address | | channel | String | Channel name | | chainIndex | String | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](./dex-supported-chain)) | | tokenContractAddress | String | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | code | String | Error code | | msg | String | Error message | ## Push Data Parameters | Parameter | Type | Description | | ----------------------- | ------ | ------------------------------------------------------------------------------------------------ | | arg | Object | Successfully subscribed channel | | > channel | String | Channel name | | > chainIndex | String | Unique identifier for the chain. (e.g., 1 for Ethereum. See [ChainIndex](./dex-supported-chain)) | | > tokenContractAddress | String | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) | | data | Array | Subscribed data | | > id | String | Unique trade id | | > txHashUrl | String | On-chain txhash of the transaction | | > userAddress | String | Authorizer of the transaction | | > dexName | String | Name of the dex where the trade occured | | > poolLogoUrl | String | Pool logo url | | > type | String | Trade Type buy sell | | > amountExchanged | String | Amount exchanged in this pair | | >> amount | String | Token exchanged amount in this trade | | >> tokenSymbol | String | Token symbol | | >> tokenContractAddress | String | Token contract address | | > price | String | Latest token price | | > volume | String | USD value of this trade | | > time | String | Timestamp of the trade, Unix timestamp format in milliseconds | | > isFiltered | String | If the trade is filtered for price and k-line calculation.
`0`: not filtered `1`: filtered |
## Request Example ```json { "op": "subscribe", "args": [ { "channel": "trades", "chainIndex": "501", "tokenContractAddress": "HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC" } ] } ``` ## Response Example Successful response example ```json { "event": "subscribe", "arg": { "channel": "trades", "chainIndex": "501", "tokenContractAddress": "HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC" }, "connId": "a4d3ae55" } ``` Failure response example ```json { "event": "error", "code": "60012", "msg": "Invalid request: {\"op\": \"subscribe\", \"argss\":[{ \"channel\" : \"trades\", \"chainIndex\" : \"501\", \"tokenContractAddress\" : \"HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC\"}]}", "connId": "a4d3ae55" } ``` Push data example ```json { "arg": { "channel": "trades", "chainIndex": "501" "tokenContractAddress":"HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC" }, "data":[ { "id":"1739439633000!@#120!@#14731892839", "chainIndex": "501", "tokenContractAddress": "HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC", "txHashUrl": "https://solscan.io/tx/zgDzoiVG4XuDgQcoEg9vhpRyfyk5thNUQuTeTCeF289Qec5iraeCrUzPLyiE2UCviox2ebbTcsagGvzYF7M5uqs", "userAddress": "2kCm1RHGJjeCKL4SA3ZJCLyXqUD7nEJ7GMtVaP7c6jQ8", "dexName": "Orca Whirlpools", "poolLogoUrl": "https://static.okx.com/cdn/wallet/logo/dex_orcaswap.png", "type": "sell", "changedTokenInfo": [ { "amount":"100.396595878", "tokenSymbol":"ai16z", "tokenContractAddress": "HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC" }, { "amount":"2.482831", "tokenSymbol":"SOL", "tokenContractAddress": "So11111111111111111111111111111111111111112" } ] "price": "26.458143090226812", "volume": "519.788163", "time": "1739439633000", "isFiltered": "0" } ] } ```
- [Error Codes](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-websocket-error-code.md) # Error Codes | Code | Message | |-------|------------------------------------------------------------------------------------------------------------| | 60004 | Invalid timestamp | | 60005 | Invalid apiKey | | 60006 | Timestamp request expired | | 60007 | Invalid sign | | 60008 | The current WebSocket endpoint does not support subscribing to {0} channels. Please check the WebSocket URL | | 60009 | Login failure | | 60011 | Please log in | | 60012 | Invalid request | | 60013 | Invalid args | | 60014 | Requests too frequent | | 60018 | Wrong URL or {0} doesn't exist. Please use the correct URL, channel and parameters referring to API document. | | 60019 | Invalid op: \{op\} | | 60020 | APIKey subscription amount exceeds the limit {0}. | | 60021 | This operation does not support multiple accounts login. | | 60022 | Bulk login partially succeeded | | 60023 | Bulk login requests too frequent | | 60024 | Wrong passphrase | | 60025 | token subscription amount exceeds the limit {0} | | 60026 | Batch login by APIKey and token simultaneously is not supported. | | 60027 | Parameter {0} can not be empty. | | 60028 | The current operation is not supported by this URL. Please use the correct WebSocket URL for the operation. | | 60029 | Only users who are in the whitelist are allowed to subscribe to this channel. | | 60030 | The WebSocket endpoint does not allow multiple or repeated logins. | | 60031 | API key doesn't exist. | | 63999 | Login failed due to internal error. Please try again later. | - [Index Price API Reference](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-index-price-reference.md) # Index Price API Reference - [Get Supported Chains](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-index-price-chains.md) {/* api-page */} # Get Supported Chains Retrieve information on chains supported by Index price API ### Request URL GET `https://web3.okx.com/api/v6/dex/balance/supported/chain` ## Request Parameters None ## Response Parameters | Parameter | Type | Description | |-----------|--------|-------------------| | name | String | Chain name | | logoUrl | String | Chain logo URL | | shortName | String | Chain short name | | chainIndex| String | Chain unique identifier | ## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/balance/supported/chain' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "name": "Ethereum", "logoUrl": "http://www.eth.org/eth.png", "shortName": "ETH", "chainIndex": "1" } ], "msg": "" } ``` - [Get Token Index Price](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-index-price.md) {/* api-page */} # Get Token Index Price The index price refers to a currency price calculated from the prices of multiple third-party data sources. Batch query for index token prices, maximum 100 token prices can be queried per request.
Request Parameters should be passed in the form of an array. ### Request URL POST `https://web3.okx.com/api/v6/dex/index/current-price` ## Request Parameters | Parameter | Type | Required | Description | |--------------|--------|----------|-------------| | chainIndex | String | Yes | Unique identifier of the blockchain | | tokenContractAddress | String | Yes | Token address.
`1`: Pass an empty string `""` to query the native token of the corresponding chain.
`2`: Pass the specific token contract address to query the corresponding token. |
## Response Parameters | Parameter | Type | Description | |--------------|--------|-------------------------------| | price | String | Token price | | time | String | Timestamp of the price, Unix timestamp in milliseconds | | chainIndex | String | Unique identifier of the blockchain | | tokenContractAddress | String | Token address.|
## Request Example ``` shell curl --location --request POST 'https://web3.okx.com/api/v6/dex/index/current-price' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '[ { "chainIndex": "1", "tokenContractAddress":"0xc18360217d8f7ab5e7c516566761ea12ce7f9d72" }, ]' ``` ## Response Example ``` json { "code": 0, "msg": "success", "data": [ { "chainIndex": "1", "tokenContractAddress": "0xc18360217d8f7ab5e7c516566761ea12ce7f9d72" "time": "1716892020000", "price": "26.458143090226812", } ] } ```
- [Get Historical Index Price](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-historical-index-price.md) {/* api-page */} # Get Historical Index Price Query historical prices for a specific token. ### Request URL GET `https://web3.okx.com/api/v6/dex/index/historical-price` ## Request Parameters | Parameter | Type | Required | Description | |--------------|--------|----------|----------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier of the blockchain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). | | tokenContractAddress | String | No | Token address.
`1`: Pass an empty string `""` to query the native token of the corresponding chain.
`2`: Pass the specific token contract address to query the corresponding token. | | limit | String | No | Number of entries per query, default is 50, maximum is 200 | | cursor | String | No | Cursor position, defaults to the first entry | | begin | String | No | Start time to query historical prices after. Unix timestamp in milliseconds | | end | String | No | End time to query historical prices before. If neither begin nor end is provided, query historical prices before the current time. Unix timestamp in milliseconds | | period | String | No | Time interval unit:
`1m`: 1 minute
`5m`: 5 minutes
`30m`: 30 minutes
`1h`: 1 hour
`1d`: 1 day (default) |
## Response Parameters | Parameter | Type | Description | |-----------|--------|----------------------| | prices | Array | List of historical prices | | >time | String | Timestamp of the minute (whole minute) | | >price | String | Cryptocurrency price (precision 18 decimal places) |
## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v5/wallet/token/historical-price?chainIndex=1&limit=5&begin=1700040600000&period=5m' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "msg": "success", "data": [ { "cursor": "31", "prices": [ { "time": "1700040600000", "price": "1994.430000000000000000" }, { "time": "1700040300000", "price": "1994.190000000000000000" }, { "time": "1700040000000", "price": "1992.090000000000000000" }, { "time": "1700039700000", "price": "1992.190000000000000000" }, { "time": "1700039400000", "price": "1990.190000000000000000" } ] } ] } ```
- [Error Codes](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-index-price-error-code.md) # Error Codes | Code | HTTP status | Message | |-------|-------------|-----------------------------------------------------------------------------------------| | 81001 | 200 | Incorrect parameter | - [Token API Reference](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-market-token-reference.md) # Token API Reference - [Token Search](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-market-token-search.md) {/* api-page */} # Token Search Search tokens by token name, symbol or token contract address. For token name or symbol search, return maximum 100 results by relevance.For token contract address, return the exact match result. ### Request URL GET `https://web3.okx.com/api/v6/dex/market/token/search` ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chains | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). | | search | String | Yes | Search for token keywords, token address or token symbol |
## Response Parameters | Parameter | Type | Description | |---------------------- |--------- |--------------------------------------------------------------------------------------------- | | chainIndex | String | Unique identifier of the chain. (Such as 1: Ethereum, for more see the list of [chainIndex](./dex-supported-chain) ) | | tokenName | String | Token name | | tokenSymbol | String | Token identification | | tokenLogoUrl | String | Token icon url | | tokenContractAddress | String | Token contract address | | decimal | String | Token precision | | explorerUrl | String | Token Browser link | | change | String | 24H price change ratio | | holders | String | Number of holders | | liquidity | String | Token liquidity (24h) | | marketCap | String | Token market cap | | price | String | Price | | tagList | Object | Label | | >communityRecognized | Boolean | True means it's listed in the Top 10 CEX or is community verifed |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/token/search?chains=1,10&search=weth' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "chainIndex": "1", "change": "1.02", "decimal": "18", "explorerUrl": "https://web3.okx.com/explorer/ethereum/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "holders": "886855", "liquidity": "2188092231.7914506202196479164801803109959738", "marketCap": "9916173829.907587128987514754", "price": "4391.91765972826983527", "tagList": { "communityRecognized": true }, "tokenContractAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "tokenLogoUrl": "https://static.coinall.ltd/cdn/wallet/logo/WETH-0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2.png", "tokenName": "Wrapped Ether", "tokenSymbol": "WETH" }, { "chainIndex": "10", "change": "1.57", "decimal": "18", "explorerUrl": "https://web3.okx.com/explorer/optimism/token/0x4200000000000000000000000000000000000006", "holders": "", "liquidity": "8066012.857541468860969364926025092091", "marketCap": "89347769.41928855897874667", "price": "4388.588953537819147873", "tagList": { "communityRecognized": false }, "tokenContractAddress": "0x4200000000000000000000000000000000000006", "tokenLogoUrl": "https://static.coinall.ltd/cdn/wallet/logo/WETH-0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2.png", "tokenName": "Wrapped Ether", "tokenSymbol": "WETH" }, { "chainIndex": "1", "change": "0", "decimal": "18", "explorerUrl": "https://web3.okx.com/explorer/ethereum/token/0x03928473f25bb2da6bc880b07ecbadc636822264", "holders": "", "liquidity": "290386.93658880514761888891240493783472", "marketCap": "125306.637009951812221918", "price": "1865.6119139683371", "tagList": { "communityRecognized": false }, "tokenContractAddress": "0x03928473f25bb2da6bc880b07ecbadc636822264", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/default-logo/token_custom_logo_default_s.png/type=default_350_0", "tokenName": "Static Aave Ethereum WETH", "tokenSymbol": "stataEthWETH" }, { "chainIndex": "1", "change": "", "decimal": "18", "explorerUrl": "https://web3.okx.com/explorer/ethereum/token/0xa684eaf215ad323452e2b2bf6f817d4aa5c116ab", "holders": "", "liquidity": "282162.925026260171260600639527587053876", "marketCap": "2708767.72448012889795138", "price": "4709.630733200069922727", "tagList": { "communityRecognized": false }, "tokenContractAddress": "0xa684eaf215ad323452e2b2bf6f817d4aa5c116ab", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/1-0xa684eaf215ad323452e2b2bf6f817d4aa5c116ab-106/type=default_90_0?v=1756925210569", "tokenName": "Loop Liquidity Pool - WETH", "tokenSymbol": "lpETH" }, { "chainIndex": "1", "change": "", "decimal": "18", "explorerUrl": "https://web3.okx.com/explorer/ethereum/token/0x5c6ee304399dbdb9c8ef030ab642b10820db8f56", "holders": "2084", "liquidity": "116461.577792709260809499466595788994488", "marketCap": "36218431.822006716776613252", "price": "5.339960118861368738", "tagList": { "communityRecognized": false }, "tokenContractAddress": "0x5c6ee304399dbdb9c8ef030ab642b10820db8f56", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/1-0x5c6ee304399dbdb9c8ef030ab642b10820db8f56-106/type=default_90_0?v=1756916154072", "tokenName": "Balancer 80 BAL 20 WETH", "tokenSymbol": "B-80BAL-20WETH" }, { "chainIndex": "1", "change": "", "decimal": "18", "explorerUrl": "https://web3.okx.com/explorer/ethereum/token/0x59cd1c87501baa753d0b5b5ab5d8416a45cd71db", "holders": "3062", "liquidity": "23099.0090680252518897028883167295250576", "marketCap": "873724256.731651779318335243", "price": "3073.898172687059849241", "tagList": { "communityRecognized": false }, "tokenContractAddress": "0x59cd1c87501baa753d0b5b5ab5d8416a45cd71db", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/default-logo/token_custom_logo_default_s.png/type=default_350_0", "tokenName": "Spark WETH", "tokenSymbol": "spWETH" }, { "chainIndex": "1", "change": "", "decimal": "18", "explorerUrl": "https://web3.okx.com/explorer/ethereum/token/0x2015bc0be96be4aea2aabc95522109acfec84c30", "holders": "168", "liquidity": "20290.228588047977267221819104361761613", "marketCap": "12948.232224742", "price": "0.000012948232224742", "tagList": { "communityRecognized": false }, "tokenContractAddress": "0x2015bc0be96be4aea2aabc95522109acfec84c30", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/1-0x2015bc0be96be4aea2aabc95522109acfec84c30-106/type=default_90_0?v=1756940993907", "tokenName": "WETH HEDZ", "tokenSymbol": "HEDZ" }, { "chainIndex": "10", "change": "", "decimal": "18", "explorerUrl": "https://web3.okx.com/explorer/optimism/token/0xc4d4500326981eacd020e20a81b1c479c161c7ef", "holders": "", "liquidity": "13254.943087761946817613043627328123036048", "marketCap": "611320.947975873134702172", "price": "1456.890419322951364824", "tagList": { "communityRecognized": false }, "tokenContractAddress": "0xc4d4500326981eacd020e20a81b1c479c161c7ef", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/10-0xc4d4500326981eacd020e20a81b1c479c161c7ef-106/type=default_90_0?v=1756917757030", "tokenName": "exactly WETH", "tokenSymbol": "exaWETH" }, { "chainIndex": "1", "change": "", "decimal": "18", "explorerUrl": "https://web3.okx.com/explorer/ethereum/token/0x030ba81f1c18d280636f32af80b9aad02cf0854e", "holders": "", "liquidity": "12547.59168386404013787240620483741313585", "marketCap": "35826020.242000942530530715", "price": "1314.148440799180995081", "tagList": { "communityRecognized": false }, "tokenContractAddress": "0x030ba81f1c18d280636f32af80b9aad02cf0854e", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/1666600000-0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8-106/type=default_90_0?v=1756916162800", "tokenName": "Aave interest bearing WETH", "tokenSymbol": "aWETH" }, { "chainIndex": "1", "change": "2.85", "decimal": "18", "explorerUrl": "https://web3.okx.com/explorer/ethereum/token/0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8", "holders": "34257", "liquidity": "11463.76396971485790593630247013424890962", "marketCap": "4750418418.712334041035710975", "price": "1907.640543775320052289", "tagList": { "communityRecognized": false }, "tokenContractAddress": "0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/1-0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8-106/type=default_90_0?v=1756917533831", "tokenName": "Aave Ethereum WETH", "tokenSymbol": "aEthWETH" }, { "chainIndex": "1", "change": "2.53", "decimal": "18", "explorerUrl": "https://web3.okx.com/explorer/ethereum/token/0xf951e335afb289353dc249e82926178eac7ded78", "holders": "18161", "liquidity": "573690.521874861978296864780127470294686829", "marketCap": "118167328.627636452996603343", "price": "4810.636535713744994382", "tagList": { "communityRecognized": false }, "tokenContractAddress": "0xf951e335afb289353dc249e82926178eac7ded78", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/1-0xf951e335afb289353dc249e82926178eac7ded78-106/type=default_90_0?v=1756916429358", "tokenName": "swETH", "tokenSymbol": "swETH" }, { "chainIndex": "1", "change": "1.09", "decimal": "18", "explorerUrl": "https://web3.okx.com/explorer/ethereum/token/0xa250cc729bb3323e7933022a67b52200fe354767", "holders": "129", "liquidity": "432842.271496957013794432695201924702530761", "marketCap": "308953196.848479131339625307", "price": "4382.323930133209063397", "tagList": { "communityRecognized": false }, "tokenContractAddress": "0xa250cc729bb3323e7933022a67b52200fe354767", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/default-logo/token_custom_logo_default_f.png/type=default_350_0", "tokenName": "Few Wrapped Wrapped Ether", "tokenSymbol": "fwWETH" }, { "chainIndex": "1", "change": "0.86", "decimal": "18", "explorerUrl": "https://web3.okx.com/explorer/ethereum/token/0xfae103dc9cf190ed75350761e95403b7b8afa6c0", "holders": "6051", "liquidity": "94590.872589521640507013935412981213469", "marketCap": "97299486.614255600625166281", "price": "4562.053912037697209607", "tagList": { "communityRecognized": false }, "tokenContractAddress": "0xfae103dc9cf190ed75350761e95403b7b8afa6c0", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/1-0xfae103dc9cf190ed75350761e95403b7b8afa6c0-106/type=default_90_0?v=1756918311334", "tokenName": "rswETH", "tokenSymbol": "rswETH" }, { "chainIndex": "1", "change": "", "decimal": "18", "explorerUrl": "https://web3.okx.com/explorer/ethereum/token/0x8e298734681adbfc41ee5d17ff8b0d6d803e7098", "holders": "", "liquidity": "67061.540612104310398692858222227724703", "marketCap": "256182610.813755222831916009", "price": "4122.319245593319382348", "tagList": { "communityRecognized": false }, "tokenContractAddress": "0x8e298734681adbfc41ee5d17ff8b0d6d803e7098", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/default-logo/token_custom_logo_default_f.png/type=default_350_0", "tokenName": "FARM_WETH", "tokenSymbol": "fWETH" }, { "chainIndex": "1", "change": "", "decimal": "18", "explorerUrl": "https://web3.okx.com/explorer/ethereum/token/0x90551c1795392094fe6d29b758eccd233cfaa260", "holders": "741", "liquidity": "23765.1203196336624818945354471916846708", "marketCap": "7169375.619352028020506861", "price": "4249.361573945986551465", "tagList": { "communityRecognized": false }, "tokenContractAddress": "0x90551c1795392094fe6d29b758eccd233cfaa260", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/1-0x90551c1795392094fe6d29b758eccd233cfaa260-106/type=default_90_0?v=1756921635155", "tokenName": "Fluid Wrapped Ether", "tokenSymbol": "fWETH" }, { "chainIndex": "1", "change": "", "decimal": "18", "explorerUrl": "https://web3.okx.com/explorer/ethereum/token/0xc585df3a8c9ca0c614d023a812624be36161502b", "holders": "", "liquidity": "5186.6585198126431857330171348192302664", "marketCap": "945937.955473011322178552", "price": "3295.093599759049722035", "tagList": { "communityRecognized": false }, "tokenContractAddress": "0xc585df3a8c9ca0c614d023a812624be36161502b", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/default-logo/token_custom_logo_default_K.png/type=default_350_0", "tokenName": "Karak - swETH", "tokenSymbol": "KswETH" }, { "chainIndex": "1", "change": "", "decimal": "9", "explorerUrl": "https://web3.okx.com/explorer/ethereum/token/0x3ca992ab59d77f1f72c87617fbff89a61c8dec19", "holders": "154", "liquidity": "11744.312223638733976406301174289191332", "marketCap": "8058.2964779077", "price": "0.000080582964779077", "tagList": { "communityRecognized": false }, "tokenContractAddress": "0x3ca992ab59d77f1f72c87617fbff89a61c8dec19", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/1-0x3ca992ab59d77f1f72c87617fbff89a61c8dec19-106/type=default_90_0?v=1756916858337", "tokenName": "Halloweth", "tokenSymbol": "Heth" }, { "chainIndex": "1", "change": "", "decimal": "18", "explorerUrl": "https://web3.okx.com/explorer/ethereum/token/0x1609d8aa20295feb8831ae0931bae14acf7a9c91", "holders": "", "liquidity": "28860.994451383949923801031550409468869", "marketCap": "18528.49701055747097576", "price": "0.000000000044043123", "tagList": { "communityRecognized": false }, "tokenContractAddress": "0x1609d8aa20295feb8831ae0931bae14acf7a9c91", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/default-logo/token_custom_logo_default_W.png/type=default_350_0", "tokenName": "We The Pepe", "tokenSymbol": "WTP" }, { "chainIndex": "1", "change": "", "decimal": "18", "explorerUrl": "https://web3.okx.com/explorer/ethereum/token/0x76cddf8c2a011f6a0264363ac3f82f2993fc1fab", "holders": "", "liquidity": "23132.527870367083040975207711380759535", "marketCap": "14353.657427732", "price": "0.000014353657427732", "tagList": { "communityRecognized": false }, "tokenContractAddress": "0x76cddf8c2a011f6a0264363ac3f82f2993fc1fab", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/1-0x76cddf8c2a011f6a0264363ac3f82f2993fc1fab-106/type=default_90_0?v=1756920804942", "tokenName": "We The People", "tokenSymbol": "POPULI" }, { "chainIndex": "1", "change": "", "decimal": "9", "explorerUrl": "https://web3.okx.com/explorer/ethereum/token/0x4a38a8089f8d33d6595ace079f999327a58c700f", "holders": "", "liquidity": "10307.401749556132649599477026641937954", "marketCap": "6914.14719751533", "price": "0.000000016435254457", "tagList": { "communityRecognized": false }, "tokenContractAddress": "0x4a38a8089f8d33d6595ace079f999327a58c700f", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/1-0x4a38a8089f8d33d6595ace079f999327a58c700f-106/type=default_90_0?v=1756938301307", "tokenName": "New Ethereum Project", "tokenSymbol": "PROTOCOL" } ], "msg": "" } ```
- [Token Basic Information](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-market-token-basic-info.md) {/* api-page */} # Token Basic Information Retrieve the basic token information of the specified token contract address ### Request URL POST `https://web3.okx.com/api/v6/dex/market/token/basic-info` ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). | | tokenContractAddress | String | Yes | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) |
## Response Parameters | Parameter | Type | Description | |---------------------- |--------- |-------------------------------------------------------------------------------------------- | | chainIndex | String | Unique identifier of the chain. (Such as 1: Ethereum, for more see the list of [chainIndex](./dex-supported-chain) ) | | tokenName | String | Token name | | tokenSymbol | String | Token identification | | tokenLogoUrl | String | Token icon url | | decimal | String | Token precision | | tagList | Object | Label | | >communityRecognized | Boolean | True means it's listed in the Top 10 CEX or is community verifed |
## Request Example ```shell curl --location --request POST 'https://web3.okx.com/api/v6/dex/market/token/basic-info' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '[ { "chainIndex": "501", "tokenContractAddress": "5mbK36SZ7J19An8jFochhQS4of8g6BwUjbeCSxBSoWdp" }, { "chainIndex": "501", "tokenContractAddress": "eL5fUxj2J4CiQsmW85k5FG9DvuQjjUoBHoQBi2Kpump" } ]' ``` ## Response Example ```json { "code": "0", "data": [ { "chainIndex": "501", "decimal": "6", "tagList": { "communityRecognized": true }, "tokenContractAddress": "5mbK36SZ7J19An8jFochhQS4of8g6BwUjbeCSxBSoWdp", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/small/501-5mbK36SZ7J19An8jFochhQS4of8g6BwUjbeCSxBSoWdp-106?v=1749146943562", "tokenName": "michi", "tokenSymbol": "$michi" }, { "chainIndex": "501", "decimal": "6", "tagList": { "communityRecognized": true }, "tokenContractAddress": "eL5fUxj2J4CiQsmW85k5FG9DvuQjjUoBHoQBi2Kpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-eL5fUxj2J4CiQsmW85k5FG9DvuQjjUoBHoQBi2Kpump-108/type=default_90_0?v=1755815305433", "tokenName": "Unicorn Fart Dust", "tokenSymbol": "UFD" } ], "msg": "" } ```
- [Token Trading Information](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-market-token-price-info.md) {/* api-page */} # Token Trading Information Return token trading information including price, volume, trading info, supply, holders, liquidity etc at specific timestamp, support max 100 multiple tokens query. ### Request URL POST `https://web3.okx.com/api/v6/dex/market/price-info` ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). | | tokenContractAddress | String | Yes | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) |
## Response Parameters | Parameter | Type | Description | |---------------------- |-------- |-------------------------------------------------------------------------------------------- | | chainIndex | String | Unique identifier of the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain) | | tokenContractAddress | String | Token contract address (e.g. 0x382bb369d343125bfb2117af9c149795c6c65c50) | | time | String | Price timestamp, using Unix Millisecond timestamp format | | price | String | Latest token price | | marketCap | String | Token market cap | | priceChange5M | String | Price changes within 5 minutes, in percentage increase or decrease | | priceChange1H | String | Price changes within one hour, expressed as a percentage increase or decrease | | priceChange4H | String | Price changes within 4 hours, expressed as a percentage increase or decrease | | priceChange24H | String | Price changes within 24 hours, expressed as a percentage increase or decrease | | volume5M | String | Trading volume within 5 minutes | | volume1H | String | Trading volume within 1 hour | | volume4H | String | Trading volume within 4 hours | | volume24H | String | Trading volume within 24 hours | | txs5M | String | Token transactions within 5 minutes | | txs1H | String | Token transactions within 1 hour | | txs4H | String | Token transactions within 4 hours | | txs24H | String | Number of token transactions within 24 hours | | maxPrice | String | Token 24h highest price | | tradeNum | String | 24H token trading quantity | | minPrice | String | Token 24h lowest price | | circSupply | String | Token circulation supply | | liquidity | String | Liquidity in the token pool | | holders | String | Number of token holding addresses |
## Request Example ```shell curl --location --request POST 'https://web3.okx.com/api/v6/dex/market/price-info' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '[ { "chainIndex": "501", "tokenContractAddress": "5mbK36SZ7J19An8jFochhQS4of8g6BwUjbeCSxBSoWdp" }, { "chainIndex": "501", "tokenContractAddress": "eL5fUxj2J4CiQsmW85k5FG9DvuQjjUoBHoQBi2Kpump" } ]' ``` ## Response Example ```json { "code": "0", "data": [ { "chainIndex": "501", "circSupply": "555761678.7348550000", "holders": "46998", "liquidity": "2909733.283759244562509712218832656", "marketCap": "12252728.212049527112081409", "maxPrice": "0.023000175796511334", "minPrice": "0.021290716539724027", "price": "0.022046730965585534", "priceChange1H": "-1.24", "priceChange24H": "-1.8", "priceChange4H": "-2.64", "priceChange5M": "0.22", "time": "1756816961600", "tokenContractAddress": "5mbK36SZ7J19An8jFochhQS4of8g6BwUjbeCSxBSoWdp", "tradeNum": "9577269.994247", "txs1H": "27664", "txs24H": "127879", "txs4H": "108489", "txs5M": "2265", "volume1H": "7376.6139697593500223", "volume24H": "213047.96235814982022456", "volume4H": "33943.03136454470008366", "volume5M": "544.69701090069000181" }, { "chainIndex": "501", "circSupply": "999973538.9201610000", "holders": "37302", "liquidity": "2946946.965800864848335614721052390", "marketCap": "25792746.281014184438384254", "maxPrice": "0.026539875867707924", "minPrice": "0.02427728431412691", "price": "0.025793428802993062", "priceChange1H": "-1.13", "priceChange24H": "3.4", "priceChange4H": "-2.07", "priceChange5M": "0.52", "time": "1756816961600", "tokenContractAddress": "eL5fUxj2J4CiQsmW85k5FG9DvuQjjUoBHoQBi2Kpump", "tradeNum": "10046562.105494", "txs1H": "166", "txs24H": "2888", "txs4H": "322", "txs5M": "29", "volume1H": "10343.0564689259900202", "volume24H": "253496.67765782958052983", "volume4H": "21530.5160926891601342", "volume5M": "3278.85450250897" } ], "msg": "" } ```
- [Token Ranking List](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-market-token-ranking.md) {/* api-page */} # Token Ranking List Return token ranking list based on price fluctuations, trading volume or market cap within the specified timeframe in descending order,maximum 100 results ### Request URL GET `https://web3.okx.com/api/v6/dex/market/token/toplist` ## Request Parameters | Parameter | Type | Required | Description | |----------- |-------- |----------- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | chains | String | Yes | Unique identifier of the chain, e.g., 1: Ethereum.See more [here](./dex-supported-chain).
Supports querying multiple chains, seperated by commas. | | sortBy | String | Yes | Input 2,return token ranking lists based on price fluctuations
Input 5, return token ranking lists based on trading volume
Input 6,return token ranking lists based on market cap | | timeFrame | String | Yes | 1:5m,
2:1h,
3:4h
4:24h |
## Response Parameters | Parameter | Type | Description | |---------------------- |-------- |-------------------------------------------------------------------------------------------- | | chainIndex | String | Unique identifier of the chain. (Such as 1: Ethereum, for more see the list of [chainIndex](./dex-supported-chain). ) | | tokenSymbol | String | Token identification | | tokenLogoUrl | String | Token icon url | | tokenContractAddress | String | Token contract address | | marketCap | String | Token market cap, token price multiplied by circulating supply | | volume | String | Token trading USD value | | firstTradeTime | String | Token first transaction time | | change | String | Proportion of token price change | | liquidity | String | Liquidity in the token pool | | price | String | Token price | | holders | String | Number of token holding addresses | | uniqueTraders | String | Number of token unique trading addresses at a specified time | | txsBuy | String | Number of purchases at the specified time | | txsSell | String | Number of sales at a specified time | | txs | String | Number of transactions at a specified time |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/token/toplist?chains=501&sortBy=2&timeFrame=1' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "chainIndex": "501", "change": "2022.46", "firstTradeTime": "1756817281000", "holders": "82", "liquidity": "1879425.106935120795227971", "marketCap": "2306047.701895103", "price": "0.002306047701895103", "tokenContractAddress": "2fBioj73cpdEFNczg5LNU6rgeTzYjHqhn6FGg5JJ3eSu", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-2fBioj73cpdEFNczg5LNU6rgeTzYjHqhn6FGg5JJ3eSu-108/type=default_90_0?v=1756817284604", "tokenSymbol": "SOMNIA", "txs": "159", "txsBuy": "82", "txsSell": "77", "uniqueTraders": "56", "volume": "66302.6442408798505016" }, { "chainIndex": "501", "change": "1989.39", "firstTradeTime": "1756817267000", "holders": "135", "liquidity": "92935.605935683173018898", "marketCap": "2068281.512847419", "price": "0.002068281512847419", "tokenContractAddress": "8yLDUQxmnefTgJMuGRsfWK6ZpFQ6xuox5rXRBNQ1ZZB4", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-8yLDUQxmnefTgJMuGRsfWK6ZpFQ6xuox5rXRBNQ1ZZB4-108/type=default_90_0?v=1756817268811", "tokenSymbol": "Froggy", "txs": "261", "txsBuy": "148", "txsSell": "113", "uniqueTraders": "102", "volume": "74823.758787540322738" }, { "chainIndex": "501", "change": "1058.3", "firstTradeTime": "1756817174000", "holders": "160", "liquidity": "85349.876607952601183713", "marketCap": "2073732.175809067", "price": "0.002073732175809067", "tokenContractAddress": "H5cQFT1zGkDLURJ6b5Pzm9iZcrRbo6VcMurJPAHq9U7o", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-H5cQFT1zGkDLURJ6b5Pzm9iZcrRbo6VcMurJPAHq9U7o-108/type=default_90_0?v=1756817176283", "tokenSymbol": "Froggie", "txs": "718", "txsBuy": "390", "txsSell": "328", "uniqueTraders": "149", "volume": "147565.706687239476516" }, { "chainIndex": "501", "change": "1014.29", "firstTradeTime": "1756817324000", "holders": "17", "liquidity": "1893459.465171589063908358", "marketCap": "2323677.729778543", "price": "0.002323677729778543", "tokenContractAddress": "49AnnzZq3FnL8ofHC89Duq4SnLm6yUxfjRV8duHaMioo", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-49AnnzZq3FnL8ofHC89Duq4SnLm6yUxfjRV8duHaMioo-108/type=default_90_0?v=1756817325587", "tokenSymbol": "Froggy", "txs": "33", "txsBuy": "23", "txsSell": "10", "uniqueTraders": "13", "volume": "48554.287860729174464" }, { "chainIndex": "501", "change": "897.27", "firstTradeTime": "1756817154000", "holders": "192", "liquidity": "75884.421084854656282973", "marketCap": "1773957.694951651", "price": "0.001773957694951651", "tokenContractAddress": "FjUnoYwYBUc5kqwLFEYe2imDtq9x7dZGDR8REzc5gqXu", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-FjUnoYwYBUc5kqwLFEYe2imDtq9x7dZGDR8REzc5gqXu-108/type=default_90_0?v=1756817156272", "tokenSymbol": "Diaminu", "txs": "975", "txsBuy": "542", "txsSell": "433", "uniqueTraders": "182", "volume": "179727.147100923050173" }, { "chainIndex": "501", "change": "687.3", "firstTradeTime": "1756817257000", "holders": "92", "liquidity": "14012.601216005533678184", "marketCap": "45126.599462127", "price": "0.000045126599462127", "tokenContractAddress": "Gx4XzK9webKtf5yFCCKGpVLzqkyDKmKpjLSudfnYpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-Gx4XzK9webKtf5yFCCKGpVLzqkyDKmKpjLSudfnYpump-108/type=default_90_0?v=1756817259972", "tokenSymbol": "FROG", "txs": "455", "txsBuy": "245", "txsSell": "210", "uniqueTraders": "184", "volume": "67008.67653863694713376" }, { "chainIndex": "501", "change": "252.46", "firstTradeTime": "1756817068000", "holders": "148", "liquidity": "11032.889894624904861453", "marketCap": "22308.741908356", "price": "0.000022308741908356", "tokenContractAddress": "A9wDc5pG1SeyfhzaLYNWzUMck5oJqZ8RSVc4Z9xnpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-A9wDc5pG1SeyfhzaLYNWzUMck5oJqZ8RSVc4Z9xnpump-108/type=default_90_0?v=1756817073526", "tokenSymbol": "Froggie", "txs": "1361", "txsBuy": "726", "txsSell": "635", "uniqueTraders": "441", "volume": "209960.160543612614763145" }, { "chainIndex": "501", "change": "75.3", "firstTradeTime": "1756817219000", "holders": "34", "liquidity": "7323.515695454196350214", "marketCap": "10675.783299905", "price": "0.000010675783299905", "tokenContractAddress": "85FxoUES38v2D6M3YyARGGFaaLkCv6QxWjukodEwpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-85FxoUES38v2D6M3YyARGGFaaLkCv6QxWjukodEwpump-108/type=default_90_0?v=1756817232853", "tokenSymbol": "Blobby Man", "txs": "164", "txsBuy": "89", "txsSell": "75", "uniqueTraders": "82", "volume": "13510.406610950301260508" }, { "chainIndex": "501", "change": "71.98", "firstTradeTime": "1756817103000", "holders": "37", "liquidity": "7045.546426281110103218", "marketCap": "10069.235886313", "price": "0.000010069235886313", "tokenContractAddress": "CJtUqq3bjPzYVStSuSqLTGbdFCdx8SF4e6KUYRk7pump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-CJtUqq3bjPzYVStSuSqLTGbdFCdx8SF4e6KUYRk7pump-108/type=default_90_0?v=1756817105010", "tokenSymbol": "UFT", "txs": "279", "txsBuy": "148", "txsSell": "131", "uniqueTraders": "86", "volume": "14520.066055244963147296" }, { "chainIndex": "501", "change": "62.56", "firstTradeTime": "1756817152000", "holders": "21", "liquidity": "131652.987361751835318228", "marketCap": "93453.42572654", "price": "0.00009345342572654", "tokenContractAddress": "4d9EfTpxJKaPKpza1ENojiuY3jPHfUThxoNQEuecT5kh", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-4d9EfTpxJKaPKpza1ENojiuY3jPHfUThxoNQEuecT5kh-108/type=default_90_0?v=1756816432260", "tokenSymbol": "BARKY", "txs": "26", "txsBuy": "26", "txsSell": "0", "uniqueTraders": "18", "volume": "14251.26048527397244897" }, { "chainIndex": "501", "change": "49.93", "firstTradeTime": "1755706155000", "holders": "1497", "liquidity": "98709.611525230925225582", "marketCap": "403887.798597632848813235", "price": "0.000403906190167366", "tokenContractAddress": "9xzF5pmvWcEhmCCnuXKXttdF6HfQFy5V246v34SFpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-9xzF5pmvWcEhmCCnuXKXttdF6HfQFy5V246v34SFpump-108/type=default_90_0?v=1756553365620", "tokenSymbol": "PMP", "txs": "91", "txsBuy": "57", "txsSell": "34", "uniqueTraders": "67", "volume": "22148.86491423674785406" }, { "chainIndex": "501", "change": "30.74", "firstTradeTime": "1756816839000", "holders": "139", "liquidity": "11686.356699533866082067", "marketCap": "25422.963359543", "price": "0.000025422963359543", "tokenContractAddress": "HjkLxt2t196iTQz2NEE8b3tHbGCPpHij6N4ddkZpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-HjkLxt2t196iTQz2NEE8b3tHbGCPpHij6N4ddkZpump-108/type=default_90_0?v=1756816873473", "tokenSymbol": "Ⅳ", "txs": "286", "txsBuy": "203", "txsSell": "83", "uniqueTraders": "140", "volume": "17984.008434328438638037" }, { "chainIndex": "501", "change": "18.86", "firstTradeTime": "1756804973000", "holders": "4763", "liquidity": "58795.265442791133885032", "marketCap": "202815.68975336383171415", "price": "0.000202816839897315", "tokenContractAddress": "77zu17bv8G4p2tKB1VNGt3G5XaciMaMcHuKdFaRdgKNB", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-77zu17bv8G4p2tKB1VNGt3G5XaciMaMcHuKdFaRdgKNB-108/type=default_90_0?v=1756804974763", "tokenSymbol": "USDMC", "txs": "292", "txsBuy": "180", "txsSell": "112", "uniqueTraders": "151", "volume": "30067.94208777356207428" }, { "chainIndex": "501", "change": "14.38", "firstTradeTime": "1756816237000", "holders": "60", "liquidity": "260429.231680142778574054", "marketCap": "192710.222700692590387621", "price": "0.000192710676094279", "tokenContractAddress": "GPJY1V2Uu1SzNaJZHeEBCgLzn1fuT7z9dLsFeUvg8T4z", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-GPJY1V2Uu1SzNaJZHeEBCgLzn1fuT7z9dLsFeUvg8T4z-108/type=default_90_0?v=1756816166614", "tokenSymbol": "TRADOOR", "txs": "1843", "txsBuy": "922", "txsSell": "921", "uniqueTraders": "51", "volume": "1846125.2049301402716" }, { "chainIndex": "501", "change": "14.04", "firstTradeTime": "1756816677000", "holders": "282", "liquidity": "48463.704883897680756153", "marketCap": "119792.661508354057359712", "price": "0.000119792930788857", "tokenContractAddress": "4JJe26d3J7cMq9bTpQexa8UDizXWuMJqV1osYctjbonk", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-4JJe26d3J7cMq9bTpQexa8UDizXWuMJqV1osYctjbonk-108/type=default_90_0?v=1756816676181", "tokenSymbol": "commodity", "txs": "482", "txsBuy": "255", "txsSell": "227", "uniqueTraders": "174", "volume": "18195.73937606113859018" }, { "chainIndex": "501", "change": "12.05", "firstTradeTime": "1756816771000", "holders": "286", "liquidity": "46464.418791554785140646", "marketCap": "110133.885010382606960702", "price": "0.00011074182298676", "tokenContractAddress": "HKZ3qUCah4679ArZXi25bpTAdQkUXZVyJ9MQUQ3ebonk", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-HKZ3qUCah4679ArZXi25bpTAdQkUXZVyJ9MQUQ3ebonk-108/type=default_90_0?v=1756816768056", "tokenSymbol": "commodity", "txs": "529", "txsBuy": "271", "txsSell": "258", "uniqueTraders": "166", "volume": "21130.432670260435783926" }, { "chainIndex": "501", "change": "11.25", "firstTradeTime": "1756314247000", "holders": "1679", "liquidity": "196928.642226023874498611", "marketCap": "1048033.221144608560937667", "price": "0.001048033653071918", "tokenContractAddress": "FfixAeHevSKBZWoXPTbLk4U4X9piqvzGKvQaFo3cpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-FfixAeHevSKBZWoXPTbLk4U4X9piqvzGKvQaFo3cpump-108/type=webp_90_0?v=1756314249180", "tokenSymbol": "POLYFACTS", "txs": "129", "txsBuy": "52", "txsSell": "77", "uniqueTraders": "108", "volume": "21422.1482206240017355" }, { "chainIndex": "501", "change": "10.28", "firstTradeTime": "1756816849000", "holders": "113", "liquidity": "47064.196882814850861275", "marketCap": "32673.339958935702263041", "price": "0.000032491707104644", "tokenContractAddress": "ERavPgzsG69jem88y22kiKCSsTPcsecbJYAeSun3T4mR", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-ERavPgzsG69jem88y22kiKCSsTPcsecbJYAeSun3T4mR-108/type=default_90_0?v=1756816794043", "tokenSymbol": "JPUSD", "txs": "676", "txsBuy": "424", "txsSell": "252", "uniqueTraders": "102", "volume": "54658.57307647939379818" }, { "chainIndex": "501", "change": "9.15", "firstTradeTime": "1756816910000", "holders": "112", "liquidity": "46319.633191192228323872", "marketCap": "31679.616279152344458346", "price": "0.000031679817725352", "tokenContractAddress": "h6ATe7aTKizjNDtzXLpQL6ATZ5aWyvnSrMfpCb4Sqyb", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-h6ATe7aTKizjNDtzXLpQL6ATZ5aWyvnSrMfpCb4Sqyb-108/type=default_90_0?v=1756816854020", "tokenSymbol": "Tokabu", "txs": "670", "txsBuy": "425", "txsSell": "245", "uniqueTraders": "103", "volume": "50574.669872156585311845" }, { "chainIndex": "501", "change": "8.81", "firstTradeTime": "1721244265000", "holders": "1117", "liquidity": "84216.447787284889106843", "marketCap": "478266.1908833959771361", "price": "0.000478822309574452", "tokenContractAddress": "8EPFXce1eGU7ePRMp8z3ZSu7rT7eczKB7VaysX4Rpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-8EPFXce1eGU7ePRMp8z3ZSu7rT7eczKB7VaysX4Rpump-108/type=default_90_0?v=1756776508370", "tokenSymbol": "GIB", "txs": "653", "txsBuy": "333", "txsSell": "320", "uniqueTraders": "334", "volume": "300168.4703874356571827" }, { "chainIndex": "501", "change": "8.8", "firstTradeTime": "1756808201000", "holders": "208", "liquidity": "143071.497204747476008732", "marketCap": "5746512.075769158", "price": "0.005746512075769158", "tokenContractAddress": "7odQZLuEwiv3pi8R6kqLgXAKoauMGsaAKXy24Hgfo4iB", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-7odQZLuEwiv3pi8R6kqLgXAKoauMGsaAKXy24Hgfo4iB-108/type=default_90_0?v=1756808203257", "tokenSymbol": "THE PEBBLE", "txs": "1148", "txsBuy": "587", "txsSell": "561", "uniqueTraders": "160", "volume": "132182.7131730246420993" }, { "chainIndex": "501", "change": "8.01", "firstTradeTime": "1756810486000", "holders": "5166", "liquidity": "188475.50034245594858762", "marketCap": "153140.294967924", "price": "0.000153140294967924", "tokenContractAddress": "CddRHVMf3xWhBxQEkK7WQDXPzYFTGWVqfi6PijNg5wTS", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-CddRHVMf3xWhBxQEkK7WQDXPzYFTGWVqfi6PijNg5wTS-108/type=default_90_0?v=1756810515269", "tokenSymbol": "ONE PIECE", "txs": "1486", "txsBuy": "864", "txsSell": "622", "uniqueTraders": "263", "volume": "250600.7146032930388663" }, { "chainIndex": "501", "change": "6.56", "firstTradeTime": "1756816734000", "holders": "205", "liquidity": "99369.494981259308774054", "marketCap": "2914020.419135382", "price": "0.002914020419135382", "tokenContractAddress": "HhYihEk2SaT4EKRAgA2C1ds8h9jN7aD3hZKbTjre7bNA", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-HhYihEk2SaT4EKRAgA2C1ds8h9jN7aD3hZKbTjre7bNA-108/type=default_90_0?v=1756816735407", "tokenSymbol": "MANGOBIRD", "txs": "1493", "txsBuy": "827", "txsSell": "666", "uniqueTraders": "200", "volume": "177448.50671647199706424" }, { "chainIndex": "501", "change": "5.83", "firstTradeTime": "1752019086000", "holders": "1258", "liquidity": "230097.771344113781214109", "marketCap": "1938312.098571112883149527", "price": "0.00193985502138577", "tokenContractAddress": "EebvSxfGbjyHMJ2bu1jhtNidbhVbQJtcg9y561Kipump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-EebvSxfGbjyHMJ2bu1jhtNidbhVbQJtcg9y561Kipump-108/type=default_90_0?v=1756682045165", "tokenSymbol": "ZARD", "txs": "88", "txsBuy": "45", "txsSell": "43", "uniqueTraders": "41", "volume": "17662.79395007747064292" }, { "chainIndex": "501", "change": "4.87", "firstTradeTime": "1756815650000", "holders": "546", "liquidity": "139310.558951493673723994", "marketCap": "103756.2019846", "price": "0.000010310161269128", "tokenContractAddress": "6ffWGbyR3Hrr6tzjTkMAxATPa42JxWhmVJiCmPv6h9vD", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-6ffWGbyR3Hrr6tzjTkMAxATPa42JxWhmVJiCmPv6h9vD-108/type=default_90_0?v=1756815613592", "tokenSymbol": "USDMC", "txs": "1067", "txsBuy": "569", "txsSell": "498", "uniqueTraders": "230", "volume": "217076.52273519271564663" }, { "chainIndex": "501", "change": "4.08", "firstTradeTime": "1756816121000", "holders": "533", "liquidity": "176498.376991055636983963", "marketCap": "119031.911888089879837479", "price": "0.000119031926990248", "tokenContractAddress": "BrgHBrXYU71is1HcNytcrgS2GmhgQCEKc32j5MG34q6f", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-BrgHBrXYU71is1HcNytcrgS2GmhgQCEKc32j5MG34q6f-108/type=default_90_0?v=1756816153537", "tokenSymbol": "USDMC", "txs": "1715", "txsBuy": "918", "txsSell": "797", "uniqueTraders": "166", "volume": "1419158.8875468562698442" }, { "chainIndex": "501", "change": "1.98", "firstTradeTime": "1752716161000", "holders": "5349", "liquidity": "959753.501266530949870961", "marketCap": "8746128.422067497138265686", "price": "0.008750528751440552", "tokenContractAddress": "2oQNkePakuPbHzrVVkQ875WHeewLHCd2cAwfwiLQbonk", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-2oQNkePakuPbHzrVVkQ875WHeewLHCd2cAwfwiLQbonk-108/type=default_90_0?v=1755778887746", "tokenSymbol": "AOL", "txs": "73", "txsBuy": "32", "txsSell": "41", "uniqueTraders": "32", "volume": "28579.08751165764033952" }, { "chainIndex": "501", "change": "1.41", "firstTradeTime": "1756809674000", "holders": "1059", "liquidity": "56482.892992827244299535", "marketCap": "215305.560175936875167839", "price": "0.000215305699270649", "tokenContractAddress": "HMcQvSj8hEqdkbyPbEUmiU6mnu5k2Ki5y5J65ebpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-HMcQvSj8hEqdkbyPbEUmiU6mnu5k2Ki5y5J65ebpump-108/type=default_90_0?v=1756809677266", "tokenSymbol": "KITTY", "txs": "1438", "txsBuy": "780", "txsSell": "658", "uniqueTraders": "585", "volume": "104245.124277390296519518" }, { "chainIndex": "501", "change": "1.07", "firstTradeTime": "1747606449000", "holders": "9477", "liquidity": "3230670.928656840071469246", "marketCap": "52802397.564394416783409086", "price": "0.052806821443135322", "tokenContractAddress": "CB9dDufT3ZuQXqqSfa1c5kY935TEreyBw9XJXxHKpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-CB9dDufT3ZuQXqqSfa1c5kY935TEreyBw9XJXxHKpump-108/type=default_90_0?v=1755847029086", "tokenSymbol": "USDUC", "txs": "329", "txsBuy": "192", "txsSell": "137", "uniqueTraders": "113", "volume": "46265.685740000620042" }, { "chainIndex": "501", "change": "1.03", "firstTradeTime": "1756664069000", "holders": "133", "liquidity": "62057.619989926922236819", "marketCap": "274703.021291954", "price": "0.000274703021291954", "tokenContractAddress": "HNwh4FSc9mTH4p9j42LwBGLFaNRvBF7AAskcvQ6Ppump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-HNwh4FSc9mTH4p9j42LwBGLFaNRvBF7AAskcvQ6Ppump-108/type=default_90_0?v=1756764219844", "tokenSymbol": "HOPE", "txs": "175", "txsBuy": "130", "txsSell": "45", "uniqueTraders": "42", "volume": "17406.45868918717628976" }, { "chainIndex": "501", "change": "0.95", "firstTradeTime": "1740949246000", "holders": "20714", "liquidity": "1594822.515115390943909249", "marketCap": "7756827.713473804622872756", "price": "0.007757714960340776", "tokenContractAddress": "CniPCE4b3s8gSUPhUiyMjXnytrEqUrMfSsnbBjLCpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-CniPCE4b3s8gSUPhUiyMjXnytrEqUrMfSsnbBjLCpump-108/type=default_90_0?v=1755828682923", "tokenSymbol": "pwease", "txs": "133", "txsBuy": "86", "txsSell": "47", "uniqueTraders": "71", "volume": "27256.35945966481044445" }, { "chainIndex": "501", "change": "0.28", "firstTradeTime": "1749247401000", "holders": "10247", "liquidity": "2862763.031465412908522645", "marketCap": "40600564.991735767807254698", "price": "0.040653924365789036", "tokenContractAddress": "H8xQ6poBjB9DTPMDTKWzWPrnxu4bDEhybxiouF8Ppump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-H8xQ6poBjB9DTPMDTKWzWPrnxu4bDEhybxiouF8Ppump-108/type=default_90_0?v=1755850364794", "tokenSymbol": "Tokabu", "txs": "224", "txsBuy": "109", "txsSell": "115", "uniqueTraders": "59", "volume": "16155.45452672287000046" }, { "chainIndex": "501", "change": "0.01", "firstTradeTime": "1741648846000", "holders": "257", "liquidity": "20492752.06680118772222342", "marketCap": "327987695.280425384109332464", "price": "0.999582416469253323", "tokenContractAddress": "2u1tszSeqZ3qBWF3uNGPFc8TzMk2tdiwknnRMWGWjGWH", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-2u1tszSeqZ3qBWF3uNGPFc8TzMk2tdiwknnRMWGWjGWH-108/type=default_90_0?v=1756797958448", "tokenSymbol": "USDG", "txs": "223", "txsBuy": "88", "txsSell": "135", "uniqueTraders": "52", "volume": "44986.25270077389012" }, { "chainIndex": "501", "change": "-0.02", "firstTradeTime": "1737165693000", "holders": "636702", "liquidity": "336626054.806566640071151926", "marketCap": "1658904007.245981009619110273", "price": "8.294548857547532416", "tokenContractAddress": "6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN-108/type=default_90_0?v=1756791330135", "tokenSymbol": "TRUMP", "txs": "332", "txsBuy": "87", "txsSell": "245", "uniqueTraders": "67", "volume": "675964.0777230149" }, { "chainIndex": "501", "change": "-0.09", "firstTradeTime": "1701848394000", "holders": "18340", "liquidity": "8467691.620883390777782272", "marketCap": "200181415.37351283395756281", "price": "0.200184919068676607", "tokenContractAddress": "METAewgxyPbgwsseH8T16a39CQ5VyVxZi9zXiDPY18m", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-METAewgxyPbgwsseH8T16a39CQ5VyVxZi9zXiDPY18m-108/type=default_90_0?v=1756765320384", "tokenSymbol": "MPLX", "txs": "190", "txsBuy": "97", "txsSell": "93", "uniqueTraders": "40", "volume": "19607.67215057749002" }, { "chainIndex": "501", "change": "-0.14", "firstTradeTime": "1742398577000", "holders": "1803", "liquidity": "15083768.447320617604364142", "marketCap": "16836748.633987710899393822", "price": "0.336737071706557472", "tokenContractAddress": "GbbesPbaYh5uiAZSYNXTc7w9jty1rpg3P9L4JeN4LkKc", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-GbbesPbaYh5uiAZSYNXTc7w9jty1rpg3P9L4JeN4LkKc-108/type=default_90_0?v=1756801228556", "tokenSymbol": "TRX", "txs": "41", "txsBuy": "11", "txsSell": "30", "uniqueTraders": "13", "volume": "44546.64649089299" }, { "chainIndex": "501", "change": "-0.21", "firstTradeTime": "1756816704000", "holders": "115", "liquidity": "112328.55920957834314807", "marketCap": "77492.468208494937899376", "price": "0.000077492666857508", "tokenContractAddress": "BWMxZb5kjTFHqoBuBLpqgAxqMpwGY8jwv6HqFYABM9w2", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-BWMxZb5kjTFHqoBuBLpqgAxqMpwGY8jwv6HqFYABM9w2-108/type=default_90_0?v=1756816647453", "tokenSymbol": "TAPS", "txs": "722", "txsBuy": "371", "txsSell": "351", "uniqueTraders": "103", "volume": "151755.711163994205613708" }, { "chainIndex": "501", "change": "-0.26", "firstTradeTime": "1752489191000", "holders": "24193", "liquidity": "994852.118358644362982639", "marketCap": "7340180.457669025340876496", "price": "0.007340310921537003", "tokenContractAddress": "9tqjeRS1swj36Ee5C1iGiwAxjQJNGAVCzaTLwFY8bonk", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-9tqjeRS1swj36Ee5C1iGiwAxjQJNGAVCzaTLwFY8bonk-108/type=default_90_0?v=1755857244210", "tokenSymbol": "Ani", "txs": "271", "txsBuy": "124", "txsSell": "147", "uniqueTraders": "58", "volume": "10467.82107846434030144" }, { "chainIndex": "501", "change": "-0.32", "firstTradeTime": "1752511812000", "holders": "60955", "liquidity": "28729403.329430994575424009", "marketCap": "3580769520.00776265866247889", "price": "0.003580807374082859", "tokenContractAddress": "pumpCmXqMfrsAkQ5r49WcJnRayYRqmXz6ae8H7H9Dfn", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-pumpCmXqMfrsAkQ5r49WcJnRayYRqmXz6ae8H7H9Dfn-108/type=default_90_0?v=1756752472961", "tokenSymbol": "PUMP", "txs": "258", "txsBuy": "102", "txsSell": "156", "uniqueTraders": "92", "volume": "79488.63379785466202671" }, { "chainIndex": "501", "change": "-0.4", "firstTradeTime": "1735221625000", "holders": "31476", "liquidity": "12313130.70860638334161615", "marketCap": "112270659.425022338634864188", "price": "0.112453080943296085", "tokenContractAddress": "CreiuhfwdWCN5mJbMJtA9bBpYQrQF2tCBuZwSPWfpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-CreiuhfwdWCN5mJbMJtA9bBpYQrQF2tCBuZwSPWfpump-108/type=default_90_0?v=1755816193056", "tokenSymbol": "PYTHIA", "txs": "56", "txsBuy": "19", "txsSell": "37", "uniqueTraders": "56", "volume": "19117.57055385588" }, { "chainIndex": "501", "change": "-0.42", "firstTradeTime": "1756804372000", "holders": "270", "liquidity": "30070.913992866852943079", "marketCap": "64294.459498080603907264", "price": "0.000064294531130488", "tokenContractAddress": "Dx6PwhGk3cF5f4mPdwkYbCdjcLanjyG6FEAArZjZpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-Dx6PwhGk3cF5f4mPdwkYbCdjcLanjyG6FEAArZjZpump-108/type=default_90_0?v=1756804376293", "tokenSymbol": "Momo", "txs": "374", "txsBuy": "248", "txsSell": "126", "uniqueTraders": "220", "volume": "35040.437204533404558263" }, { "chainIndex": "501", "change": "-0.43", "firstTradeTime": "1745713919000", "holders": "10846", "liquidity": "2101462.396030390002012024", "marketCap": "25842250.676096884059139112", "price": "0.025847118015564947", "tokenContractAddress": "Ce2gx9KGXJ6C9Mp5b5x1sn9Mg87JwEbrQby4Zqo3pump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-Ce2gx9KGXJ6C9Mp5b5x1sn9Mg87JwEbrQby4Zqo3pump-108/type=default_90_0?v=1756808290961", "tokenSymbol": "neet", "txs": "50", "txsBuy": "24", "txsSell": "26", "uniqueTraders": "29", "volume": "18621.73282791124" }, { "chainIndex": "501", "change": "-0.49", "firstTradeTime": "1703230923000", "holders": "52786", "liquidity": "5858943.200064747689369564", "marketCap": "124161978.041356767015308726", "price": "1.060068672600690647", "tokenContractAddress": "J3NKxxXZcnNiMjKw9hYb2K4LUxgwB6t1FtPtQVsv3KFr", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-J3NKxxXZcnNiMjKw9hYb2K4LUxgwB6t1FtPtQVsv3KFr-106/type=default_90_0?v=1756745050332", "tokenSymbol": "SPX", "txs": "129", "txsBuy": "53", "txsSell": "76", "uniqueTraders": "47", "volume": "18196.113822388101335" }, { "chainIndex": "501", "change": "-0.5", "firstTradeTime": "1714478191000", "holders": "57550", "liquidity": "3503553.575746051059036125", "marketCap": "530496719.612381489082310458", "price": "0.053049866687500575", "tokenContractAddress": "KMNo3nJsBXfcpJTVhZcXLW7RmTwTt4GVFE7suUBo9sS", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/small/501-KMNo3nJsBXfcpJTVhZcXLW7RmTwTt4GVFE7suUBo9sS-106?v=1749233998450", "tokenSymbol": "KMNO", "txs": "253", "txsBuy": "123", "txsSell": "130", "uniqueTraders": "48", "volume": "21196.6704031720328527" }, { "chainIndex": "501", "change": "-0.54", "firstTradeTime": "1701965089000", "holders": "93743", "liquidity": "6351853.047020716817278871", "marketCap": "1864508657.908564052161137277", "price": "1.864509268104291059", "tokenContractAddress": "jtojtomepa8beP8AuQc6eXt5FriJwfFMwQx2v2f9mCL", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-jtojtomepa8beP8AuQc6eXt5FriJwfFMwQx2v2f9mCL-108/type=default_90_0?v=1756766940736", "tokenSymbol": "JTO", "txs": "106", "txsBuy": "46", "txsSell": "60", "uniqueTraders": "35", "volume": "11471.98806288022" }, { "chainIndex": "501", "change": "-0.57", "firstTradeTime": "1701848381000", "holders": "10425", "liquidity": "5206854.952460004468760647", "marketCap": "90198952.749364871048601994", "price": "1.520163211643151287", "tokenContractAddress": "31k88G5Mq7ptbRDf3AM13HAq6wRQHXHikR8hik7wPygk", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-31k88G5Mq7ptbRDf3AM13HAq6wRQHXHikR8hik7wPygk-108/type=default_90_0?v=1756765876705", "tokenSymbol": "GP", "txs": "26", "txsBuy": "11", "txsSell": "15", "uniqueTraders": "14", "volume": "10725.83580580955" }, { "chainIndex": "501", "change": "-0.6", "firstTradeTime": "1702891849000", "holders": "149311", "liquidity": "13804267.909578686266654869", "marketCap": "236992038.376843530541570339", "price": "0.241843609462384847", "tokenContractAddress": "7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr-108/type=default_90_0?v=1756767007492", "tokenSymbol": "POPCAT", "txs": "148", "txsBuy": "71", "txsSell": "77", "uniqueTraders": "50", "volume": "11711.48386228778" }, { "chainIndex": "501", "change": "-0.61", "firstTradeTime": "1701848792000", "holders": "294265", "liquidity": "33329263.884225634242294454", "marketCap": "1824306493.87597123406676769", "price": "3.287049437952254678", "tokenContractAddress": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/small/501-4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R-96?v=1744224535655", "tokenSymbol": "RAY", "txs": "539", "txsBuy": "273", "txsSell": "266", "uniqueTraders": "111", "volume": "60400.3627705018318114" }, { "chainIndex": "501", "change": "-0.62", "firstTradeTime": "1729078788000", "holders": "95584", "liquidity": "5803360.246745414163393397", "marketCap": "207550672.411394344883919785", "price": "0.02075514066089847", "tokenContractAddress": "DBRiDgJAMsM95moTzJs7M9LnkGErpbv9v6CUR1DXnUu5", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/small/501-DBRiDgJAMsM95moTzJs7M9LnkGErpbv9v6CUR1DXnUu5-106?v=1749240674058", "tokenSymbol": "DBR", "txs": "113", "txsBuy": "54", "txsSell": "59", "uniqueTraders": "15", "volume": "17055.080317176320015" }, { "chainIndex": "501", "change": "-0.71", "firstTradeTime": "1701848385000", "holders": "975286", "liquidity": "811399.879835735900498019", "marketCap": "1751976800.434951808784886615", "price": "0.000019909881307969", "tokenContractAddress": "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263-108/type=default_90_0?v=1756765646663", "tokenSymbol": "Bonk", "txs": "265", "txsBuy": "265", "txsSell": "0", "uniqueTraders": "213", "volume": "15084.96875361978736307" }, { "chainIndex": "501", "change": "-0.74", "firstTradeTime": "1729231505000", "holders": "162608", "liquidity": "35810170.652766346474451762", "marketCap": "747248769.328500552903338278", "price": "0.747261461498460346", "tokenContractAddress": "9BB6NFEcjBCtnNLFko2FqVQBq8HHM13kCyYcdQbgpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-9BB6NFEcjBCtnNLFko2FqVQBq8HHM13kCyYcdQbgpump-108/type=default_90_0?v=1756781592095", "tokenSymbol": "Fartcoin ", "txs": "549", "txsBuy": "229", "txsSell": "320", "uniqueTraders": "128", "volume": "66827.413140211020134" }, { "chainIndex": "501", "change": "-0.76", "firstTradeTime": "1722558985000", "holders": "45425", "liquidity": "8502286.136579875528469722", "marketCap": "143008472.947260417584714578", "price": "0.143159614762440338", "tokenContractAddress": "5UUH9RTDiSpq6HKS6bp4NdU9PNJpXRXuiw6ShBTBhgH2", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/small/501-5UUH9RTDiSpq6HKS6bp4NdU9PNJpXRXuiw6ShBTBhgH2-106?v=1749237961825", "tokenSymbol": "TROLL", "txs": "83", "txsBuy": "35", "txsSell": "48", "uniqueTraders": "43", "volume": "54867.87791791286" }, { "chainIndex": "501", "change": "-0.81", "firstTradeTime": "1751192437000", "holders": "11155", "liquidity": "1608642.143027921903636493", "marketCap": "13482727.045170026304288584", "price": "328.860161325617027377", "tokenContractAddress": "XsDoVfqeBukxuZHWhdvWHBhgEHjGNst4MLodqsJHzoB", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-XsDoVfqeBukxuZHWhdvWHBhgEHjGNst4MLodqsJHzoB-108/type=default_90_0?v=1756749927607", "tokenSymbol": "TSLAx", "txs": "112", "txsBuy": "57", "txsSell": "55", "uniqueTraders": "38", "volume": "21528.91910247913" }, { "chainIndex": "501", "change": "-0.87", "firstTradeTime": "1756718017000", "holders": "407", "liquidity": "35810.866178870233151972", "marketCap": "75696.243046482090735767", "price": "0.000075700606752127", "tokenContractAddress": "9SVVzMUkyDX28awzM5tpVjbjLD3oi8GJmnn6tsrYpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-9SVVzMUkyDX28awzM5tpVjbjLD3oi8GJmnn6tsrYpump-108/type=default_90_0?v=1756718019119", "tokenSymbol": "Pebble", "txs": "94", "txsBuy": "44", "txsSell": "50", "uniqueTraders": "43", "volume": "10243.25665267222257715" }, { "chainIndex": "501", "change": "-1", "firstTradeTime": "1754619229000", "holders": "11173", "liquidity": "1054473.765867328481420363", "marketCap": "7556093.467775672399372311", "price": "0.007556279632129639", "tokenContractAddress": "7eMJmn1bYWSQEwxAX7CyngBzGNGu1cT582asKxxRpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-7eMJmn1bYWSQEwxAX7CyngBzGNGu1cT582asKxxRpump-108/type=default_90_0?v=1756481432162", "tokenSymbol": "CLIPPY", "txs": "271", "txsBuy": "125", "txsSell": "146", "uniqueTraders": "66", "volume": "16273.885000164280091802" }, { "chainIndex": "501", "change": "-1.01", "firstTradeTime": "1737689992000", "holders": "18568", "liquidity": "2919307.844092568434327159", "marketCap": "58142655.79440949944109751", "price": "0.058150069607903893", "tokenContractAddress": "Ey59PH7Z4BFU4HjyKnyMdWt5GGN76KazTAwQihoUXRnk", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-Ey59PH7Z4BFU4HjyKnyMdWt5GGN76KazTAwQihoUXRnk-108/type=default_90_0?v=1755820095834", "tokenSymbol": "LAUNCHCOIN", "txs": "225", "txsBuy": "112", "txsSell": "113", "uniqueTraders": "51", "volume": "25909.396403160040107" }, { "chainIndex": "501", "change": "-1.1", "firstTradeTime": "1742834682000", "holders": "23023", "liquidity": "1696270.146705075984180152", "marketCap": "13179281.388774324581150843", "price": "0.013197418046766592", "tokenContractAddress": "DitHyRMQiSDhn5cnKMJV2CDDt6sVct96YrECiM49pump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-DitHyRMQiSDhn5cnKMJV2CDDt6sVct96YrECiM49pump-108/type=default_90_0?v=1756733850056", "tokenSymbol": "House", "txs": "61", "txsBuy": "39", "txsSell": "22", "uniqueTraders": "39", "volume": "12521.11707455585051005" }, { "chainIndex": "501", "change": "-1.15", "firstTradeTime": "1756677244000", "holders": "4282", "liquidity": "496130.868074816683066771", "marketCap": "2667539.196191917194379295", "price": "0.002667730535593812", "tokenContractAddress": "48TqCgU8zC2H5tWshNriY2bWHDULSTSvdgL4iP1Fpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-48TqCgU8zC2H5tWshNriY2bWHDULSTSvdgL4iP1Fpump-108/type=default_90_0?v=1756677317150", "tokenSymbol": "holo", "txs": "171", "txsBuy": "75", "txsSell": "96", "uniqueTraders": "102", "volume": "18745.667712469031174809" }, { "chainIndex": "501", "change": "-1.27", "firstTradeTime": "1746886853000", "holders": "34420", "liquidity": "11260169.491934699438490084", "marketCap": "167290087.625995830265953066", "price": "0.167442262985240444", "tokenContractAddress": "Dz9mQ9NzkBcCsuGPFJ3r1bS4wgqKMHBPiVuniW8Mbonk", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-Dz9mQ9NzkBcCsuGPFJ3r1bS4wgqKMHBPiVuniW8Mbonk-108/type=default_90_0?v=1755845114460", "tokenSymbol": "USELESS", "txs": "172", "txsBuy": "68", "txsSell": "104", "uniqueTraders": "59", "volume": "17808.633933166034474" }, { "chainIndex": "501", "change": "-1.43", "firstTradeTime": "1754379336000", "holders": "14613", "liquidity": "2516732.530501292817960534", "marketCap": "24461578.138047018165041247", "price": "0.024462998608412244", "tokenContractAddress": "5zCETicUCJqJ5Z3wbfFPZqtSpHPYqnggs1wX7ZRpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-5zCETicUCJqJ5Z3wbfFPZqtSpHPYqnggs1wX7ZRpump-108/type=default_90_0?v=1756687273181", "tokenSymbol": "SPARK", "txs": "299", "txsBuy": "154", "txsSell": "145", "uniqueTraders": "79", "volume": "84389.556859371030010312" }, { "chainIndex": "501", "change": "-2.1", "firstTradeTime": "1745506318000", "holders": "12086", "liquidity": "3933535.672255125919287143", "marketCap": "59930195.030363686046966601", "price": "0.06402345574464", "tokenContractAddress": "C29ebrgYjYoJPMGPnPSGY1q3mMGk4iDSqnQeQQA7moon", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-C29ebrgYjYoJPMGPnPSGY1q3mMGk4iDSqnQeQQA7moon-108/type=default_90_0?v=1756807428925", "tokenSymbol": "NOBODY", "txs": "188", "txsBuy": "59", "txsSell": "129", "uniqueTraders": "32", "volume": "24223.3289374815905103" }, { "chainIndex": "501", "change": "-2.19", "firstTradeTime": "1751611293000", "holders": "5771", "liquidity": "597811.858973478296588652", "marketCap": "5116626.441902262625552977", "price": "0.005117849016896625", "tokenContractAddress": "83kGGSggYGP2ZEEyvX54SkZR1kFn84RgGCDyptbDbonk", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-83kGGSggYGP2ZEEyvX54SkZR1kFn84RgGCDyptbDbonk-108/type=default_90_0?v=1755855055960", "tokenSymbol": "旺柴", "txs": "65", "txsBuy": "38", "txsSell": "27", "uniqueTraders": "44", "volume": "12660.95416320661204006" }, { "chainIndex": "501", "change": "-2.45", "firstTradeTime": "1715231153000", "holders": "4341", "liquidity": "655556.367757539521897327", "marketCap": "4487750.842648499327760551", "price": "0.005010844496677946", "tokenContractAddress": "7oLWGMuGbBm9uwDmffSdxLE98YChFAH1UdY5XpKYLff8", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-7oLWGMuGbBm9uwDmffSdxLE98YChFAH1UdY5XpKYLff8-106/type=default_90_0?v=1756747552994", "tokenSymbol": "WOJAK", "txs": "111", "txsBuy": "78", "txsSell": "33", "uniqueTraders": "65", "volume": "22739.28640933544044545" }, { "chainIndex": "501", "change": "-2.45", "firstTradeTime": "1711333572000", "holders": "23462", "liquidity": "3145356.641734818850872981", "marketCap": "26541878.023917293620312702", "price": "0.026543867455616667", "tokenContractAddress": "GtDZKAqvMZMnti46ZewMiXCa4oXF4bZxwQPoKzXPFxZn", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-GtDZKAqvMZMnti46ZewMiXCa4oXF4bZxwQPoKzXPFxZn-108/type=default_90_0?v=1756770194154", "tokenSymbol": "nub", "txs": "30", "txsBuy": "13", "txsSell": "17", "uniqueTraders": "15", "volume": "14508.10337875355" }, { "chainIndex": "501", "change": "-2.46", "firstTradeTime": "1756728000000", "holders": "23010", "liquidity": "10296833.97978188316813947", "marketCap": "80514822.620035993800511383", "price": "0.228971021261937605", "tokenContractAddress": "WLFinEv6ypjkczcS83FZqFpgFZYwQXutRbxGe7oC16g", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-WLFinEv6ypjkczcS83FZqFpgFZYwQXutRbxGe7oC16g-107/type=default_90_0?v=1756816967011", "tokenSymbol": "WLFI", "txs": "864", "txsBuy": "266", "txsSell": "598", "uniqueTraders": "154", "volume": "391738.54038637512634855" }, { "chainIndex": "501", "change": "-2.69", "firstTradeTime": "1745617855000", "holders": "13651", "liquidity": "1241635.813449274005351253", "marketCap": "9092277.01728385125494646", "price": "0.009102872708143264", "tokenContractAddress": "GkyPYa7NnCFbduLknCfBfP7p8564X1VZhwZYJ6CZpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-GkyPYa7NnCFbduLknCfBfP7p8564X1VZhwZYJ6CZpump-108/type=default_90_0?v=1755841994349", "tokenSymbol": "CHILLHOUSE", "txs": "25", "txsBuy": "17", "txsSell": "8", "uniqueTraders": "16", "volume": "19481.12160467637009" }, { "chainIndex": "501", "change": "-2.7", "firstTradeTime": "1747141893000", "holders": "12403", "liquidity": "1293840.933359991871930738", "marketCap": "14129110.880164326541121501", "price": "0.014130889780118507", "tokenContractAddress": "HtTYHz1Kf3rrQo6AqDLmss7gq5WrkWAaXn3tupUZbonk", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-HtTYHz1Kf3rrQo6AqDLmss7gq5WrkWAaXn3tupUZbonk-108/type=default_90_0?v=1756811233784", "tokenSymbol": "KORI", "txs": "233", "txsBuy": "95", "txsSell": "138", "uniqueTraders": "92", "volume": "40575.74616474066207482" }, { "chainIndex": "501", "change": "-3.44", "firstTradeTime": "1756295122000", "holders": "6632", "liquidity": "516287.402115277434729202", "marketCap": "3583165.429817142192045831", "price": "0.003583315024744681", "tokenContractAddress": "3vz82EWYv8xnc7Cm7qSgERcpMeqw92PcX8PBz88npump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-3vz82EWYv8xnc7Cm7qSgERcpMeqw92PcX8PBz88npump-108/type=default_90_0?v=1756295123756", "tokenSymbol": "USDUT", "txs": "122", "txsBuy": "48", "txsSell": "74", "uniqueTraders": "72", "volume": "12924.92522779911036556" }, { "chainIndex": "501", "change": "-3.5", "firstTradeTime": "1756789254000", "holders": "415", "liquidity": "47505.885217617230776031", "marketCap": "130852.710532865239185882", "price": "0.000130854982052018", "tokenContractAddress": "AYFwa6B2vHeKzbGEMDaQckw9BXbgSve5BBbmtodhpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-AYFwa6B2vHeKzbGEMDaQckw9BXbgSve5BBbmtodhpump-108/type=default_90_0?v=1756789256837", "tokenSymbol": "Adrian", "txs": "128", "txsBuy": "63", "txsSell": "65", "uniqueTraders": "84", "volume": "12562.45111815591207465" }, { "chainIndex": "501", "change": "-4.09", "firstTradeTime": "1750286928000", "holders": "18107", "liquidity": "1263144.004142219998684378", "marketCap": "9444736.549621072495087447", "price": "0.009445293062751946", "tokenContractAddress": "71Jvq4Epe2FCJ7JFSF7jLXdNk1Wy4Bhqd9iL6bEFELvg", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-71Jvq4Epe2FCJ7JFSF7jLXdNk1Wy4Bhqd9iL6bEFELvg-108/type=default_90_0?v=1755773268187", "tokenSymbol": "GOR", "txs": "165", "txsBuy": "107", "txsSell": "58", "uniqueTraders": "43", "volume": "18800.208422415130128703" }, { "chainIndex": "501", "change": "-4.5", "firstTradeTime": "1756490781000", "holders": "5965", "liquidity": "356885.563820142810387406", "marketCap": "1318623.454727214186783899", "price": "0.001318698331757437", "tokenContractAddress": "4JPyh4ATbE8hfcH7LqhxF3YThsECZm6htmLvMUyrbonk", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-4JPyh4ATbE8hfcH7LqhxF3YThsECZm6htmLvMUyrbonk-108/type=default_90_0?v=1756763606824", "tokenSymbol": "Eagle", "txs": "165", "txsBuy": "91", "txsSell": "74", "uniqueTraders": "85", "volume": "21569.36897841580255085" }, { "chainIndex": "501", "change": "-4.63", "firstTradeTime": "1756805684000", "holders": "3165", "liquidity": "61347.543877642551777517", "marketCap": "247636.112329224807801974", "price": "0.000247636112329388", "tokenContractAddress": "AD8UhEiEyztbceknCQ2reeAWyRxcB8F2d9yUuXUNpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-AD8UhEiEyztbceknCQ2reeAWyRxcB8F2d9yUuXUNpump-108/type=default_90_0?v=1756805686898", "tokenSymbol": "FROGI", "txs": "1412", "txsBuy": "765", "txsSell": "647", "uniqueTraders": "308", "volume": "25972.315008990893403758" }, { "chainIndex": "501", "change": "-5.03", "firstTradeTime": "1756564230000", "holders": "4920", "liquidity": "516484.426491865407166872", "marketCap": "1880832.02191478958343709", "price": "0.001880871926740969", "tokenContractAddress": "B9iPvm8YybydhvMiKAuJuygEKuzspgxdavhFNzzUpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-B9iPvm8YybydhvMiKAuJuygEKuzspgxdavhFNzzUpump-108/type=default_90_0?v=1756564233200", "tokenSymbol": "EMULITES", "txs": "352", "txsBuy": "224", "txsSell": "128", "uniqueTraders": "163", "volume": "50315.418761854402779749" }, { "chainIndex": "501", "change": "-5.35", "firstTradeTime": "1752268905000", "holders": "3610", "liquidity": "439086.606281285638490144", "marketCap": "3733332.427739275309307035", "price": "0.003733447970943229", "tokenContractAddress": "5EaYZcaKfTVdpQ2avVtJ7BNWJ1Rnj86F1dWxppawpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-5EaYZcaKfTVdpQ2avVtJ7BNWJ1Rnj86F1dWxppawpump-108/type=default_90_0?v=1755856779013", "tokenSymbol": "dollo", "txs": "41", "txsBuy": "26", "txsSell": "15", "uniqueTraders": "25", "volume": "20205.448063214531132447" }, { "chainIndex": "501", "change": "-5.68", "firstTradeTime": "1727855513000", "holders": "9024", "liquidity": "505324.108266182660900249", "marketCap": "2119299.095285223227765242", "price": "0.0021194201573712", "tokenContractAddress": "mkvXiNBpa8uiSApe5BrhWVJaT87pJFTZxRy7zFapump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-mkvXiNBpa8uiSApe5BrhWVJaT87pJFTZxRy7zFapump-108/type=default_90_0?v=1755807007444", "tokenSymbol": "Nailong", "txs": "69", "txsBuy": "53", "txsSell": "16", "uniqueTraders": "35", "volume": "13735.83322517981060821" }, { "chainIndex": "501", "change": "-7.18", "firstTradeTime": "1756745922000", "holders": "2277", "liquidity": "125673.405953846301227689", "marketCap": "433094.743697150096342215", "price": "0.000433242457286127", "tokenContractAddress": "6DEa18xxCgx2SgBTJbFdEY6PTNZMWvG2nDv47LHspump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-6DEa18xxCgx2SgBTJbFdEY6PTNZMWvG2nDv47LHspump-108/type=default_90_0?v=1756745925687", "tokenSymbol": "glub", "txs": "915", "txsBuy": "483", "txsSell": "432", "uniqueTraders": "398", "volume": "89242.270921917407228658" }, { "chainIndex": "501", "change": "-7.21", "firstTradeTime": "1756779154000", "holders": "2513", "liquidity": "186284.518433526477916523", "marketCap": "675616.952310451768476353", "price": "0.000675622501838361", "tokenContractAddress": "AtPNZ3Rwcezea16xkjkxULzCMKpSbS2rVEirVfzrnEa6", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-AtPNZ3Rwcezea16xkjkxULzCMKpSbS2rVEirVfzrnEa6-108/type=default_90_0?v=1756779155981", "tokenSymbol": "GOLD", "txs": "530", "txsBuy": "299", "txsSell": "231", "uniqueTraders": "276", "volume": "38496.14223413013762555" }, { "chainIndex": "501", "change": "-8.05", "firstTradeTime": "1756734017000", "holders": "1864", "liquidity": "81784.542682646989471842", "marketCap": "288276.693103112970979955", "price": "0.000288305376983988", "tokenContractAddress": "4CmYCPDzU22ck8hT6AiPVk2iTHg9SeYtPCXZNuonpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-4CmYCPDzU22ck8hT6AiPVk2iTHg9SeYtPCXZNuonpump-108/type=default_90_0?v=1756734020238", "tokenSymbol": "amuricah", "txs": "602", "txsBuy": "346", "txsSell": "256", "uniqueTraders": "331", "volume": "63409.016081975042647226" }, { "chainIndex": "501", "change": "-8.93", "firstTradeTime": "1756765281000", "holders": "351", "liquidity": "73235.742614179186571261", "marketCap": "364045.907449118020746898", "price": "0.000364046772554586", "tokenContractAddress": "A9ga87pYeS59BDrNn9J1c9cZYaZm32MnoBfVVX1Kbonk", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-A9ga87pYeS59BDrNn9J1c9cZYaZm32MnoBfVVX1Kbonk-108/type=default_90_0?v=1756765283532", "tokenSymbol": "ODUNG", "txs": "51", "txsBuy": "34", "txsSell": "17", "uniqueTraders": "24", "volume": "10736.23938131995344191" }, { "chainIndex": "501", "change": "-9.31", "firstTradeTime": "1754389610000", "holders": "2078", "liquidity": "295868.865047378718109424", "marketCap": "2485397.764263724383871199", "price": "0.002485441523727923", "tokenContractAddress": "5oY7mmN5yiBRF2Fq3c4fhftTEsPykHcA5X5G52tpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-5oY7mmN5yiBRF2Fq3c4fhftTEsPykHcA5X5G52tpump-108/type=default_90_0?v=1756756864831", "tokenSymbol": "TANAKI", "txs": "100", "txsBuy": "65", "txsSell": "35", "uniqueTraders": "60", "volume": "34529.708760932052287" }, { "chainIndex": "501", "change": "-9.96", "firstTradeTime": "1756816421000", "holders": "116", "liquidity": "121763.082950017535606366", "marketCap": "79754.762192230435318303", "price": "0.000079754955713241", "tokenContractAddress": "DCQS1i4tLFUW4nb74K3316A4oZjJuvMpqtGgPEVTJKEz", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-DCQS1i4tLFUW4nb74K3316A4oZjJuvMpqtGgPEVTJKEz-108/type=default_90_0?v=1756816314485", "tokenSymbol": "me", "txs": "654", "txsBuy": "395", "txsSell": "259", "uniqueTraders": "98", "volume": "122880.27885707160108721" }, { "chainIndex": "501", "change": "-10.87", "firstTradeTime": "1756480719000", "holders": "1784", "liquidity": "189608.651422160472799041", "marketCap": "1277767.873268989538155662", "price": "0.0012777887763542", "tokenContractAddress": "EmNFqmSi5DvwGjW57LJ7J5i8R6T155JrNf6GNFaupump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-EmNFqmSi5DvwGjW57LJ7J5i8R6T155JrNf6GNFaupump-108/type=default_90_0?v=1756763563015", "tokenSymbol": "JELLY", "txs": "168", "txsBuy": "82", "txsSell": "86", "uniqueTraders": "86", "volume": "32542.75899398449197982" }, { "chainIndex": "501", "change": "-12.81", "firstTradeTime": "1756785911000", "holders": "2532", "liquidity": "79767.256895909643750498", "marketCap": "408375.18757308446409794", "price": "0.000408375492159385", "tokenContractAddress": "2ubH6Na9xWxXBWfNfQYqSvqLPUXRdEdAgCUcHXCKpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-2ubH6Na9xWxXBWfNfQYqSvqLPUXRdEdAgCUcHXCKpump-108/type=default_90_0?v=1756785914910", "tokenSymbol": "NOSTALGIC", "txs": "450", "txsBuy": "256", "txsSell": "194", "uniqueTraders": "260", "volume": "40163.41098417165259315" }, { "chainIndex": "501", "change": "-13.03", "firstTradeTime": "1756796469000", "holders": "554", "liquidity": "29174.962758075288045483", "marketCap": "55475.546909914133751213", "price": "0.000055479365786075", "tokenContractAddress": "GRagLc7DcKGDXzULb25sz1RosCGcFHxgwxfMHsBpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-GRagLc7DcKGDXzULb25sz1RosCGcFHxgwxfMHsBpump-108/type=default_90_0?v=1756796472442", "tokenSymbol": "Dolly", "txs": "125", "txsBuy": "64", "txsSell": "61", "uniqueTraders": "60", "volume": "10937.30595484825788278" }, { "chainIndex": "501", "change": "-13.83", "firstTradeTime": "1756816450000", "holders": "65", "liquidity": "8850.053033772716193756", "marketCap": "14294.045258173", "price": "0.000014294045258173", "tokenContractAddress": "Cd9EPGNJyrSG9wyiQaRyXatkX2vVg44eCLAFBS6pump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-Cd9EPGNJyrSG9wyiQaRyXatkX2vVg44eCLAFBS6pump-108/type=default_90_0?v=1756816451633", "tokenSymbol": "CGI DOG", "txs": "256", "txsBuy": "136", "txsSell": "120", "uniqueTraders": "89", "volume": "16153.267985670552360886" }, { "chainIndex": "501", "change": "-18.82", "firstTradeTime": "1756809935000", "holders": "97", "liquidity": "79803.957048358863262069", "marketCap": "446248.621397709107502757", "price": "0.00044624862139771", "tokenContractAddress": "LdoYUMkHx6q66tWrRL2JC3v4pxFLmEWPiEpr8Mwpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/default-logo/token_custom_logo_default_M.png/type=default_350_0", "tokenSymbol": "MOONA", "txs": "32", "txsBuy": "17", "txsSell": "15", "uniqueTraders": "23", "volume": "11397.852383019803915" }, { "chainIndex": "501", "change": "-20.84", "firstTradeTime": "1756816421000", "holders": "47", "liquidity": "7360.630200713482085332", "marketCap": "10735.564277107", "price": "0.000010576363657773", "tokenContractAddress": "ChC664uyhaAS99tzVeD2vGX42EMKwBtSFwmBRzkJpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-ChC664uyhaAS99tzVeD2vGX42EMKwBtSFwmBRzkJpump-108/type=default_90_0?v=1756816423196", "tokenSymbol": "ATH", "txs": "172", "txsBuy": "85", "txsSell": "87", "uniqueTraders": "93", "volume": "19906.842808052472074143" }, { "chainIndex": "501", "change": "-24.8", "firstTradeTime": "1756816912000", "holders": "472", "liquidity": "26954.545956648982275443", "marketCap": "49848.60504948525525969", "price": "0.000049848607003814", "tokenContractAddress": "4wyFWsArUxww5W7UeV9eX6dyTK9Fcs7jHqdgmtTgpump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-4wyFWsArUxww5W7UeV9eX6dyTK9Fcs7jHqdgmtTgpump-108/type=default_90_0?v=1756816916092", "tokenSymbol": "Froggy", "txs": "3153", "txsBuy": "1768", "txsSell": "1385", "uniqueTraders": "1019", "volume": "292913.969890403630310861" }, { "chainIndex": "501", "change": "-28.26", "firstTradeTime": "1756762309000", "holders": "394", "liquidity": "26411.512409531919753611", "marketCap": "49729.906715517", "price": "0.000049729906715517", "tokenContractAddress": "7qjzyCpUz5LJR4TXAemmTfnTi1Dc5HSjJaeHzEZ5bonk", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-7qjzyCpUz5LJR4TXAemmTfnTi1Dc5HSjJaeHzEZ5bonk-108/type=default_90_0?v=1756764854568", "tokenSymbol": "stables", "txs": "297", "txsBuy": "178", "txsSell": "119", "uniqueTraders": "179", "volume": "27897.660471127695696613" }, { "chainIndex": "501", "change": "-34.02", "firstTradeTime": "1756815969000", "holders": "332", "liquidity": "20211.113356577161234324", "marketCap": "28154.26322336176601633", "price": "0.000028157411373228", "tokenContractAddress": "QDUjVq2v8vrim1r42JSogYTBE4mUmmozjG7yaYWbonk", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-QDUjVq2v8vrim1r42JSogYTBE4mUmmozjG7yaYWbonk-108/type=default_90_0?v=1756815970615", "tokenSymbol": "Diamond", "txs": "386", "txsBuy": "195", "txsSell": "191", "uniqueTraders": "226", "volume": "27539.131577861225665" }, { "chainIndex": "501", "change": "-47.57", "firstTradeTime": "1756812385000", "holders": "159", "liquidity": "105925.098946947236923891", "marketCap": "2809857749.04907474", "price": "0.280985774904907474", "tokenContractAddress": "DJ7zwo9saEsV8prLmNvBFRu54gBGP43NynnMvmfnSyvS", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-DJ7zwo9saEsV8prLmNvBFRu54gBGP43NynnMvmfnSyvS-108/type=default_90_0?v=1756812248721", "tokenSymbol": "ELONCOIN", "txs": "455", "txsBuy": "342", "txsSell": "113", "uniqueTraders": "101", "volume": "26649.377739254010002" }, { "chainIndex": "501", "change": "-52.61", "firstTradeTime": "1730082694000", "holders": "244", "liquidity": "38860.28626545654522376", "marketCap": "106503.583893530580067963", "price": "0.000107055341658189", "tokenContractAddress": "HNhLKtM2K2P7Acxf1xyeJVLUTdwHchBrf42QNEsppump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-HNhLKtM2K2P7Acxf1xyeJVLUTdwHchBrf42QNEsppump-108/type=default_90_0?v=1756782555307", "tokenSymbol": "PS2", "txs": "455", "txsBuy": "406", "txsSell": "49", "uniqueTraders": "406", "volume": "30134.509466349618252" }, { "chainIndex": "501", "change": "-62.88", "firstTradeTime": "1756803271000", "holders": "1079", "liquidity": "27372.849941049145040546", "marketCap": "49497.441666679084478244", "price": "0.000049497441981376", "tokenContractAddress": "2m6cXUkHEpD2KHFovxcdS9uzTKcCbMVav3Yj77mipump", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-2m6cXUkHEpD2KHFovxcdS9uzTKcCbMVav3Yj77mipump-108/type=default_90_0?v=1756803273339", "tokenSymbol": "RISK", "txs": "1244", "txsBuy": "721", "txsSell": "523", "uniqueTraders": "501", "volume": "75903.9784426482111411" }, { "chainIndex": "501", "change": "-89.07", "firstTradeTime": "1756815652000", "holders": "214", "liquidity": "17420.304672664309894505", "marketCap": "131930065.934370751044168882", "price": "0.131930065803863551", "tokenContractAddress": "CSm2gkq8AYWCppbkf5EbUV1TsutjKmZzCnLtTSH4md6e", "tokenLogoUrl": "https://static.oklink.com/cdn/web3/currency/token/large/501-CSm2gkq8AYWCppbkf5EbUV1TsutjKmZzCnLtTSH4md6e-108/type=default_90_0?v=1756815587054", "tokenSymbol": "Copilot", "txs": "1715", "txsBuy": "1528", "txsSell": "187", "uniqueTraders": "195", "volume": "65825.8872477378500025" } ], "msg": "" } ```
- [Top Token Holder](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-market-token-holder.md) {/* api-page */} # Top Token Holder Return Top 20 holder addresses and specific token holding amount. ### Request URL GET `https://web3.okx.com/api/v6/dex/market/token/holder` ## Request Parameters | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). | | tokenContractAddress | String | Yes | Token contract address (e.g., 0x382bb369d343125bfb2117af9c149795c6c65c50) |
## Response Parameters | Parameter | Type | Description | |--------------------- |-------- |--------------------------------------------------------- | | holdAmount | String | Number of tokens the holder holds on the specific token | | holderWalletAddress | String | Wallet address of the token holder |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/market/token/holder?chainIndex=501&tokenContractAddress=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "holdAmount": "570747950.108575", "holderWalletAddress": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM" }, { "holdAmount": "500000000.001", "holderWalletAddress": "3gd3dqgtJ4jWfBfLYTX67DALFetjc5iS72sCgRhCkW2u" }, { "holdAmount": "403111293.236032", "holderWalletAddress": "AVzP2GeRmqGphJsMxWoqjpUifPpCret7LqWhD8NWQK49" }, { "holdAmount": "272206237.244708", "holderWalletAddress": "7VHUFJHWu2CuExkJcJrzhQPJ2oygupTWkL2A2For4BmE" }, { "holdAmount": "259027606.450607", "holderWalletAddress": "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" }, { "holdAmount": "252904995.765205", "holderWalletAddress": "9d9mb8kooFfaD3SctgZtkxQypkshx6ezhbKio89ixyy2" }, { "holdAmount": "113506938.878224", "holderWalletAddress": "FWznbcNXWQuHTawe9RxvQ2LdCENssh12dsznf4RiouN5" }, { "holdAmount": "101985136.043764", "holderWalletAddress": "DBD8hAwLDRQkTsu6EqviaYNGKPnsAMmQonxf7AH8ZcFY" }, { "holdAmount": "73752706.890644", "holderWalletAddress": "6FEVkH17P9y8Q9aCkDdPcMDjvj7SVxrTETaYEm8f51Jy" }, { "holdAmount": "72838497.992745", "holderWalletAddress": "3csuXZKah5rgpb8RiwX9XfjrMxcp3u1K9mBdCwL51spj" }, { "holdAmount": "66079266.10245", "holderWalletAddress": "B9spsrMK6pJicYtukaZzDyzsUQLgc3jbx5gHVwdDxb6y" }, { "holdAmount": "63824158.64382", "holderWalletAddress": "7MNeJP9gi5kBY1DVzJA1kzdeCr6oscXEZW51XMnmByC7" }, { "holdAmount": "63539584.430483", "holderWalletAddress": "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" }, { "holdAmount": "55351694.338679", "holderWalletAddress": "6iyaZw4aLJhmh2WXydrDw4poX1uzeu2UDfSatCwqmzPA" }, { "holdAmount": "51465340.60226", "holderWalletAddress": "F6ZjiBm1WgVXzez5vxHeBDgaVPQRfLyFb7GFwXvyZVxD" }, { "holdAmount": "50916839.714253", "holderWalletAddress": "9un5wqE3q4oCjyrDkwsdD48KteCJitQX5978Vh7KKxHo" }, { "holdAmount": "49730509.851315", "holderWalletAddress": "4kWwg9hQri1aFVqjxayDVmjmYtjXjrf1h5TpfvvAk5Sm" }, { "holdAmount": "44593888.562", "holderWalletAddress": "61yKS9bjxWdqNgAHt439DfoNfwK3uKPAJGWAsFkC5M4C" }, { "holdAmount": "39477953.030487", "holderWalletAddress": "F5aW6AUHn74rwpU6wS6PT77FrXWCfKcT7jX26fpbE635" }, { "holdAmount": "36288729.399797", "holderWalletAddress": "AS5MV3ear4NZPMWXbCsEz3AdbCaXEnq4ChdaWsvLgkcM" } ], "msg": "" } ```
- [Error Codes](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-market-token-error-code.md) # Error Codes | Code | HTTP status | Message | |-------|-------------|-----------------------------------------------------------------------------------------| | 0 | 200 | Succeeded | | 50011 | 429 | Rate limit reached. Please refer to API documentation and throttle requests accordingly | | 50014 | 400 | Parameter \{param0\} cannot be empty | | 50026 | 500 | System error. Try again later | | 50103 | 401 | Request header "OK-ACCESS-KEY" cannot be empty | | 50104 | 401 | Request header "OK-ACCESS-PASSPHRASE" cannot be empty| | 50105 | 401 | Request header "OK-ACCESS-PASSPHRASE" incorrect | | 50106 | 401 | Request header "OK-ACCESS-SIGN" cannot be empty | | 50107 | 401 | Request header "OK-ACCESS-TIMESTAMP" cannot be empty | | 50111 | 401 | Invalid OK-ACCESS-KEY | | 50112 | 401 | Invalid OK-ACCESS-TIMESTAMP | | 50113 | 401 | Invalid signature | | 51000 | 400 | Parameter \{param0\} error | - [Balance API Reference](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-balance-reference.md) # Balance API Reference - [Get Supported Chains](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-balance-chains.md) {/* api-page */} # Get Supported Chains Retrieve information on chains supported by the DEX Balance endpoint ### Request URL GET `https://web3.okx.com/api/v6/dex/balance/supported/chain` ## Request Parameters None ## Response Parameters | Parameter | Type | Description | |-----------|--------|-------------------| | name | String | Chain name | | logoUrl | String | Chain logo URL | | shortName | String | Chain short name | | chainIndex| String | Chain unique identifier | ## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/balance/supported/chain' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "name": "Ethereum", "logoUrl": "http://www.eth.org/eth.png", "shortName": "ETH", "chainIndex": "1" } ], "msg": "" } ``` - [Get Total Value](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-balance-total-value.md) {/* api-page */} # Get Total Value Retrieve the total balance of all tokens and DeFi assets under an account. ### Request URL GET `https://web3.okx.com/api/v6/dex/balance/total-value-by-address` ## Request Parameters | Parameter | Type | Required | Description | | ------------------| ------- | -------- | ------------------------------------------------------------------ | | address | String | Yes | Get the total valuation for the address | | chains | String | Yes | Filter chains for which to query total assets, separated by ",". Supports up to 50 chains..
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). | | assetType | String | No | Query balance type. Default is to query all asset balances.
`0`: Query total balance for all assets, including tokens and DeFi assets.
`1`: Query only token balance.
`2`: Query only DeFi balance. | | excludeRiskToken | Boolean | No | Option to filter out risky airdrop & honeypot tokens. Default is to filter.
`true`: filter out, `false`: do not filter out
It supports only `ETH`、`BSC`、`SOL`、`BASE` for honeypot tokens, more chains will be supported soon. |
## Response Parameters | Parameter | Type | Description | | --- | --- | --- | | totalValue | String | Total asset balance based on the query type, returned in USD |
## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/balance/total-value-by-address?address=0x0b32aa5c1e71715206fe29b7badb21ad95f272c0&chains=1&assetType=0' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ``` json { "code": "0", "msg": "success", "data": [ { "totalValue": "1172.895057177065864522056725546579939398" } ] } ```
- [Get Total Token Balances](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-balance-total-token-balances.md) {/* api-page */} # Get Total Token Balances Retrieve the list of token balances for an address across multiple chains or specified chains. ### Request URL GET `https://web3.okx.com/api/v6/dex/balance/all-token-balances-by-address` ## Request Parameters | Parameter | Type | Required | Description | |----------------|--------|----------|-----------------------------------------| | address | String | Yes | Address | | chains | Array | Yes | When filtering the chains for querying asset details, multiple chains should be separated by commas (`,`). A maximum of 50 chains is supported.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain).| | excludeRiskToken | String | No | Option to filter out risky airdrop & honeypot tokens. Default is to filter.
`0`: Filter out
`1`: Do not filter out
It supports only `ETH`、`BSC`、`SOL`、`BASE` for honeypot tokens, more chains will be supported soon. |
## Response Parameters | Parameter | Type | Description | |---------------|--------|------------------------------------------| | tokenAssets | Array | List of token balances | | >chainIndex | String | Unique identifier for the chain | | >tokenContractAddress | String | Contract address | | >address | String | Address | | >symbol | String | Token symbol | | >balance | String | Token balance | | >rawBalance | String | Raw balance of token address. For unsupported chains, this field is empty. More chains will be supported soon. | | >tokenPrice | String | Token unit value, priced in USD | | >isRiskToken | Boolean| `true`: flagged as a risky airdrop & honeypot token
`false`: not flagged as a risky airdrop & honeypot token |
## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/balance/all-token-balances-by-address?address=0xEd0C6079229E2d407672a117c22b62064f4a4312&chains=1' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ``` json { "code": "0", "msg": "success", "data": [ { "tokenAssets": [ { "chainIndex": "1", "tokenContractAddress": "0x386ae941d4262b0ee96354499df2ab8442734ec0", "symbol": "PT-sUSDE-27FEB2025", "balance": "47042180.520700015", "tokenPrice": "0.968391562089677097", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0", "symbol": "wstETH", "balance": "7565.892480395067", "tokenPrice": "4321.611627695311", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", "symbol": "WBTC", "balance": "329.10055205", "tokenPrice": "98847.8", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x23878914efe38d27c4d67ab83ed1b93a74d4086a", "symbol": "aEthUSDT", "balance": "30057379.938443", "tokenPrice": "0.99978", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x657e8c867d8b37dcc18fa4caead9c45eb088c642", "symbol": "eBTC", "balance": "271.94970471", "tokenPrice": "99094.345321371", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8", "symbol": "aEthWETH", "balance": "6080.001975381972", "tokenPrice": "3634.32", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xe00bd3df25fb187d6abbb620b3dfd19839947b81", "symbol": "PT-sUSDE-27MAR2025", "balance": "19016580.895408865", "tokenPrice": "0.952031186961110727", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xa17581a9e3356d9a858b789d68b4d866e593ae94", "symbol": "cWETHv3", "balance": "3000.000734740809", "tokenPrice": "3663.74", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x9d39a5de30e57443bff2a8307a4256c8797a3497", "symbol": "sUSDe", "balance": "4863500.628333919", "tokenPrice": "1.144688569528375454", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xec5a52c685cc3ad79a6a347abace330d69e0b1ed", "symbol": "PT-LBTC-27MAR2025", "balance": "46.02912324", "tokenPrice": "97165.169717785655331396", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x8236a87084f8b84306f72007f36f2618a5634494", "symbol": "LBTC", "balance": "38.09998", "tokenPrice": "99187.19184268864", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xbeef047a543e45807105e51a8bbefcc5950fcfba", "symbol": "steakUSDT", "balance": "482651.8612595832", "tokenPrice": "1.063", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x4c9edd5852cd905f086c759e8383e09bff1e68b3", "symbol": "USDe", "balance": "69564", "tokenPrice": "0.99977", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x8be3460a480c80728a8c4d7a5d5303c85ba7b3b9", "symbol": "sENA", "balance": "42294.989425", "tokenPrice": "1.19", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "", "symbol": "ETH", "balance": "8.135546539084933", "tokenPrice": "3638.63", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xbf5495efe5db9ce00f80364c8b423567e58d2110", "symbol": "ezETH", "balance": "5.270854886240325", "tokenPrice": "3763.152404188635320082", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x6b175474e89094c44da98b954eedeac495271d0f", "symbol": "DAI", "balance": "1196.2693184870445", "tokenPrice": "1.0002", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xc00e94cb662c3520282e6f5717214004a7f26888", "symbol": "COMP", "balance": "0.007643", "tokenPrice": "84.43345772756197", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x9abfc0f085c82ec1be31d30843965fcc63053ffe", "symbol": "Q*", "balance": "900", "tokenPrice": "0.000419255747329174", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xa1290d69c65a6fe4df752f95823fae25cb99e5a7", "symbol": "rsETH", "balance": "0.00007090104120006", "tokenPrice": "3765.640772858747921444", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x56015bbe3c01fe05bc30a8a9a9fd9a88917e7db3", "symbol": "CAT", "balance": "0.42", "tokenPrice": "0.06242994543936436", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xec53bf9167f50cdeb3ae105f56099aaab9061f83", "symbol": "EIGEN", "balance": "0.002496149915967488", "tokenPrice": "4.018538365202288", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x58d97b57bb95320f9a05dc918aef65434969c2b2", "symbol": "MORPHO", "balance": "0.001409373661132556", "tokenPrice": "3.3568669630371337", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xaf5191b0de278c7286d6c7cc6ab6bb8a73ba2cd6", "symbol": "STG", "balance": "0.000009547670354338", "tokenPrice": "0.49707759500034454", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xba3335588d9403515223f109edc4eb7269a9ab5d", "symbol": "GEAR", "balance": "0.000009005734110189", "tokenPrice": "0.012329598382413718", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x35fa164735182de50811e8e2e824cfb9b6118ac2", "symbol": "eETH", "balance": "0.000000000000000001", "tokenPrice": "3637.93", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xae7ab96520de3a18e5e111b5eaab095312d7fe84", "symbol": "stETH", "balance": "0.000000000000000001", "tokenPrice": "3637.93", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xa3931d71877c0e7a3148cb7eb4463524fec27fbd", "symbol": "sUSDS", "balance": "67435907.43236613", "tokenPrice": "0", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xa8705a14c79fa1cded70875510211fec822b3c30", "symbol": "BEEX", "balance": "5000000", "tokenPrice": "0", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0xabc0abace9fb9625fcefbedc423e8f94225bd251", "symbol": "TANUKI", "balance": "3548102.746002181", "tokenPrice": "0", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenContractAddress": "0x356b8d89c1e1239cbbb9de4815c39a1474d5ba7d", "symbol": "syrupUSDT", "balance": "1750000", "tokenPrice": "0", "isRiskToken": false, "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" } ] } ] } ```
- [Get Specific Token Balance](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-balance-specific-token-balance.md) {/* api-page */} # Get Specific Token Balance Query the balance of a specific token under an address. ### Request URL POST `https://web3.okx.com/api/v6/dex/balance/token-balances-by-address` ## Request Parameters | Parameter | Type | Required | Description | |----------------|--------|----------|-----------------------------------------| | address | String | Yes | Address | | tokenContractAddresses | Array | Yes | List of tokens addresses to query. Maximum of 20 items. | | >chainIndex | String | Yes | Unique identifier for the chain.
e.g., `1`: Ethereum.
See more [here](./dex-supported-chain). | | >tokenContractAddress | String | Yes | Token address.
`1`: Pass an empty string `""` to query the native token of the corresponding chain.
`2`: Pass the specific token contract address to query the corresponding token. | | excludeRiskToken | String | No | Option to filter out risky airdrop & honeypot tokens. Default is to filter
`0`: Filter out
`1`: Do not filter out
It supports only `ETH`、`BSC`、`SOL`、`BASE` for honeypot tokens, more chains will be supported soon. |
## Response Parameters | Parameter | Type | Description | |--------------|--------|-----------------------------------------| | tokenAssets | Array | List for token balances | | >chainIndex | String | Unique identifier for the chain | | >tokenContractAddress | String | Token address.If the return is an empty string `""`, it means the query is for the native token of the corresponding blockchain. | | >address | String | Address | | >symbol | String | Token symbol | | >balance | String | Token balance. | | >rawBalance | String | Raw balance of token address. For unsupported chains, this field is empty. More chains will be supported soon. | | >tokenPrice | String | Token price in USD | | >isRiskToken | Boolean| `true`: flagged as a risky airdrop & honeypot token
`false`: not flagged as a risky airdrop & honeypot token |
## Request Example ```shell curl --location --request POST 'https://web3.okx.com/api/v6/dex/balance/token-balances' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '{ "address": "0x50c476a139aab23fdaf9bca12614cdd54a4244e3", "tokenContractAddresses": [ { "chainIndex": "1", "tokenContractAddress": "" } ] }' ``` ## Response Example ``` json { "code": "0", "msg": "success", "data": [ { "tokenAssets": [ { "chainIndex": "1", "tokenContractAddress": "", "symbol": "eth", "balance": "0", "tokenPrice": "3640.43", "isRiskToken": false, "rawBalance": "", "address": "" } ] } ] } ```
- [Error Codes](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-balance-error-code.md) # Error Codes | Code | HTTP status | Message | |-------|-------------|-----------------------------------------------------------------| | 50014 | 400 | param \{param0\} is invalid | | 50001 | 200 | Service temporarily unavailable. Try again later | | 81001 | 200 | Incorrect parameter: : \{param0\} | | 50011 | 429 | Too Many Requests | | 81104 | 200 | Chain not support | | 81001 | 200 | Required request body is missing | - [Transaction History API Reference](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-tx-history-reference.md) # Transaction History API Reference - [Get Supported Chains](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-tx-history-chains.md) {/* api-page */} # Get Supported Chains Retrieve information on chains supported by Transaction history API ### Request URL GET `https://web3.okx.com/api/v6/dex/balance/supported/chain` ## Request Parameters None ## Response Parameters | Parameter | Type | Description | |-----------|--------|-------------------| | name | String | Chain name | | logoUrl | String | Chain logo URL | | shortName | String | Chain short name | | chainIndex| String | Chain unique identifier | ## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/balance/supported/chain' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ```json { "code": "0", "data": [ { "name": "Ethereum", "logoUrl": "http://www.eth.org/eth.png", "shortName": "ETH", "chainIndex": "1" } ], "msg": "" } ``` - [Get History by Address](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-tx-history-transactions-by-address.md) {/* api-page */} # Get History by Address Query the transaction history under the address dimension for 6 months, sorted in descending chronological order. ### Request URL GET `https://web3.okx.com/api/v6/dex/post-transaction/transactions-by-address` ## Request Parameters | Parameter | Type | Required | Description | |-------------- |-------- |---------- |--------------------------------------------------------------------------------------------------------------- | | address | String | Yes | Address to query the transaction history for | | chains | String | No | Filter the chains whose transaction history needs to be queried. Multiple chains are separated by ",". A maximum of 50 chains are supported. | | tokenContractAddress | String | No | Token contract address; if empty, query addresses with main chain currency balance;if not pass, query all | | begin | String | No | Start time, queries transactions after this time. Unix timestamp, in milliseconds | | end | String | No | End time, queries transactions before this time. If both begin and end are not provided, queries transactions before the current time. Unix timestamp, in milliseconds | | cursor | String | No | Cursor | | limit | String | No | Number of records to return, defaults to the most recent 20 records.
Up to a maximum of 20 records for query on single chain.
Up to a maximum of 100 records for query on multiple chain. | |
## Response Parameters | Parameter | Type | Description | |----------------- |--------------------------------- |----------------------------------------------------- | | transactions | Array | List of transactions | | >chainIndex | String | Chain ID | | >txHash | String | Transaction hash | | >itype | String | Transaction tier type
`0`: Outer main chain coin transfer
`1`: Contract inner main chain coin transfer
`2`: Token transfer | | >methodId | String | Contract Function Call | | >nonce | String | The nth transaction initiated by the sender address | | >txTime | String | Transaction time in Unix timestamp format, in milliseconds, e.g., 1597026383085 | | >from | Array | Transaction input | | >>address | String | Sending/input address, comma-separated for multi-signature transactions | | >>amount | String | Input amount | | >to | Array | Transaction output | | >>address | String | Receiving/output address, comma-separated for multiple addresses | | >>amount | String | Output amount | >tokenContractAddress | String | Token contract address | | >amount | String | Transaction amount | | >symbol | String | Currency symbol corresponding to the transaction amount | | >txFee | String | Transaction fee | | >txStatus | String | Transaction status: `success` for successful transactions, `fail` for failed transactions, `pending` for pending transactions | | >hitBlacklist | Boolean | `false`: Not in blacklist, `true`: In blacklist | | cursor | String | Cursor |
## Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/post-transaction/transactions-by-address?addresses=0x50c476a139aab23fdaf9bca12614cdd54a4244e4&chains=1' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ``` json { "code": "0", "msg": "success", "data": [ { "cursor": "1706197403", "transactionList": [ { "chainIndex": "1", "txHash": "0x963767695543cfb7804039c470b110b87adf9ab69ebc002b571523b714b828ca", "methodId": "", "nonce": "", "txTime": "1724213411000", "from": [ { "address": "0xae7ab96520de3a18e5e111b5eaab095312d7fe84" "amount": "" } ], "to": [ { "address": "0x50c476a139aab23fdaf9bca12614cdd54a4244e4" "amount": "" } ], "tokenContractAddress": "0xe13c851c331874028cd8f681052ad3367000fb13", "amount": "1", "symbol": "claim rewards on stethdao.net", "txFee": "", "txStatus": "success", "hitBlacklist": true, "itype": "2" } ] } ] } ```
- [Get Specific Transaction](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-tx-history-specific-transaction-detail-by-txhash.md) {/* api-page */} # Get Specific Transaction Retrieve details of a transaction based on `txHash` for 6 months. It decomposes a transaction and its internal transactions into sub-transactions based on asset type:
`0`: Outer layer mainnet coin transfer
`1`: Inner layer mainnet coin transfer in a contract
`2`: Token transfer It decomposes a transaction into sub-transactions based on asset type. For EVM transactions, different sub-transaction types include:
`0`: Outer layer mainnet coin transfer
`1`: Inner layer mainnet coin transfer in a contract
`2`: Token transfer
### Request URL GET `https://web3.okx.com/api/v6/dex/post-transaction/transaction-detail-by-txhash` ## Request Parameters | Parameter | Type | Required | Description | |--------------------|----------------|------------------|--------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain | | txHash | String | Yes | Transaction hash | | itype | String | No | Layer type for transactions
`0`: Outer layer mainnet coin transfer
`1`: Inner layer mainnet coin transfer
`2`: Token transfer |
## Response Parameters | Parameter | Type | Description | |------------------------------------|----------------|----------------------------------------------------------------| | chainIndex | String | Unique identifier for the chain | | height | String | Block height where the transaction occurred | | txTime | String | Transaction time; Unix timestamp in milliseconds | | txhash | String | Transaction hash | | txStatus | String | Transaction status:
`1`: pending
`2`: success
`3`: fail | | gasLimit | String | Gas limit | | gasUsed | String | Gas used | | gasPrice | String | Gas price | | txFee | String | Transaction fee. | | nonce | String | Nonce | | amount | String | Transaction amount | | symbol | String | Currency symbol for the transaction amount | | methodId | String | Contract method ID | | fromDetails | Array | Details of transaction inputs | | >address | String | Sender/input address | | >vinIndex | String | Index of the input in the current transaction | | >preVoutIndex | String | Index of the output in the previous transaction | | >txhash | String | Transaction hash, used with `preVoutIndex` to uniquely identify the UTXO | | >isContract | Boolean | Whether the sender address is a contract (true: yes; false: no) | | >amount | String | Transaction amount | | toDetails | Array | Details of transaction outputs | | >address | String | Receiver/output address | | >voutIndex | String | Output index | | >isContract | Boolean | Whether the receiver address is a contract (true: yes; false: no) | | >amount | String | Transaction amount | | internalTransactionDetails | Array | Internal transaction details | | >from | String | Sender address for the internal transaction | | >to | String | Receiver address for the internal transaction | | >isFromContract | Boolean | Whether the sender address is a contract (true: yes; false: no) | | >isToContract | Boolean | Whether the receiver address is a contract (true: yes; false: no) | | >amount | String | Transaction amount | | >txStatus | String | Transaction status | | tokenTransferDetails | Array | Token transfer details | | >from | String | Sender address for token transfer | | >to | String | Receiver address for token transfer | | >isFromContract | Boolean | Whether the sender address is a contract (true: yes; false: no) | | >isToContract | Boolean | Whether the receiver address is a contract (true: yes; false: no) | | >tokenContractAddress | String | Token contract address | | >symbol | String | Token symbol | | >amount | String | Token amount | | l1OriginHash | String | Hash of the L1 transaction executed |
## Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v6/dex/post-transaction/transaction-detail-by-txhash?txHash=0x9ab8ccccc9f778ea91ce4c0f15517672c4bd06d166e830da41ba552e744d29a5&chainIndex=42161' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ## Response Example ``` json { "code": "0", "msg": "success", "data": [ { "chainIndex": "42161", "height": "245222398", "txTime": "1724253417000", "txhash": "0x9ab8ccccc9f778ea91ce4c0f15517672c4bd06d166e830da41ba552e744d29a5", "gasLimit": "2000000", "gasUsed": "2000000", "gasPrice": "10000000", "txFee":"", "nonce": "0", "symbol": "ETH", "amount": "0", "txStatus": "success", "methodId": "0xc9f95d32", "l1OriginHash": "0xa6a87ba2f18cc32bbae8f3b2253a29a9617ed1eb0940d80443f6e3bf9873dbad", "fromDetails": [ { "address": "0xd297fa914353c44b2e33ebe05f21846f1048cfeb", "vinIndex": "", "preVoutIndex": "", "txHash": "", "isContract": false, "amount": "" } ], "toDetails": [ { "address": "0x000000000000000000000000000000000000006e", "voutIndex": "", "isContract": false, "amount": "" } ], "internalTransactionDetails": [ { "from": "0x0000000000000000000000000000000000000000", "to": "0xd297fa914353c44b2e33ebe05f21846f1048cfeb", "isFromContract": false, "isToContract": false, "amount": "0.02", "txStatus": "success" }, { "from": "0xd297fa914353c44b2e33ebe05f21846f1048cfeb", "to": "0x428ab2ba90eba0a4be7af34c9ac451ab061ac010", "isFromContract": false, "isToContract": false, "amount": "0.00998", "txStatus": "success" }, { "from": "0xd297fa914353c44b2e33ebe05f21846f1048cfeb", "to": "0x428ab2ba90eba0a4be7af34c9ac451ab061ac010", "isFromContract": false, "isToContract": false, "amount": "0.009977946366846017", "txStatus": "success" } ], "tokenTransferDetails": [] } ] } ```
- [Error Codes](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-tx-history-error-code.md) # Error Codes | Code | HTTP status | Message | |-------|-------------|-----------------------------------------------------------------------------------------| | 81001 | 200 | Incorrect parameter | - [Introduction ](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-sdk-introduction.md) # Introduction The OKX DEX SDK is a typescript toolkit for developers to integrate OKX DEX API functionalities into their applications. GitHub Repository https://github.com/okx/okx-dex-sdk To get started, follow the guide here: https://github.com/okx/okx-dex-sdk?tab=readme-ov-file#usage ## Install the SDK ```bash npm install @okx-dex/okx-dex-sdk # or yarn add @okx-dex/okx-dex-sdk # or pnpm add @okx-dex/okx-dex-sdk ``` ## Setup Your Environment Create a .env file with your API credentials and wallet information. ```bash # OKX API Credentials OKX_API_KEY=your_api_key OKX_SECRET_KEY=your_secret_key OKX_API_PASSPHRASE=your_passphrase OKX_PROJECT_ID=your_project_id # Solana Configuration SOLANA_RPC_URL=your_solana_rpc_url SOLANA_WALLET_ADDRESS=your_solana_wallet_address SOLANA_PRIVATE_KEY=your_solana_private_key # EVM Configuration EVM_RPC_URL=your_evm_rpc_url EVM_PRIVATE_KEY=your_evm_private_key ``` ## Initialize the Client Create a file for your DEX client (e.g., DexClient.ts): ```typescript // example.ts or test.ts import { OKXDexClient } from '@okx-dex/okx-dex-sdk'; import { Connection } from '@solana/web3.js'; import { createWallet } from '@okx-dex/okx-dex-sdk/core/wallet'; import 'dotenv/config'; import { createEVMWallet } from '@okx-dex/okx-dex-sdk/core/evm-wallet'; import { ethers } from 'ethers'; // Validate environment variables const requiredEnvVars = [ 'OKX_API_KEY', 'OKX_SECRET_KEY', 'OKX_API_PASSPHRASE', 'OKX_PROJECT_ID', 'SOLANA_RPC_URL', 'SOLANA_PRIVATE_KEY', 'EVM_RPC_URL', 'EVM_PRIVATE_KEY' ]; for (const envVar of requiredEnvVars) { if (!process.env[envVar]) { throw new Error(`Missing required environment variable: ${envVar}`); } } // Create Solana connection and wallet const connection = new Connection(process.env.SOLANA_RPC_URL!); const wallet = createWallet(process.env.SOLANA_PRIVATE_KEY!, connection); // Create EVM provider and wallet const provider = new ethers.JsonRpcProvider(process.env.EVM_RPC_URL!); const evmWallet = createEVMWallet(process.env.EVM_PRIVATE_KEY!, provider); // Initialize the client with both Solana and EVM support export const client = new OKXDexClient({ apiKey: process.env.OKX_API_KEY!, secretKey: process.env.OKX_SECRET_KEY!, apiPassphrase: process.env.OKX_API_PASSPHRASE!, projectId: process.env.OKX_PROJECT_ID!, solana: { wallet: wallet }, evm: { wallet: evmWallet } }); ``` ## Using the Client Once initialized, you can use the client to make DEX API calls: ```typescript async function main() { try { // Get tokens for Solana (chainId: 501) const tokens = await client.dex.getTokens("501"); console.log('Supported tokens:', JSON.stringify(tokens, null, 2)); // Get tokens for Ethereum (chainId: 1) const ethTokens = await client.dex.getTokens("1"); console.log('Ethereum tokens:', JSON.stringify(ethTokens, null, 2)); } catch (error) { console.error('Error:', error); } } main(); ``` - [EVM Example](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-sdk-evm.md) # EVM Example ## Create an Approval ```javaScript // approval.ts import { client } from './DexClient'; // Helper function to convert human-readable amounts to base units export function toBaseUnits(amount: string, decimals: number): string { // Remove any decimal point and count the decimal places const [integerPart, decimalPart = ''] = amount.split('.'); const currentDecimals = decimalPart.length; // Combine integer and decimal parts, removing the decimal point let result = integerPart + decimalPart; // Add zeros if we need more decimal places if (currentDecimals < decimals) { result = result + '0'.repeat(decimals - currentDecimals); } // Remove digits if we have too many decimal places else if (currentDecimals > decimals) { result = result.slice(0, result.length - (currentDecimals - decimals)); } // Remove leading zeros result = result.replace(/^0+/, '') || '0'; return result; } /** * Example: Approve a token for swapping */ async function executeApproval(tokenAddress: string, amount: string) { try { // Get token information using quote console.log("Getting token information..."); const tokenInfo = await client.dex.getQuote({ chainId: '8453', // Base Chain fromTokenAddress: tokenAddress, toTokenAddress: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // Native token amount: '1000000', // Use a reasonable amount for quote slippage: '0.005'// 0.5% slippage }); const tokenDecimals = parseInt(tokenInfo.data[0].fromToken.decimal); const rawAmount = toBaseUnits(amount, tokenDecimals); console.log(`\nApproval Details:`); console.log(`--------------------`); console.log(`Token: ${tokenInfo.data[0].fromToken.tokenSymbol}`); console.log(`Amount: ${amount} ${tokenInfo.data[0].fromToken.tokenSymbol}`); console.log(`Amount in base units: ${rawAmount}`); // Execute the approval console.log("\nExecuting approval..."); const result = await client.dex.executeApproval({ chainId: '8453', // Base Chain tokenContractAddress: tokenAddress, approveAmount: rawAmount }); if ('alreadyApproved' in result) { console.log("\nToken already approved for the requested amount!"); return { success: true, alreadyApproved: true }; } else { console.log("\nApproval completed successfully!"); console.log("Transaction Hash:", result.transactionHash); console.log("Explorer URL:", result.explorerUrl); return result; } } catch (error) { if (error instanceof Error) { console.error('Error executing approval:', error.message); } throw error; } } // Run if this file is executed directly if (require.main === module) { // Example usage: ts-node approval.ts 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 1000 const args = process.argv.slice(2); if (args.length !== 2) { console.log("Usage: ts-node approval.ts "); console.log("\nExamples:"); console.log(" # Approve 1000 USDC"); console.log(` ts-node approval.ts 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 1000`); process.exit(1); } const [tokenAddress, amount] = args; executeApproval(tokenAddress, amount) .then(() => process.exit(0)) .catch((error) => { console.error('Error:', error); process.exit(1); }); } export { executeApproval }; ``` ## Create a Swap ```javaScript // swap.ts import { client } from './DexClient'; /** * Example: Execute a swap from ETH to USDC on Base chain */ async function executeSwap() { try { if (!process.env.EVM_PRIVATE_KEY) { throw new Error('Missing EVM_PRIVATE_KEY in .env file'); } // You can change this to any EVM chain // For example, for Base, use chainId: '8453' // For example, for baseSepolia, use chainId: '84532' // You can also use SUI, use chainId: '784' // When using another Chain, you need to change the fromTokenAddress and toTokenAddress to the correct addresses for that chain const swapResult = await client.dex.executeSwap({ chainId: '8453', // Base chain ID fromTokenAddress: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // Native ETH toTokenAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC on Base amount: String(10 * 10 ** 14), // .0001 ETH slippage: '0.005', // 0.5% slippage userWalletAddress: process.env.EVM_WALLET_ADDRESS! }); console.log('Swap executed successfully:'); console.log(JSON.stringify(swapResult, null, 2)); return swapResult; } catch (error) { if (error instanceof Error) { console.error('Error executing swap:', error.message); // API errors include details in the message if (error.message.includes('API Error:')) { const match = error.message.match(/API Error: (.*)/); if (match) console.error('API Error Details:', match[1]); } } throw error; } } // Run if this file is executed directly if (require.main === module) { executeSwap() .then(() => process.exit(0)) .catch((error) => { console.error('Error:', error); process.exit(1); }); } export { executeSwap }; ``` ## Get a Quote ```javaScript const quote = await client.dex.getQuote({ chainId: '8453', // Base Chain fromTokenAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC toTokenAddress: '0x4200000000000000000000000000000000000006', // WETH amount: '1000000', // 1 USDC (in smallest units) slippage: '0.005' // 0.5% slippage }); ``` - [Solana Example](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-sdk-solana.md) # Solana Example ## Create a Swap ```javaScript // swap.ts import { client } from './DexClient'; /** * Example: Execute a swap from SOL to USDC */ async function executeSwap() { try { if (!process.env.SOLANA_PRIVATE_KEY) { throw new Error('Missing SOLANA_PRIVATE_KEY in .env file'); } // Get quote to fetch token information console.log("Getting token information..."); const quote = await client.dex.getQuote({ chainId: '501', fromTokenAddress: '11111111111111111111111111111111', // SOL toTokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC amount: '1000000', // Small amount for quote slippage: '0.005' // 0.5% slippage }); const tokenInfo = { fromToken: { symbol: quote.data[0].fromToken.tokenSymbol, decimals: parseInt(quote.data[0].fromToken.decimal), price: quote.data[0].fromToken.tokenUnitPrice }, toToken: { symbol: quote.data[0].toToken.tokenSymbol, decimals: parseInt(quote.data[0].toToken.decimal), price: quote.data[0].toToken.tokenUnitPrice } }; // Convert amount to base units (for display purposes) const humanReadableAmount = 0.1; // 0.1 SOL const rawAmount = (humanReadableAmount * Math.pow(10, tokenInfo.fromToken.decimals)).toString(); console.log("\nSwap Details:"); console.log("--------------------"); console.log(`From: ${tokenInfo.fromToken.symbol}`); console.log(`To: ${tokenInfo.toToken.symbol}`); console.log(`Amount: ${humanReadableAmount} ${tokenInfo.fromToken.symbol}`); console.log(`Amount in base units: ${rawAmount}`); console.log(`Approximate USD value: $${(humanReadableAmount * parseFloat(tokenInfo.fromToken.price)).toFixed(2)}`); // Execute the swap console.log("\nExecuting swap..."); const swapResult = await client.dex.executeSwap({ chainId: '501', // Solana chain ID fromTokenAddress: '11111111111111111111111111111111', // SOL toTokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC amount: rawAmount, slippage: '0.005', // 0.5% slippage userWalletAddress: process.env.SOLANA_WALLET_ADDRESS! }); console.log('Swap executed successfully:'); console.log(JSON.stringify(swapResult, null, 2)); return swapResult; } catch (error) { if (error instanceof Error) { console.error('Error executing swap:', error.message); // API errors include details in the message if (error.message.includes('API Error:')) { const match = error.message.match(/API Error: (.*)/); if (match) console.error('API Error Details:', match[1]); } } throw error; } } // Run if this file is executed directly if (require.main === module) { executeSwap() .then(() => process.exit(0)) .catch((error) => { console.error('Error:', error); process.exit(1); }); } export { executeSwap }; ``` ## Get a Quote ```javaScript const quote = await client.dex.getQuote({ chainId: '501', // Solana fromTokenAddress: '11111111111111111111111111111111', // SOL toTokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC amount: '100000000', // 0.1 SOL (in lamports) slippage: '0.005' // 0.5% slippage }); ``` ## Swap-Instructions Execution Import the necessary libraries: ```javaScript // Required Solana dependencies for DEX interaction import { Connection, // Handles RPC connections to Solana network Keypair, // Manages wallet keypairs for signing PublicKey, // Handles Solana public key conversion and validation TransactionInstruction, // Core transaction instruction type TransactionMessage, // Builds transaction messages (v0 format) VersionedTransaction, // Supports newer transaction format with lookup tables RpcResponseAndContext, // RPC response wrapper type SimulatedTransactionResponse, // Simulation result type AddressLookupTableAccount, // For transaction size optimization PublicKeyInitData // Public key input type } from "@solana/web3.js"; import base58 from "bs58"; // Required for private key decoding ``` Initialize your connection and wallet: ```javaScript // Note: Consider using a reliable RPC endpoint with high rate limits for production const connection = new Connection( process.env.SOLANA_RPC_URL || "https://api.mainnet-beta.solana.com" ); // Initialize wallet for signing // This wallet will be the fee payer and transaction signer const wallet = Keypair.fromSecretKey( Uint8Array.from(base58.decode(userPrivateKey)) ); ``` Set up the parameters for your swap: ```javaScript // Configure swap parameters const baseUrl = "https://web3.okx.com/api/v6/dex/aggregator/swap-instruction"; const params = { chainId: "501", // Solana mainnet chain ID feePercent: "1", // Platform fee percentage amount: "1000000", // Amount in smallest denomination (lamports for SOL) fromTokenAddress: "11111111111111111111111111111111", // SOL mint address toTokenAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC mint address slippage: "0.1", // Slippage tolerance 10% userWalletAddress: userAddress, // Wallet performing the swap priceTolerance: "0", // Maximum allowed price impact autoSlippage: "false", // Use fixed slippage instead of auto pathNum: "3" // Maximum routes to consider }; ``` ## Process the Swap Instructions: ```javaScript // Helper function to convert DEX API instructions to Solana format function createTransactionInstruction(instruction) { return new TransactionInstruction({ programId: new PublicKey(instruction.programId), // DEX program ID keys: instruction.accounts.map((key) => ({ pubkey: new PublicKey(key.pubkey), // Account address isSigner: key.isSigner, // True if account must sign tx isWritable: key.isWritable // True if instruction modifies account })), data: Buffer.from(instruction.data, 'base64') // Instruction parameters }); } // Fetch optimal swap route and instructions from DEX const timestamp = new Date().toISOString(); const requestPath = "/api/v6/dex/aggregator/swap-instruction"; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); const response = await fetch( `https://web3.okx.com${requestPath}${queryString}`, { method: 'GET', headers } ); const { data } = await response.json(); const { instructionLists, addressLookupTableAccount } = data; // Process DEX instructions into Solana-compatible format const instructions = []; // Remove duplicate lookup table addresses returned by DEX const uniqueLookupTables = Array.from(new Set(addressLookupTableAccount)); console.log("Lookup tables to load:", uniqueLookupTables); // Convert each DEX instruction to Solana format if (instructionLists?.length) { instructions.push(...instructionLists.map(createTransactionInstruction)); } ``` ## Handle Address Lookup Tables ```javaScript // Process lookup tables for transaction optimization // Lookup tables are crucial for complex swaps that interact with many accounts // They significantly reduce transaction size and cost const addressLookupTableAccounts = []; if (uniqueLookupTables?.length > 0) { console.log("Loading address lookup tables..."); // Fetch all lookup tables in parallel for better performance const lookupTableAccounts = await Promise.all( uniqueLookupTables.map(async (address) => { const pubkey = new PublicKey(address); // Get lookup table account data from Solana const account = await connection .getAddressLookupTable(pubkey) .then((res) => res.value); if (!account) { throw new Error(`Could not fetch lookup table account ${address}`); } return account; }) ); addressLookupTableAccounts.push(...lookupTableAccounts); } ``` ## Create and Sign Transaction ```javaScript // Get recent blockhash for transaction timing and uniqueness const latestBlockhash = await connection.getLatestBlockhash('finalized'); // Create versioned transaction message (V0 format required for lookup table support) const messageV0 = new TransactionMessage({ payerKey: wallet.publicKey, // Fee payer address recentBlockhash: latestBlockhash.blockhash, // Transaction timing instructions // Swap instructions from DEX }).compileToV0Message(addressLookupTableAccounts); // Include lookup tables // Create new versioned transaction with optimizations const transaction = new VersionedTransaction(messageV0); // Simulate transaction to check for errors // This helps catch issues before paying fees const result = await connection.simulateTransaction(transaction); // Sign transaction with fee payer wallet transaction.sign([wallet]); ``` ## Execute Transaction ```javaScript // Send transaction to Solana // skipPreflight=false ensures additional validation // maxRetries helps handle network issues const txId = await connection.sendRawTransaction(transaction.serialize(), { skipPreflight: false, // Run preflight validation maxRetries: 5 // Retry on failure }); // Log transaction results console.log("Transaction ID:", txId); console.log("Explorer URL:", `https://solscan.io/tx/${txId}`); // Wait for confirmation await connection.confirmTransaction({ signature: txId, blockhash: latestBlockhash.blockhash, lastValidBlockHeight: latestBlockhash.lastValidBlockHeight }); console.log("Transaction confirmed!"); ``` - [Sui Example](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-sdk-sui.md) # Sui Example ## Create a Token Helper (Optional) ```javaScript // Common tokens on Sui mainnet export const TOKENS = { SUI: "0x2::sui::SUI", USDC: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC" } as const; ``` ## Create a Swap ```javaScript // swap.ts import { client } from './DexClient'; import { TOKENS } from './Tokens'; // Optional, if you created the token helper /** Example: Execute a swap from SUI to USDC */ async function executeSwap() { try { if (!process.env.SUI_PRIVATE_KEY) { throw new Error('Missing SUI_PRIVATE_KEY in .env file'); } // First, get token information using a quote console.log("Getting token information..."); const fromTokenAddress = TOKENS.SUI; // Or use directly: "0x2::sui::SUI" const toTokenAddress = TOKENS.USDC; // Or use directly: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC" const quote = await client.dex.getQuote({ chainId: '784', // Sui chain ID fromTokenAddress, toTokenAddress, amount: '1000000', // Small amount for quote slippage: '0.005' // 0.5% slippage }); const tokenInfo = { fromToken: { symbol: quote.data[0].fromToken.tokenSymbol, decimals: parseInt(quote.data[0].fromToken.decimal), price: quote.data[0].fromToken.tokenUnitPrice }, toToken: { symbol: quote.data[0].toToken.tokenSymbol, decimals: parseInt(quote.data[0].toToken.decimal), price: quote.data[0].toToken.tokenUnitPrice } }; // Convert amount to base units const humanReadableAmount = 1.5; // 1.5 SUI const rawAmount = (humanReadableAmount * Math.pow(10, tokenInfo.fromToken.decimals)).toString(); console.log("\nSwap Details:"); console.log("--------------------"); console.log( From: ${tokenInfo.fromToken.symbol} ); console.log( To: ${tokenInfo.toToken.symbol} ); console.log( Amount: ${humanReadableAmount} ${tokenInfo.fromToken.symbol} ); console.log( Amount in base units: ${rawAmount} ); console.log( Approximate USD value: $${(humanReadableAmount * parseFloat(tokenInfo.fromToken.price)).toFixed(2)} ); // Execute the swap console.log("\nExecuting swap..."); const swapResult = await client.dex.executeSwap({ chainId: '784', // Sui chain ID fromTokenAddress, toTokenAddress, amount: rawAmount, slippage: '0.5', // 0.5% slippage userWalletAddress: process.env.SUI_WALLET_ADDRESS! }); console.log('Swap executed successfully:'); console.log("\nTransaction ID:", swapResult.transactionId); console.log("Explorer URL:", swapResult.explorerUrl); if (swapResult.details) { console.log("\nDetails:"); console.log( Input: ${swapResult.details.fromToken.amount} ${swapResult.details.fromToken.symbol} ); console.log( Output: ${swapResult.details.toToken.amount} ${swapResult.details.toToken.symbol} ); if (swapResult.details.priceImpact) { console.log( Price Impact: ${swapResult.details.priceImpact}% ); } } return swapResult; } catch (error) { if (error instanceof Error) { console.error('Error executing swap:', error.message); // API errors include details in the message if (error.message.includes('API Error:')) { const match = error.message.match(/API Error: (.*)/); if (match) console.error('API Error Details:', match[1]); } } throw error; } } // Run if this file is executed directly if (require.main === module) { executeSwap() .then(() => process.exit(0)) .catch((error) => { console.error('Error:', error); process.exit(1); }); } export { executeSwap }; ``` ## Get a quote ```javaScript const quote = await client.dex.getQuote({ chainId: '784', // Sui fromTokenAddress: '0x2::sui::SUI', // SUI toTokenAddress: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC', // USDC amount: '100000000', // In base units slippage: '0.005' // 0.5% slippage }); ``` - [Use Widget](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/dex-widget.md) # Use Widget

Integrate the powerful OKX Widget into your product! With this widget, you can create an effective trading interface within 30 minutes.

## Install ```javaScript yarn add @okxweb3/dex-widget // or npm install @okxweb3/dex-widget // or pnpm add @okxweb3/dex-widget ``` ## Quickstart

Here is an example which shows how to use @okxweb3/dex-widget in a React project. You can find more examples through this [link](https://github.com/okx/dex-widget/tree/develop/packages/widget-configurator/src/react-cra).
Demo:https://okx.github.io/dex-widget/

```javaScript import React, { useRef, useEffect } from 'react'; import ReactDOM from 'react-dom/client'; import { createOkxSwapWidget } from '@okxweb3/dex-widget'; function App() { const widgetRef = useRef(); useEffect(() => { const params = { width: 375, providerType: 'EVM', }; const provider = window.ethereum; const listeners = [ { event: 'ON_CONNECT_WALLET', handler: () => { provider.enable(); }, }, ]; const instance = createOkxSwapWidget(widgetRef.current, { params, provider, listeners, }); return () => { instance.destroy(); }; }, []); return
; } const root = ReactDOM.createRoot(document.getElementById('root')); root.render( ); ``` ## Wallet Provider

You should pass the wallet provider information from your application if you want to connect a wallet. Then add the ON_CONNECT_WALLET event to seamlessly use the widget as part of your application.

- If it’s on Ethereum or other EVM networks, the provider must comply with EIP-1193 to implement the interface. - If it’s on Solana, the provider must pass the wallet provider information from your application. ```typeScript import { createOkxSwapWidget, ProviderType } from '@okxweb3/dex-widget'; const widgetEthInstance = createOkxSwapWidget( document.getElementById('widget'), { params: { providerType: ProviderType.EVM, }, provider: window.ethereum, // e.g. window.okexchain } ); const widgetSolanaInstance = createOkxSwapWidget( document.getElementById('widget'), { params: { providerType: ProviderType.SOLANA, }, provider: window.solana, // window.okexchain.solana } ); ```

You can check out this [link](https://github.com/okx/dex-widget/blob/faf69c76b90268f2352507c9a90fb37bb80fdbc7/example/widget-demo/src/main.tsx#L22)。 for an example of using the Rainbow kit to connect to a wallet.

## Params

The following sheet contains the descriptions of the params.

| Parameter | Type | Default | Description | | -------------- | --------------- | ------- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `width` | `number` | 450 | The width of the widget in css values (px). If the width is not set, the display style for the width will be: 450px when the screen width > 767px. 100% when the screen width < 768px. 375px when the screen width < 375px. | | `theme` | `THEME` | light | The swap widget provides a default light theme and a dark theme as options. You can change the theme of the widget by following the example below. | | `lang` | `string` | en_us | The widget language is adjustable. Check the Multilanguage section for more details. | | `tradeType` | `TradeType` | auto | The type of transaction. It can be “swap”, “bridge”, or “auto”.Note: “Auto” includes “swap” and “bridge”. | | `chainIds` | `Array` | [] | The ID of the blockchain on which the single-chain swap will take place. Check the ChainId config section for all the networks that you can choose from. | | `feeConfig` | `IFeeConfig` | {} | You can enable a fee for all transactions in the widget. Check the Fee customization section for more details. | | `tokenPair` | `ITokenPair` | {} | The default token pair you have set for Swap, can be found in the default tokenPair configuration section for more details. | | `bridgeTokenPair` | `ITokenPair` | {} | The default token pair you have set for Bridge, can be found in the default tokenPair configuration section for more details. | | `providerType` | `ProviderType` | ' ' | ProviderType represents the type of the provider and corresponds to it one-to-one. For example, if the provider is Solana, then the providerType would be SOLANA. | | `defaultTab` | `TradeTab ` | 'swap' | Default open mode can be set to single-chain or cross-chain. Supported from version 1.3.16 and above. | | `walletName` | `string` | ' ' | Name of the connected wallet. This parameter helps the DEX widget continuously improve its products and services to provide a better user experience. Supported from version 1.3.16 and above. | ## Type Description ```typeScript interface IFeeConfig { [key: string]: { feePercent?: string | number; referrerAddress?: { [key: string]: { feePercent: string | number; }; }; }; } interface ITokenPair { fromChain: string | number; toChain: string | number; fromToken?: string; toToken?: string; } enum ProviderType { EVM = 'EVM', SOLANA = 'SOLANA', WALLET_CONNECT = 'WALLET_CONNECT', } enum TradeType { SWAP = 'swap', BRIDGE = 'bridge', AUTO = 'auto', } enum THEME { LIGHT = 'light', DARK = 'dark', } ``` ## Multilanguage | lang | Description | | -------- | ----------------------- | | `en_us` | English,Default | | `zh_cn` | 简体中文 | | `zh_tw` | 繁體中文 | | `fr_fr` | Français (Afrique) | | `id_id` | Bahasa Indonesia | | `ru_ru` | Русский | | `tr_tr` | Türkçe | | `vi_vn` | Tiếng Việt | | `de_de` | Deutsch | | `it_it` | Italiano | | `pl_pl` | Polski | | `pt_pt` | Português (Portugal) | | `es_es` | Español (España) | | `pt_br` | Português (Brasil) | | `es_419` | Español (Latinoamérica) | | `cs_cz` | Čeština | | `ro_ro` | Română | | `uk_ua` | Українська | | `ar_eh` | العربية | | `nl_nl` | Nederlands | ## ChainId Config | Network | ChainId | Native token contract | | ----------- | ------- | ------------------------------------------ | | Ethereum | 1 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | zkSync Era | 324 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Optimism | 10 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Polygon | 137 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Avalanche C | 43114 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Arbitrum | 42161 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Linea | 59144 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Base | 8453 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Mantle | 5000 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Scroll | 534352 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | X layer | 196 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Blast | 81457 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | BNB Chain | 56 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Solana | 501 | 11111111111111111111111111111111 | ## Default tokenPair Config

`tokenPair`: If tokenPair not configured, the default network for single-chain swaps is set to Ethereum, with ETH as `fromToken` and USDC as `toToken`.

`bridgeTokenPair`: If bridgeTokenPair not configured, the default bridge transaction is set to one from Ethereum to BNB Chain, with ETH as `fromToken` and BNB as `toToken`.

```javaScript import React, { useEffect, useRef } from 'react'; import { OkxSwapWidgetParams, ProviderType, TradeType, } from '@okxweb3/dex-widget'; const provider = window.ethereum; export function EvmWidget() { const widgetRef = useRef(); const params = { chainIds: ['1', '10'], lang: 'zh_cn', providerType: ProviderType.EVM, theme: 'dark', tradeType: TradeType.AUTO, tokenPair: { fromChain: 1, //ETH toChain: 1, // ETH fromToken: '0xdac17f958d2ee523a2206206994597c13d831ec7', // USDT toToken: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // ETH }, bridgeTokenPair: { fromChain: 1, //ETH toChain: 56, // BNB fromToken: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // ETH toToken: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // BNB }, }; const initialConfig = { params, provider, listeners: [ { event: 'ON_CONNECT_WALLET', handler: (token, preToken) => { provider.enable(); }, }, ], }; useEffect(() => { const widgetHandler = createOkxSwapWidget(widgetRef.current, initialConfig); return () => { widgetHandler?.destroy(); }; }, []); return
; } ``` | Parameter | Type | Description | | --------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | fromChain | String | The ID of the source network that the fromToken belongs to (e.g., 1: Ethereum. Check ChainId config for a full list of the supported networks and the corresponding chain IDs). | | fromToken | String | The contract address of the token to be sold. E.g., ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE. If the fromToken is a blockchain’s native token, check the chain ID to get the contract address. | | toChain | String | The ID of the destination network that the toToken belongs to (e.g., 1: Ethereum. Check ChainId config for a full list of the supported networks and the corresponding chain IDs). | | toToken | String | "The contract address of a token to be bought. E.g., USDC: 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48. If the toToken is a blockchain’s native token, check the chain ID to get the contract address." | ### updateProvider

The widget supports EVM and Solana. When switching from EVM to Solana, remember to update the corresponding widget’s provider, and vice versa.
If you don’t pass in provider information for the first rendering and want the widget to respond to a wallet connection, you need to call updateProvider. Updating the provider can also include the `walletName` parameter to identify the plugin wallet connected by the user.

```javaScript // 3. Update the provider if the user connects a different wallet, EVM => SOLANA const walletName = 'phantom'; widgetHandler.updateProvider(window.solana, ProviderType.SOLANA, walletName); // SOLANA => EVM // widgetHandler.updateProvider(window.ethereum, ProviderType.EVM); ``` ### updateListeners

You can update the events that the widget listens to.

```javaScript // 4. Modify event listeners to handle new types of events widgetHandler.updateListeners([ { event: OkxEvents.ON_FROM_CHAIN_CHANGE, handler: (payload) => { // }, }, ]); ``` - Listeners mainly listen to the interfaces exposed externally by the widget, enabling customized processing through various events. The updateListeners function is used to modify custom processing after switching chains. - By adding event listeners, you can capture and handle data passed out from the iframe. This data usually represents events or state changes happening within the iframe and is passed to the external page through events. - The received data can be processed and manipulated flexibly according to your needs. This allows you to implement different logic or update UI elements based on the type or content of the data passed. - With the updateListeners method, you can add handlers for different types of events, such as OkxEvents.ON_TOKEN_CHANGE. When the event is triggered, the handler will receive the relevant payload data for further processing. ### destroy

Call this method when removing the widget module.

```javascript const widgetHandler = createOkxSwapWidget(container, initialConfig); widgetHandler.destory(); ``` #### Note: - Whenever you refresh or update, make sure to call the destroy method to remove previously connected events in order to prevent duplicate requests. ## Event Listeners

Widget provides event listeners for ON_CONNECT_WALLET and ON_FROM_CHAIN_CHANGE.

- `ON_CONNECT_WALLET`: This event is triggered when the widget is not connected to a wallet and the connect wallet button is clicked. - `ON_FROM_CHAIN_CHANGE`: This event is triggered when fromChain changes. - `ON_SUBMIT_TX`: This event is triggered after the transaction is completed and returns the `txHash` and `chainId`. Supported from version 1.3.16 and above.

Here’s how to use them:

```typeScript import {createOkxSwapWidget, OkxSwapWidgetParams, OkxEventListeners, OkxEvents} from '@okxweb3/dex-widget' const params: OkxSwapWidgetParams = { // ... } const listeners: OkxEventListeners = [ { event: OkxEvents.ON_CONNECT_WALLET, handler: () => { // open connect wallet method, eg openConnectModal of the rainbow kit. window.ethereum.enable() } }, { event: OkxEvents.ON_FROM_CHAIN_CHANGE, handler: (token) => { // } }, { event: OkxEvents.ON_SUBMIT_TX, handler: (res) => { console.log(`Transaction submitted successfully, txHash: ${res.data.txHash}`); } }, ] const { updateListeners } = createOkxSwapWidget(container, { params, listeners, provider }) ``` - [Javascript Signing SDK](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/private-key-wallet-javascript-sdk.md) # Javascript Signing SDK ## Overview Js-wallet-sdk is a wallet solution based on TypeScript/JavaScript language that includes various public chains' different cryptographic algorithms and common functionalities. You can use it for creating private keys, addresses, assembling transactions, and performing signatures, among other things. This document will provide a detailed guide on how to use this SDK. Currently, it supports various mainstream blockchains, with each token format having its own independent module implementation. We will continue to add support for more blockchains in the future. ### Supported Platforms As a Javascript SDK, it supports various browsers and JavaScript environments, and can be easily integrated into Web applications, mobile applications, or desktop applications. ## Installation and Building ### NPM Building To use the Signing SDK, you first need to install it. You can use npm install to get the latest version. Our Signing SDK supports two types of packages: public packages and single coin modules. Public packages are for all currencies: ```bash npm install @okxweb3/crypto-lib npm install @okxweb3/coin-base ``` Integration of individual currencies, taking ETH and BTC as examples: Integration of ETH: ```bash npm install @okxweb3/coin-ethereum ``` Integration of BTC: ```bash npm install @okxweb3/coin-bitcoin ``` ### Local Building To build the SDK locally: 1) Download the project source code ```bash git clone https://github.com/okx/js-wallet-sdk.git ``` 2) Run the build script ```bash sh build.sh ``` ## Main Features Here is a specific introduction to the functions of each module in the Signing SDK. - crypto-lib: This module provides commonly used security encryption algorithms and signature algorithms, etc. - coin-base: This module provides a common interface for coins. - coin-*: This module implements methods for building and signing transactions for each coin. Each coin has a corresponding module, such as coin-ethereum, coin-bitcoin, etc. These modules provide transaction building and signing methods for specific coins. ## Packages | Package name | Module | Description | | --- | --- | --- | | [@okxweb3/coin-base](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-base/README.md) | coin-base | We provide common functions for these chains or currencies, making access to these chains very simple. | | [@okxweb3/crypto-lib](https://github.com/okx/js-wallet-sdk/blob/main/packages/crypto-lib/README.md) | crypto-lib | We provide common functions about bip32, bip39, ecdsa, ed25519, etc. | | [@okxweb3/coin-aptos](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-aptos/README.md) | coin-aptos | Aptos SDK is used to interact with the Aptos blockchain, containing various functions that can be used for web3 wallets. | | [@okxweb3/coin-bitcoin](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-bitcoin/README.md) | coin-bitcoin | Bitcoin SDK is used to interact with the Bitcoin mainnet or testnet, containing various functions that can be used for web3 wallets. The SDK not only supports Bitcoin, but also supports the following chains: BTC, BSV, DOGE, LTC, TBTC. | | [@okxweb3/coin-cosmos](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-cosmos/README.md) | coin-cosmos | Cosmos SDK is used to interact with the Cosmos blockchain, containing various functions that can be used for web3 wallets. | | [@okxweb3/coin-eos](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-eos/README.md) | coin-eos | EOS SDK is used to interact with the EOS blockchain, containing various functions that can be used for web3 wallets. The SDK not only supports EOS, but also supports WAX. | | [@okxweb3/coin-ethereum](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-ethereum/README.md) | coin-ethereum | Ethereum SDK is used to interact with the Ethereum blockchain or Evm blockchain, containing various functions that can be used for web3 wallets. | | [@okxweb3/coin-flow](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-flow/README.md) | coin-flow | Flow SDK is used to interact with the Flow blockchain, containing various functions that can be used for web3 wallets. | | [@okxweb3/coin-near](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-near/README.md) | coin-near | Near SDK is used to interact with the Near Protocol, containing the main functions needed when interacting with the Near ecosystem. | | [@okxweb3/coin-polkadot](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-polkadot/README.md) | coin-polkadot | Polkadot SDK is used to interact with the Polkadot blockchain, containing the main functions needed when interacting with the Polkadot ecosystem. | | [@okxweb3/coin-solana](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-solana/README.md) | coin-solana | Solana SDK is used to interact with the Solana chain, containing the main functions needed when interacting with the Solana ecosystem. | | [@okxweb3/coin-stacks](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-stacks/README.md) | coin-stacks | Stacks SDK is used to interact with the Stacks blockchain, containing various functions that can be used for web3 wallets. | | [@okxweb3/coin-starknet](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-starknet/README.md) | coin-starknet | Starknet SDK is used to interact with the Starknet blockchain, containing various functions that can be used for web3 wallets. | | [@okxweb3/coin-sui](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-sui/README.md) | coin-sui | SUI SDK is used to interact with the SUI blockchain, containing various functions that can be used for web3 wallets. | | [@okxweb3/coin-tron](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-tron/README.md) | coin-tron | TRX SDK is used to interact with the TRON blockchain, containing various functions that can be used for web3 wallets. | | [@okxweb3/coin-zkspace](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-zkspace/README.md) | coin-zkspace | ZKSpace SDK is used to interact with ZK contracts, containing various functions that can be used for web3 wallets. The SDK not only supports ZKSpace, but also supports zkSync. | ### coin-base The base package is the common basic module for all currencies, providing common interface method definitions, such as: random private key generation, private key derivation, obtaining derivation paths, etc. At present, the implementation packages of individual currencies have basically implemented common interface methods, but the functions supported by different currencies may vary slightly. For more details, you can refer to the function descriptions of each coin implementation package. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-base ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | validPrivateKey | Validate a private key | | | signMessage | Sign a message | | | verifyMessage | Verify a signed message | | | ecRecover | Recover a signature to a public key | | | getAddressByPublicKey | Get an address through a public key | | | getHardWareRawTransaction | Get the raw transaction of the hardware | | | getHardWareSignedTransaction | Get the signed transaction of the hardware | | | getHardWareMessageHash | Get the message hash of the hardware | | | calcTxHash | Get a transaction hash through a raw transaction | | | getRawTransaction | Generate raw transaction data | | | validSignedTransaction | Check a signed transaction | | | estimateFee | Estimate gas fees | | For more detailed information about the functions supported by the coin-base package and use cases, you can view the github document for more detailed content: [coin-base function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-base/README.md#supporting-functions). ### crypto-lib This is a library that includes implementations of commonly used security encryption and signature algorithms such as bip32, bip39, ecdsa, ed25519, etc. For example: - Common bip32 functions: These functions are mainly used to handle and operate tasks related to the Bitcoin Improvement Payment Protocol (BIP32). - bip39 mnemonic generation, public/private key, and message signing functions: These functions are mainly used to handle and operate tasks related to the Bitcoin Improvement Payment Protocol (BIP39), such as generating mnemonics, public/private keys, and signing messages. - Common hash and encoding/decoding functions: These functions are mainly used to handle common hash and encoding/decoding tasks, such as SHA256 hashing, Base64 encoding/decoding, etc. - Common ed5519 signature functions: These functions are mainly used to handle and operate tasks related to the ed5519 signature algorithm. - Common ecdsa signature functions: These functions are mainly used to handle and operate tasks related to the Elliptic Curve Digital Signature Algorithm (ECDSA). To get the latest version of the package via npm: ```bash npm install @okxweb3/crypto-lib ``` For more detailed information about the functions supported by the crypto-lib package and use cases, you can view the github document for more detailed content: [crypto-lib function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/crypto-lib/README.md#provides). ### coin-aptos Aptos SDK is mainly used to integrate Aptos blockchain, containing functions such as private key generation, private key derivation, address generation, and transaction transfer. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-aptos ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | signMessage | Sign a message | | | verifyMessage | Verify a signed message | | | calcTxHash | Get a transaction hash through a raw transaction | | | validSignedTransaction | Check a signed transaction | | Aptos transaction support types are: "transfer", "tokenTransfer", "tokenMint", "tokenBurn", "tokenRegister", "dapp", "simulate", "offerNft", "claimNft", "offerNft_simulate", "claimNft_simulate" For more detailed information about the functions supported by the coin-aptos package and use cases, you can view the github document for more detailed content: [coin-aptos function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-aptos/README.md#usage). ### coin-bitcoin coin-bitcoin is an SDK for integrating Bitcoin blockchain. It supports both the Bitcoin mainnet and testnet, and provides a series of functional methods, making it easier for developers to interact with the Bitcoin blockchain. In addition to BTC, it also supports other cryptocurrencies such as BSV, DOGE, LTC, and TBTC. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-bitcoin ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | signMessage | Sign a message | | | verifyMessage | Verify a signed message | | | calcTxHash | Get a transaction hash through a raw transaction | | | validSignedTransaction | Check a signed transaction | | | getAddressByPublicKey | Get an address through a public key | | For more detailed information about the functions supported by the coin-bitcoin package and use cases, you can view the github document for more detailed content: [coin-bitcoin function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-bitcoin/README.md#using-bitcoin-sdk). ### coin-cosmos Cosmos SDK is a toolkit for integrating with the Cosmos blockchain, providing a series of functional methods, including generating private keys, deriving private keys, generating addresses, and transferring transactions. It supports currencies including: - Atom - Axelar - Cronos - Evmos - Iris - Juno - Kava - Kujira - Osmos - Secret - Sei - Stargaze - Terra To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-cosmos ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | signMessage | Sign a message | | | verifyMessage | Verify a signed message | | | calcTxHash | Get a transaction hash through a raw transaction | | | validSignedTransaction | Check a signed transaction | | | getAddressByPublicKey | Get an address through a public key | | For more detailed information about the functions supported by the coin-cosmos package and use cases, you can view the github document for more detailed content: [coin-cosmos function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-cosmos/README.md#using-cosmos-sdk). ### coin-eos EOS SDK is a toolkit for integrating with the EOS blockchain. It provides a series of functional methods, including generating private keys, deriving private keys, generating addresses, and transaction serialization. In addition to EOS, it also supports the Wax coin. These functional methods make it easier for developers to interact with the EOS blockchain, including creating and managing wallets, sending and receiving transactions, and querying blockchain information. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-eos ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | calcTxHash | Get a transaction hash through a raw transaction | | For more detailed information about the functions supported by the coin-eos package and use cases, you can view the github document for more detailed content: [coin-eos function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-eos/README.md#using-eos-sdk). ### coin-ethereum Ethereum SDK is a toolkit for integrating with the Ethereum blockchain and other blockchains that support EVM (Ethereum Virtual Machine). It provides a series of functional methods, including generating private keys, deriving private keys, generating addresses, and transferring transactions. These functional methods make it easier for developers to interact with the Ethereum blockchain, including creating and managing wallets, sending and receiving transactions, and querying blockchain information. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-ethereum ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | validPrivateKey | Validate a private key | | | signMessage | Sign a message | | | verifyMessage | Verify a signed message | | | ecRecover | Recover a signature to a public key | | | getAddressByPublicKey | Get an address through a public key | | | getHardWareRawTransaction | Get the raw transaction of the hardware | | | getHardWareSignedTransaction | Get the signed transaction of the hardware | | | getHardWareMessageHash | Get the message hash of the hardware | | | calcTxHash | Get a transaction hash through a raw transaction | | | getRawTransaction | Generate raw transaction data | | | validSignedTransaction | Check a signed transaction | | For more detailed information about the functions supported by the coin-ethereum package and use cases, you can view the github document for more detailed content: [coin-ethereum function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-ethereum/README.md#using-ethereum-sdk). ### coin-flow Flow blockchain is a next-generation, future-oriented blockchain platform, specifically designed for high-performance applications and games. Flow SDK is a toolkit for integrating with the Flow blockchain. It provides a series of functional methods, enabling developers to interact more conveniently with the Flow blockchain. The specific functionalities offered by the SDK can facilitate the development of applications on the Flow blockchain. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-flow ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | validateAddress | Validate an address | | | signTransaction | Sign a transaction | | Flow supports two types of transactions: Account and Transfer. For more detailed information about the functions supported by the coin-flow package and use cases, you can view the github document for more detailed content: [coin-flow function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-flow/README.md#using-flow-sdk). ### coin-near Near Protocol is a scalable blockchain platform that achieves high throughput and low latency transaction processing by using a novel consensus mechanism and sharding technology. Near SDK allows developers to interact more conveniently with the Near blockchain. Near SDK is a toolkit for integrating with the Near Protocol, containing the main functions needed when interacting with the Near ecosystem. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-near ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getAddress | Get an address through a seed | | | validateAddress | Validate an address | | | signTransaction | Sign a transaction | | | transfer | Transfer a coin | | | fullAccessKey | Get a full access key | | | publicKeyFromSeed | Get a public key from a seed | | For more detailed information about the functions supported by the coin-near package and use cases, you can view the github document for more detailed content: [coin-near function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-near/README.md#using-near-sdk). ### coin-polkadot Polkadot is a multi-chain heterogeneous blockchain platform, which allows various blockchain networks to run in parallel with a shared security model, and can also realize seamless transfer of information and value between chains. Polkadot SDK is a toolkit for integrating with the Polkadot blockchain, containing the main functions needed when interacting with the Polkadot ecosystem. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-polkadot ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getAddress | Get an address through a seed | | | validateAddress | Validate an address | | | SignTx | Sign a transaction | | For more detailed information about the functions supported by the coin-polkadot package and use cases, you can view the github document for more detailed content: [coin-polkadot function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-polkadot/README.md#using-polkadot-sdk). ### coin-solana Solana is a high-performance blockchain platform that achieves high throughput and low latency transaction processing through an innovative consensus algorithm and block generation mechanism. Solana SDK is a toolkit for integrating the Solana blockchain, containing the main functions needed when interacting with the Solana ecosystem. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-solana ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | signMessage | Sign a message | | | calcTxHash | Get a transaction hash through a raw transaction | | | validSignedTransaction | Check a signed transaction | | | getHardWareRawTransaction | Get the raw transaction of the hardware | | | getHardWareSignedTransaction | Get the signed transaction of the hardware | | | getHardWareMessageHash | Get the message hash of the hardware | | For more detailed information about the functions supported by the coin-solana package and use cases, you can view the github document for more detailed content: [coin-solana function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-solana/README.md#using-solana-sdk). ### coin-stacks Stacks is an open-source blockchain platform that allows developers to build smart contracts and decentralized applications on the Stacks blockchain. Stacks SDK is mainly used to integrate Stacks blockchain, containing various functions that can be used for web3 wallets. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-stacks ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | signMessage | Sign a message | | | verifyMessage | Verify a signed message | | | calcTxHash | Get a transaction hash through a raw transaction | | | getRawTransaction | Get a raw transaction | | For more detailed information about the functions supported by the coin-stacks package and use cases, you can view the github document for more detailed content: [coin-stacks function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-stacks/README.md#using-stacks-sdk). ### coin-starknet StarkNet is a decentralized, scalable blockchain network that uses zero-knowledge proof technology to enhance the efficiency and security of transaction processing. StarkNet SDK is a toolkit for integrating the StarkNet blockchain, providing a series of functional methods that make it easier for developers to interact with the StarkNet blockchain. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-starknet ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | signMessage | Sign a message | | | verifyMessage | Verify a signed message | | For more detailed information about the functions supported by the coin-starknet package and use cases, you can view the github document for more detailed content: [coin-starknet function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-starknet/README.md#using-starknet-sdk). ### coin-sui SUI SDK is a toolkit for integrating the SUI blockchain, containing various functions that can be used for web3 wallets. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-sui ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | signMessage | Sign a message | | | calcTxHash | Get a transaction hash through a raw transaction | | Note: Unlike secp256k1, ed25519 only supports hard mode derivation for private keys. For more details, refer to: https://github.com/satoshilabs/slips/blob/master/slip-0010.md For more detailed information about the functions supported by the coin-sui package and use cases, you can view the github document for more detailed content: [coin-sui function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-sui/README.md#usage). ### coin-tron TRON SDK is a toolkit for integrating the TRON blockchain, containing various functions that can be used for web3 wallets. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-tron ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | validPrivateKey | Validate a private key | | | signMessage | Sign a message | | | verifyMessage | Verify a signed message | | | ecRecover | Recover a signature to a public key | | | getAddressByPublicKey | Get an address through a public key | | | getHardWareRawTransaction | Get the raw transaction of the hardware | | | getHardWareSignedTransaction | Get the signed transaction of the hardware | | | getHardWareMessageHash | Get the message hash of the hardware | | | calcTxHash | Get a transaction hash through a raw transaction | | | getRawTransaction | Generate raw transaction data | | | validSignedTransaction | Check a signed transaction | | For more detailed information about the functions supported by the coin-tron package and use cases, you can view the github document for more detailed content: [coin-tron function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-tron/README.md#using-trx-sdk). ### coin-zkspace ZKSpace SDK is mainly used to integrate ZK contracts, containing various functions that can be used for web3 wallets. In addition to ZKSpace, it also supports zkSync. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-zkspace ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | validPrivateKey | Validate a private key | | | signMessage | Sign a message | | | verifyMessage | Verify a signed message | | | ecRecover | Recover a signature to a public key | | | getAddressByPublicKey | Get an address through a public key | | | getHardWareRawTransaction | Get the raw transaction of the hardware | | | getHardWareSignedTransaction | Get the signed transaction of the hardware | | | getHardWareMessageHash | Get the message hash of the hardware | | | calcTxHash | Get a transaction hash through a raw transaction | | | getRawTransaction | Generate raw transaction data | | The transaction signature supports data types including: transfer and changePubkey. For more detailed information about the functions supported by the coin-zkspace package and use cases, you can view the github document for more detailed content: [coin-zkspace function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-zkspace/README.md#using-zkspace-sdk). ## Test Cases On github, there is a `tests` directory under the package corresponding to each module, which contains test cases for various coin modules. You can learn more about the usage of functions in the SDK through these test cases. | Coin family | Test case | Remarks | | --- | --- | --- | | BTC | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-bitcoin/tests/btc.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-bitcoin/tests/btc.test.ts) | | | ETH | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-ethereum/tests/eth.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-ethereum/tests/eth.test.ts) | | | Cosmos | [https://github.com/okx/js-wallet-sdk/tree/main/packages/coin-cosmos/tests](https://github.com/okx/js-wallet-sdk/tree/main/packages/coin-cosmos/tests) | | | Aptos | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-aptos/tests/aptos.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-aptos/tests/aptos.test.ts) | | | EOS | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-eos/tests/eos.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-eos/tests/eos.test.ts) | | | Solana | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-solana/tests/sol.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-solana/tests/sol.test.ts) | | | Stacks | [https://github.com/okx/js-wallet-sdk/tree/main/packages/coin-stacks/tests](https://github.com/okx/js-wallet-sdk/tree/main/packages/coin-stacks/tests) | | | Starknet | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-starknet/tests/crypto.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-starknet/tests/crypto.test.ts) | | | SUI | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-sui/tests/crypto.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-sui/tests/crypto.test.ts) | | | TRON | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-tron/tests/trx.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-tron/tests/trx.test.ts) | | | Zkspace | [https://github.com/okx/js-wallet-sdk/tree/main/packages/coin-zkspace/tests](https://github.com/okx/js-wallet-sdk/tree/main/packages/coin-zkspace/tests) | | | Flow | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-flow/tests/flow.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-flow/tests/flow.test.ts) | | | Near | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-near/tests/near.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-near/tests/near.test.ts) | | | Polkadot | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-polkadot/tests/dot.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-polkadot/tests/dot.test.ts) | | ## Supported Coins | Coin family | Coin | Derivation path | | --- | --- | --- | | BTC | BTC | Regular address:
m/44'/0'/0/0'/0
SegWit:
m/49'/0'/0/0'/0
m/84'/0'/0/0'/0
m/86'/0'/0/0'/0 | | BTC | BCH | m/44'/145'/0'/0/0 | | BTC | BSV | m/44'/236'/0'/0/0 | | BTC | LTC | m/44'/2'/0'/0/0 | | BTC | Doge | m/44'/3'/0'/0/0 | | BTC | TBTC | m/44'/0'/0/0'/0 | | BTC | Omni USDT | m/44'/0'/0/0'/0 | | ETH | ETH | m/44'/60'/0'/0/0 | | ETH | Arbitrum One | m/44'/60'/0'/0/0 | | ETH | Arbitrum Nova | m/44'/60'/0'/0/0 | | ETH | Avalanche C | m/44'/60'/0'/0/0 | | ETH | Boba | m/44'/60'/0'/0/0 | | ETH | BNB Chain | m/44'/60'/0'/0/0 | | ETH | Base | m/44'/60'/0'/0/0 | | ETH | Core | m/44'/60'/0'/0/0 | ETH | Cronos(EVM) | m/44'/60'/0'/0/0 | | ETH | Celo | m/44'/60'/0'/0/0 | | ETH | Conflux(EVM) | m/44'/60'/0'/0/0 | | ETH | Endurance | m/44'/60'/0'/0/0 | | ETH | EthereumPoW | m/44'/60'/0'/0/0 | | ETH | EthereumFair | m/44'/60'/0'/0/0 | | ETH | Filecoin EVM | m/44'/60'/0'/0/0 | | ETH | Fantom | m/44'/60'/0'/0/0 | | ETH | Flare | m/44'/60'/0'/0/0 | | ETH | Gnosis | m/44'/60'/0'/0/0 | | ETH | Goerli | m/44'/60'/0'/0/0 | | ETH | HAQQ Network | m/44'/60'/0'/0/0 | | ETH | Klaytn | m/44'/60'/0'/0/0 | | ETH | KCC | m/44'/60'/0'/0/0 | | ETH | Kava EVM | m/44'/60'/0'/0/0 | | ETH | Linea | m/44'/60'/0'/0/0 | | ETH | Metis | m/44'/60'/0'/0/0 | | ETH | Moonebeam | m/44'/60'/0'/0/0 | | ETH | Moonriver | m/44'/60'/0'/0/0 | | ETH | Mantle | m/44'/60'/0'/0/0 | | ETH | Omega Network | m/44'/60'/0'/0/0 | | ETH | OKTC | m/44'/60'/0'/0/0 | | ETH | Optimism | m/44'/60'/0'/0/0 | | ETH | opBNB | m/44'/60'/0'/0/0 | | ETH | Polygon | m/44'/60'/0'/0/0 | | ETH | Polygon zkEVM | m/44'/60'/0'/0/0 | | ETH | PulseChain | m/44'/60'/0'/0/0 | | ETH | Sepolia | m/44'/60'/0'/0/0 | | ETH | zkSync Era | m/44'/60'/0'/0/0 | | ETH | ZetaChian | m/44'/60'/0'/0/0 | | Cosmos | Atom | m/44'/118'/0'/0/0 | | Cosmos | Axelar | m/44'/118'/0'/0/0 | | Cosmos | Cronos | m/44'/394'/0'/0/0 | | Cosmos | Osmos | m/44'/118'/0'/0/0 | | Cosmos | Evmos | m/44'/60'/0'/0/0 | | Cosmos | Iris | m/44'/118'/0'/0/0 | | Cosmos | Juno | m/44'/118'/0'/0/0 | | Cosmos | Kava | m/44'/459'/0'/0/0 | | Cosmos | Kujira | m/44'/118'/0'/0/0 | | Cosmos | Secret | m/44'/529'/0'/0/0 | | Cosmos | Sei | m/44'/118'/0'/0/0 | | Cosmos | Stargaze | m/44'/118'/0'/0/0 | | Cosmos | Terra | m/44'/330'/0'/0/0 | | Aptos | Aptos | m/44'/637'/0'/0/0 | | EOS | EOS | m/44'/194'/0'/0/0 | | Solana | Solana | m/44'/501'/0'/0/0 | | Stacks | Stacks | m/44'/5757'/0'/0/0 | | ETH lay2 | Starknet | m/44'/9004'/0'/0/0 | | SUI | SUI | m/44'/784'/0'/0/0 | | TRX | TROM | m/44'/195'/0'/0/0 | | ETH lay2 | ZKSpace | m/44'/60'/0'/0/0 | | ETH lay2 | zkSync | m/44'/60'/0'/0/0 | - [Go Signing SDK](https://web3.okx.com/onchainos/dev-docs-v5/dex-api/private-key-wallet-go-sdk.md) # Go Signing SDK ## Overview Go-wallet-sdk is a wallet solution based on Go language that includes various public chains' different cryptographic algorithms and common functionalities. You can use it for creating private keys, addresses, assembling transactions, and performing signatures, among other things. This document will provide a detailed guide on how to use this SDK. Currently, it supports various mainstream blockchains, with each token format having its own independent module implementation. We will continue to add support for more blockchains in the future. ### Supported Platforms As a Go SDK, it can be easily integrated into Web applications, mobile applications, or desktop applications. ## Installation and Building ### Go GET To use the Signing SDK, you first need to install it. You can use `go get` to get the latest version. Our Signing SDK supports two types of packages: public packages and single coin modules. Public packages are for all currencies: ```bash go get -u github.com/okx/go-wallet-sdk/crypto ``` Integration of individual currencies, taking ETH and BTC as examples: Integration of ETH: ```bash go get -u github.com/okx/go-wallet-sdk/coins/ethereum ``` Integration of BTC: ```bash go get -u github.com/okx/go-wallet-sdk/coins/bitcoin ``` ## Main Features Here is a specific introduction to the functions of each module in the Signing SDK. - crypto: This module provides commonly used security encryption algorithms and signature algorithms, etc. - coins: This module implements methods for building and signing transactions for each coin. Each coin has a corresponding module, such as ethereum, bitcoin, etc. These modules provide transaction building and signing methods for specific coins. ## Packages | Package name | Module | Description | | --- | --- | --- | | [github.com/okx/go-wallet-sdk/crypto](https://github.com/okx/go-wallet-sdk/tree/main/crypto) | crypto | We provide common functions about bip32, bip39, ecdsa, ed25519, etc. | | [github.com/okx/go-wallet-sdk/coins/aptos](https://github.com/okx/go-wallet-sdk/tree/main/coins/aptos) | aptos | Aptos SDK is used to interact with the Aptos blockchain, containing various functions that can be used for web3 wallets. | | [github.com/okx/go-wallet-sdk/coins/bitcoin](https://github.com/okx/go-wallet-sdk/tree/main/coins/bitcoin) | bitcoin | Bitcoin SDK is used to interact with the Bitcoin mainnet or testnet, containing various functions that can be used for web3 wallets. The SDK not only supports Bitcoin, but also supports the following chains: BTC, BSV, DOGE, LTC, TBTC. | | [github.com/okx/go-wallet-sdk/coins/cosmos](https://github.com/okx/go-wallet-sdk/tree/main/coins/cosmos) | cosmos | Cosmos SDK is used to interact with the Cosmos blockchain, containing various functions that can be used for web3 wallets. | | [github.com/okx/go-wallet-sdk/coins/eos](https://github.com/okx/go-wallet-sdk/tree/main/coins/eos) | eos | EOS SDK is used to interact with the EOS blockchain, containing various functions that can be used for web3 wallets. The SDK not only supports EOS, but also supports WAX. | | [github.com/okx/go-wallet-sdk/coins/ethereum](https://github.com/okx/go-wallet-sdk/tree/main/coins/ethereum) | ethereum | Ethereum SDK is used to interact with the Ethereum blockchain or Evm blockchain, containing various functions that can be used for web3 wallets. | | [github.com/okx/go-wallet-sdk/coins/flow](https://github.com/okx/go-wallet-sdk/tree/main/coins/flow) | flow | Flow SDK is used to interact with the Flow blockchain, containing various functions that can be used for web3 wallets. | | [github.com/okx/go-wallet-sdk/coins/near](https://github.com/okx/go-wallet-sdk/tree/main/coins/near) | near | Near SDK is used to interact with the Near Protocol, containing the main functions needed when interacting with the Near ecosystem. | | [github.com/okx/go-wallet-sdk/coins/polkadot](https://github.com/okx/go-wallet-sdk/tree/main/coins/polkadot) | polkadot | Polkadot SDK is used to interact with the Polkadot blockchain, containing the main functions needed when interacting with the Polkadot ecosystem. | | [github.com/okx/go-wallet-sdk/coins/solana](https://github.com/okx/go-wallet-sdk/tree/main/coins/solana) | solana | Solana SDK is used to interact with the Solana chain, containing the main functions needed when interacting with the Solana ecosystem. | | [github.com/okx/go-wallet-sdk/coins/stacks](https://github.com/okx/go-wallet-sdk/tree/main/coins/stacks) | stacks | Stacks SDK is used to interact with the Stacks blockchain, containing various functions that can be used for web3 wallets. | | [github.com/okx/go-wallet-sdk/coins/starknet](https://github.com/okx/go-wallet-sdk/tree/main/coins/starknet) | starknet | Starknet SDK is used to interact with the Starknet blockchain, containing various functions that can be used for web3 wallets. | | [github.com/okx/go-wallet-sdk/coins/sui](https://github.com/okx/go-wallet-sdk/tree/main/coins/sui) | sui | SUI SDK is used to interact with the SUI blockchain, containing various functions that can be used for web3 wallets. | | [github.com/okx/go-wallet-sdk/coins/tron](https://github.com/okx/go-wallet-sdk/tree/main/coins/tron) | tron | TRX SDK is used to interact with the TRON blockchain, containing various functions that can be used for web3 wallets. | | [github.com/okx/go-wallet-sdk/coins/zkspace](https://github.com/okx/go-wallet-sdk/tree/main/coins/zkspace) | zkspace | ZKSpace SDK is used to interact with ZK contracts, containing various functions that can be used for web3 wallets. The SDK not only supports ZKSpace, but also supports zkSync. | ### crypto This is a library that includes implementations of commonly used security encryption and signature algorithms such as BIP32, BIP39, ECDSA, ED25519, etc. For example: - Common BIP32 functions: These functions are mainly used to handle and operate tasks related to the Bitcoin Improvement Payment Protocol (BIP32). - BIP39 mnemonic generation, public/private key, and message signing functions: These functions are mainly used to handle and operate tasks related to the Bitcoin Improvement Payment Protocol (BIP39), such as generating mnemonics, public/private keys, and signing messages. - Common hash and encoding/decoding functions: These functions are mainly used to handle common hash and encoding/decoding tasks, such as SHA256 hashing, Base64 encoding/decoding, etc. - Common ED25519 signature functions: These functions are mainly used to handle and operate tasks related to the ED25519 signature algorithm. - Common ECDSA signature functions: These functions are mainly used to handle and operate tasks related to the Elliptic Curve Digital Signature Algorithm (ECDSA). To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/crypto ``` ### aptos-sdk Aptos SDK is mainly used to integrate Aptos blockchain, containing functions such as private key generation, private key derivation, address generation, and transaction transfer. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/aptos ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Generate a new address from a private key | | ValidateAddress | Validate an address | | SignRawTransaction | Sign a transaction | Aptos transaction support types are: "transfer", "tokenTransfer", "tokenMint", "tokenBurn", "tokenRegister", "dapp", "simulate", "offerNft", "claimNft", "offerNft_simulate", "claimNft_simulate" For more detailed information about the functions supported by the aptos-sdk package and use cases, you can view the github document for more detailed content: [coin-aptos function functions](https://github.com/okx/go-wallet-sdk/blob/main/coins/aptos/). ### bitcoin-sdk coin-bitcoin is an SDK for integrating the Bitcoin blockchain. It supports both the Bitcoin mainnet and testnet, and provides a series of functional methods, making it easier for developers to interact with the Bitcoin blockchain. In addition to BTC, it also supports other cryptocurrencies such as BSV, DOGE, LTC, and TBTC. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/bitcoin ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get a new address through a private key | | SignTx | Sign a transaction | | GenerateUnsignedPSBTHex | Generate a PSBT transaction | For more detailed information about the functions supported by the bitcoin-sdk package and use cases, you can view the github document for more detailed content: [coin-bitcoin function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/bitcoin). ### cosmos-sdk Cosmos SDK is a toolkit for integrating with the Cosmos blockchain, providing a series of functional methods, including generating private keys, deriving private keys, generating addresses, and transferring transactions. It supports currencies including: - Atom - Axelar - Cronos - Evmos - Iris - Juno - Kava - Kujira - Osmos - Secret - Sei - Stargaze - Terra To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/cosmos ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get a new address through a private key | | Transfer | Sign a transaction | | SignMessage | Sign a message | For more detailed information about the functions supported by the cosmos-sdk package and use cases, you can view the github document for more detailed content: [coin-cosmos function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/cosmos). ### eos-sdk EOS SDK is a toolkit for integrating with the EOS blockchain. It provides a series of functional methods, including generating private keys, deriving private keys, generating addresses, and transaction serialization. In addition to EOS, it also supports the Wax coin. These functional methods make it easier for developers to interact with the EOS blockchain, including creating and managing wallets, sending and receiving transactions, and querying blockchain information. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/eos ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get a new address through a private key | | SignTransaction | Sign a transaction | For more detailed information about the functions supported by the eos-sdk package and use cases, you can view the github document for more detailed content: [coin-eos function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/eos). ### ethereum-sdk Ethereum SDK is a toolkit for integrating with the Ethereum blockchain and other blockchains that support EVM (Ethereum Virtual Machine). It provides a series of functional methods, including generating private keys, deriving private keys, generating addresses, and transferring transactions. These functional methods make it easier for developers to interact with the Ethereum blockchain, including creating and managing wallets, sending and receiving transactions, and querying blockchain information. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/ethereum ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get a new address through a private key | | SignTransaction | Sign a transaction | | SignMessage | Sign a message | For more detailed information about the functions supported by the coin-ethereum package and use cases, you can view the github document for more detailed content: [coin-ethereum function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/ethereum). ### flow-sdk Flow blockchain is a next-generation, future-oriented blockchain platform, specifically designed for high-performance applications and games. Flow SDK is a toolkit for integrating with the Flow blockchain. It provides a series of functional methods, enabling developers to interact more conveniently with the Flow blockchain. The specific functionalities offered by the SDK can facilitate the development of applications on the Flow blockchain. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/flow ``` Supported functions: | Function name | Functionality | | --- | --- | | CreateNewAccountTx | Create a new account | | SignTx | Sign a transaction | Flow supports two types of transactions: Account and Transfer. For more detailed information about the functions supported by the coin-flow package and use cases, you can view the github document for more detailed content: [coin-flow function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/flow). ### near-sdk Near Protocol is a scalable blockchain platform that achieves high throughput and low latency transaction processing by using a novel consensus mechanism and sharding technology. Near SDK allows developers to interact more conveniently with the Near blockchain. Near SDK is a toolkit for integrating with the Near Protocol, containing the main functions needed when interacting with the Near ecosystem. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/near ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAccount | Get an address through a seed | | SignTransaction | Sign a transaction | | Transfer | Transfer a coin | | FullAccessKey | Get a full access key | | PublicKeyFromSeed | Get a public key from a seed | For more detailed information about the functions supported by the near-sdk package and use cases, you can view the github document for more detailed content: [coin-near function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/near). ### polkadot-sdk Polkadot is a multi-chain heterogeneous blockchain platform, which allows various blockchain networks to run in parallel with a shared security model, and can also realize seamless transfer of information and value between chains. Polkadot SDK is a toolkit for integrating with the Polkadot blockchain, containing the main functions needed when interacting with the Polkadot ecosystem. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/polkadot ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get an address through a seed | | SignTx | Sign a transaction | For more detailed information about the functions supported by the polkadot-sdk package and use cases, you can view the github document for more detailed content: [coin-polkadot function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/polkadot). ### solana-sdk Solana is a high-performance blockchain platform that achieves high throughput and low latency transaction processing through an innovative consensus algorithm and block generation mechanism. Solana SDK is a toolkit for integrating the Solana blockchain, containing the main functions needed when interacting with the Solana ecosystem. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/solana ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get a new address through a private key | | SignTransaction | Sign a transaction | For more detailed information about the functions supported by the solana-sdk package and use cases, you can view the github document for more detailed content: [coin-solana function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/solana). ### stacks-sdk Stacks is an open-source blockchain platform that allows developers to build smart contracts and decentralized applications on the Stacks blockchain. Stacks SDK is mainly used to integrate Stacks blockchain, containing various functions that can be used for web3 wallets. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/stacks ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get a new address through a private key | | Transfer | Sign a transaction | For more detailed information about the functions supported by the stacks-sdk package and use cases, you can view the github document for more detailed content: [coin-stacks function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/stacks). ### starknet-sdk StarkNet is a decentralized, scalable blockchain network that uses zero-knowledge proof technology to enhance the efficiency and security of transaction processing. StarkNet SDK is a toolkit for integrating the StarkNet blockchain, providing a series of functional methods that make it easier for developers to interact with the StarkNet blockchain. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/starknet ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get a new address through a private key | | CreateSignedContractTx | Sign a transaction | For more detailed information about the functions supported by the starknet-sdk package and use cases, you can view the github document for more detailed content: [coin-starknet function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/starknet). ### sui-sdk SUI SDK is a toolkit for integrating the SUI blockchain, containing various functions that can be used for web3 wallets. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/sui ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get a new address through a private key | | SignTransaction | Sign a transaction | | SignMessage | Sign a message | Note: Unlike SECP256K1, ED25519 only supports hard mode derivation for private keys. For more details, refer to: https://github.com/satoshilabs/slips/blob/master/slip-0010.md For more detailed information about the functions supported by the sui-sdk package and use cases, you can view the github document for more detailed content: [coin-sui function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/sui). ### tron-sdk TRON SDK is a toolkit for integrating the TRON blockchain, containing various functions that can be used for web3 wallets. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/tron ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get a new address through a private key | | SignTransaction | Sign a transaction | For more detailed information about the functions supported by the tron-sdk package and use cases, you can view the github document for more detailed content: [coin-tron function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/tron). ### zkspace-sdk ZKSpace SDK is mainly used to integrate ZK contracts, containing various functions that can be used for web3 wallets. In addition to ZKSpace, it also supports zkSync. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/zkspace ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get a new address through a private key | | CreateSignTransferTx | Sign a transaction | The transaction signature supports data types including: transfer and changePubkey. For more detailed information about the functions supported by the coin-zkspace package and use cases, you can view the github document for more detailed content: [coin-zkspace function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/zkspace). ## Test Cases On GitHub, each module has a corresponding `tests` directory under its package. This directory contains test cases for various coin modules. You can learn more about the usage of functions in the SDK through these test cases. | Coin Family | Test Case | | --- | --- | | BTC | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-bitcoin/tests/btc.test.ts) | | ETH | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-ethereum/tests/eth.test.ts) | | Cosmos | [Test Case](https://github.com/okx/js-wallet-sdk/tree/main/packages/coin-cosmos/tests) | | Aptos | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-aptos/tests/aptos.test.ts) | | EOS | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-eos/tests/eos.test.ts) | | Solana | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-solana/tests/sol.test.ts) | | Stacks | [Test Case](https://github.com/okx/js-wallet-sdk/tree/main/packages/coin-stacks/tests) | | Starknet | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-starknet/tests/crypto.test.ts) | | SUI | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-sui/tests/crypto.test.ts) | | TRON | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-tron/tests/trx.test.ts) | | Zkspace | [Test Case](https://github.com/okx/js-wallet-sdk/tree/main/packages/coin-zkspace/tests) | | Flow | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-flow/tests/flow.test.ts) | | Near | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-near/tests/near.test.ts) | | Polkadot | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-polkadot/tests/dot.test.ts) | ## Supported Coins | Coin Family | Coin | Derivation Path | | --- | --- | --- | | BTC | BTC | Regular address:
m/44'/0'/0/0'/0
SegWit:
m/49'/0'/0/0'/0
m/84'/0'/0/0'/0
m/86'/0'/0/0'/0 | | BTC | BCH | m/44'/145'/0'/0/0 | | BTC | BSV | m/44'/236'/0'/0/0 | | BTC | LTC | m/44'/2'/0'/0/0 | | BTC | Doge | m/44'/3'/0'/0/0 | | BTC | TBTC | m/44'/0'/0/0'/0 | | BTC | Omni USDT | m/44'/0'/0/0'/0 | | ETH | ETH | m/44'/60'/0'/0/0 | | ETH | Arbitrum One | m/44'/60'/0'/0/0 | | ETH | Arbitrum Nova | m/44'/60'/0'/0/0 | | ETH | Avalanche C | m/44'/60'/0'/0/0 | | ETH | Boba | m/44'/60'/0'/0/0 | | ETH | BNB Chain | m/44'/60'/0'/0/0 | | ETH | Base | m/44'/60'/0'/0/0 | | ETH | Core | m/44'/60'/0'/0/0 | | ETH | Cronos(EVM) | m/44'/60'/0'/0/0 | | ETH | Celo | m/44'/60'/0'/0/0 | | ETH | Conflux(EVM) | m/44'/60'/0'/0/0 | | ETH | Endurance | m/44'/60'/0'/0/0 | | ETH | EthereumPoW | m/44'/60'/0'/0/0 | | ETH | EthereumFair | m/44'/60'/0'/0/0 | | ETH | Filecoin EVM | m/44'/60'/0'/0/0 | | ETH | Fantom | m/44'/60'/0'/0/0 | | ETH | Flare | m/44'/60'/0'/0/0 | | ETH | Gnosis | m/44'/60'/0'/0/0 | | ETH | Goerli | m/44'/60'/0'/0/0 | | ETH | HAQQ Network | m/44'/60'/0'/0/0 | | ETH | Klaytn | m/44'/60'/0'/0/0 | | ETH | KCC | m/44'/60'/0'/0/0 | | ETH | Kava EVM | m/44'/60'/0'/0/0 | | ETH | Linea | m/44'/60'/0'/0/0 | | ETH | Metis | m/44'/60'/0'/0/0 | | ETH | Moonebeam | m/44'/60'/0'/0/0 | | ETH | Moonriver | m/44'/60'/0'/0/0 | | ETH | Mantle | m/44'/60'/0'/0/0 | | ETH | Omega Network | m/44'/60'/0'/0/0 | | ETH | OKTC | m/44'/60'/0'/0/0 | | ETH | Optimism | m/44'/60'/0'/0/0 | | ETH | opBNB | m/44'/60'/0'/0/0 | | ETH | Polygon | m/44'/60'/0'/0/0 | | ETH | Polygon zkEVM | m/44'/60'/0'/0/0 | | ETH | PulseChain | m/44'/60'/0'/0/0 | | ETH | Sepolia | m/44'/60'/0'/0/0 | | ETH | zkSync Era | m/44'/60'/0'/0/0 | | ETH | ZetaChian | m/44'/60'/0'/0/0 | | Cosmos | Atom | m/44'/118'/0'/0/0 | | Cosmos | Axelar | m/44'/118'/0'/0/0 | | Cosmos | Cronos | m/44'/394'/0'/0/0 | | Cosmos | Osmos | m/44'/118'/0'/0/0 | | Cosmos | Evmos | m/44'/60'/0'/0/0 | | Cosmos | Iris | m/44'/118'/0'/0/0 | | Cosmos | Juno | m/44'/118'/0'/0/0 | | Cosmos | Kava | m/44'/459'/0'/0/0 | | Cosmos | Kujira | m/44'/118'/0'/0/0 | | Cosmos | Secret | m/44'/529'/0'/0/0 | | Cosmos | Sei | m/44'/118'/0'/0/0 | | Cosmos | Stargaze | m/44'/118'/0'/0/0 | | Cosmos | Terra | m/44'/330'/0'/0/0 | | Aptos | Aptos | m/44'/637'/0'/0/0 | | EOS | EOS | m/44'/194'/0'/0/0 | | Solana | Solana | m/44'/501'/0'/0/0 | | Stacks | Stacks | m/44'/5757'/0'/0/0 | | ETH Layer 2 | Starknet | m/44'/9004'/0'/0/0 | | SUI | SUI | m/44'/784'/0'/0/0 | | TRX | TRON | m/44'/195'/0'/0/0 | | ETH Layer 2 | ZKSpace | m/44'/60'/0'/0/0 | | ETH Layer 2 | zkSync | m/44'/60'/0'/0/0 | ## OKX Wallet Documentation - [What is OKX OS](https://web3.okx.com/onchainos/docs/waas/okx-waas-what-is-waas.md) # What is OKX OS OKX OS is a comprehensive Web3 development solution that standardizes the integration of public chains and protocols, significantly reducing development time and costs. It covers four major scenarios: Wallet, DEX, Marketplace, and DeFi. **OKX OS offers the most powerful data querying capabilities, deeply analyzing asset data, transaction history, project information, and more.** It supports over 60 networks, including EVM, UTXO, Solana, TON, TRON, and cutting-edge ecosystems like inscriptions. If you are looking to build your own Web3 service, adopting OKX OS will be a more efficient and cost-effective choice. For more Web3 workflows and basic principles, you can view the technical architecture: ![Architecture Diagram](../images/web3-wallet-architecture-en.jpg) - [Preparation](https://web3.okx.com/onchainos/docs/waas/okx-waas-requirement-standard.md) # Preparation This section introduces the prerequisite steps for integrating with OKX OS, as well as authentication and environment configuration. - [Use the developer portal](https://web3.okx.com/onchainos/docs/waas/introduction-to-developer-portal-interface.md) # Use the developer portal In order to be more efficient in building your own applications, this article will cover the features of the developer management platform and the best ways to use it ## Create project ### Use the Developer portal to get started ### Step 1:Create/log in to your account 1. Click on the '[developer portal](https://web3.okx.com/web3/build/dev-portal)' under the navigation bar **developer center** 2. Click **Connect Wallet** to create or log in to an account. 3. Select the wallet you want to connect to. OKX Wallet is recommended for connection. 4. After selecting the wallet, click **Verify**, a window will pop up at the wallet. Click **Signature** in your wallet. Congrats! You have successfully created an account and are logged into the developer management platform. ### Step 2:Create a new project 1. To create a new project, just enter the project name and project description (optional), then click the **Confirm** button to create a new project. 2. After creating a new project, you can see the details of the project under the **Project** option. 3. If you want to create another project, click **Create a new project**. ## Generate API keys ### Prepared knowledge **API key**:Provides a unique identifier for the application or user to interact with the API. **Secret Key**:Works with API keys to provide additional security by adding a security token. **Passphrase**:Used to encrypt Secret keys on the OKX OS server to provide additional security. Passphrase is also used to view Secret keys and modify API information. ### Generate a new API key 1. Click the **Manage** button in the project where you want to create the API key. 2. Click the **Create API key** button. 3. Enter the name of **API key** and **Passphrase**, click **Create** to generate the corresponding API key. **Passphrase** is required to use the API. Once the Passphrase is lost, the API key will no longer be available. Remember the passphrase. Congrats! You have successfully created the API key. ### View the Secret Key When making a request to the API, you need to also provide the Secret Key. Click the **Copy** button on the right to view your Secret Key. - [REST API authentication](https://web3.okx.com/onchainos/docs/waas/rest-authentication.md) # REST API authentication ## Initiate a request All REST private request headers must contain the following: - `OK-ACCESS-KEY` string APIKey(follow [this guide])(./introduction-to-developer-portal-interface#generate-api-keys) to generate an API key - `OK-ACCESS-SIGN` uses the HMAC SHA256 hash function to get the hash value, then uses Base-64 encoding (see signature) - `OK-ACCESS-TIMESTAMP` specifies the time (UTC) when the request is initiated, for example, 2020-12-08T09:08:57.715Z - `OK-ACCESS-PASSPHRASE` represents the Passphrase you specified when creating the API key Some endpoints, require additional headers: - `OK-ACCESS-PROJECT` The project ID of your project (found under Project Details) All requests should have content of type 'application/json' and be valid JSON. ## Signature `OK-ACCESS-SIGN`request header: - is a combination of timestamp + method + requestPath + body strings (+ indicates string connection) and SecretKey, which is encrypted using the HMAC SHA256 method and output through Base-64 encoding. - Prepare the Secret Key (generated when the API key is created). - Use HMAC SHA256 to sign the pre-hash string with a key. - Encodes the signature in Base64 format. Example: `sign=CryptoJS.enc.Base64.stringify(CryptoJS.HmacSHA256(timestamp + 'GET' + '/api/v5/account/balance?ccy=BTC', SecretKey))` - The value of 'timestamp' is the same as the request header of 'OK-ACCESS-TIMESTAMP' and is in ISO format - For example:`2020-12-08T09:08:57.715Z` - method indicates the request method. All letters are uppercase - For example:`GET/POST` - requestPath specifies the request interface path - For example:`/api/v5/account/balance` - body is the string that requests the body. If the request does not have a body (usually a GET request), the body can be omitted - For example:`{"instId":"BTC-USDT","lever":"5","mgnMode":"isolated"}` - `GET`the request parameter is counted as requestPath, not body ## Postman example Postman is a popular API development and testing tool that allows developers to design, test, and document APIs. It provides a user-friendly graphical interface for making HTTP requests to APIs. If you have not installed Postman, you can download it for free from the Postman website: https://www.postman.com/ This example requires you to have a basic understanding of Postman. ### Add parameters - This typically applies to GET requests. - If your request requires query parameters, you can add them under the **Params** tab. Here, you can add key-value pairs for your query parameters. ![img](../images/postman1.png) ### Set headers Under the **Headers** tab, add the following key-value pairs: - `OK-ACCESS-KEY` - `OK-ACCESS-PASSPHRASE` - `OK-ACCESS-PROJECT` (if required) ![img](../images/postman2.png) ### Add body - This typically applies to POST requests. - If your request requires a request body, you can add them under the **Body** tab. - Select **raw** and **JSON** under the dropdown menu. - Input your request body in JSON format. ![img](../images/postman3.png) ### Set pre-request script - This is used to generate the necessary signature (`OK-ACCESS-SIGN`) and timestamp (`OK-ACCESS-TIMESTAMP`) - Under the **Pre-request Script** tab, insert the script which corresponds to the request type. - Exclude the request body when generating the prehash string for GET requests. - Edit the secret key accordingly. GET requests: ```javascript var method = pm.request.method; var now = new Date(); var isoString = now.toISOString(); var path = pm.request.url.getPathWithQuery(); var sign=CryptoJS.enc.Base64.stringify(CryptoJS.HmacSHA256(isoString + method + path, pm.variables.replaceIn('{{secret_key}}'))); pm.request.headers.add({ key: 'OK-ACCESS-SIGN', value: sign }); pm.request.headers.add({ key: 'OK-ACCESS-TIMESTAMP', value: isoString }); ``` POST requests: ```javascript var method = pm.request.method; var now = new Date(); var isoString = now.toISOString(); var path = pm.request.url.getPathWithQuery(); var bodyStr = pm.request.body.raw; var sign=CryptoJS.enc.Base64.stringify(CryptoJS.HmacSHA256(isoString + method + path + bodyStr, pm.variables.replaceIn('{{secret_key}}'))) pm.request.headers.add({ key: 'OK-ACCESS-SIGN', value: sign }); pm.request.headers.add({ key: 'OK-ACCESS-TIMESTAMP', value: isoString }); ``` ## Javascript example To invoke the API through a Javascript script, refer to the following code example: ```javascript const https = require('https'); const crypto = require('crypto'); const querystring = require('querystring'); // Define API credentials and project ids const api_config = { "api_key": '', "secret_key": '', "passphrase": '', "project": '' // This applies only to onchainOS APIs }; function preHash(timestamp, method, request_path, params) { // Create a pre-signature based on strings and parameters let query_string = ''; if (method === 'GET' && params) { query_string = '?' + querystring.stringify(params); } if (method === 'POST' && params) { query_string = JSON.stringify(params); } return timestamp + method + request_path + query_string; } function sign(message, secret_key) { // Use HMAC-SHA256 to sign the pre-signed string const hmac = crypto.createHmac('sha256', secret_key); hmac.update(message); return hmac.digest('base64'); } function createSignature(method, request_path, params) { // Get the timestamp in ISO 8601 format const timestamp = new Date().toISOString().slice(0, -5) + 'Z'; // Generate a signature const message = preHash(timestamp, method, request_path, params); const signature = sign(message, api_config['secret_key']); return { signature, timestamp }; } function sendGetRequest(request_path, params) { // Generate a signature const { signature, timestamp } = createSignature("GET", request_path, params); // Generate the request header const headers = { 'OK-ACCESS-KEY': api_config['api_key'], 'OK-ACCESS-SIGN': signature, 'OK-ACCESS-TIMESTAMP': timestamp, 'OK-ACCESS-PASSPHRASE': api_config['passphrase'], 'OK-ACCESS-PROJECT': api_config['project'] // This applies only to WaaS APIs }; const options = { hostname: 'web3.okx.com', path: request_path + (params ? `?${querystring.stringify(params)}` : ''), method: 'GET', headers: headers }; const req = https.request(options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { console.log(data); }); }); req.end(); } function sendPostRequest(request_path, params) { // Generate a signature const { signature, timestamp } = createSignature("POST", request_path, params); // Generate the request header const headers = { 'OK-ACCESS-KEY': api_config['api_key'], 'OK-ACCESS-SIGN': signature, 'OK-ACCESS-TIMESTAMP': timestamp, 'OK-ACCESS-PASSPHRASE': api_config['passphrase'], 'OK-ACCESS-PROJECT': api_config['project'], // This applies only to WaaS APIs 'Content-Type': 'application/json' // POST requests need this header }; const options = { hostname: 'web3.okx.com', path: request_path, method: 'POST', headers: headers }; const req = https.request(options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { console.log(data); }); }); if (params) { req.write(JSON.stringify(params)); } req.end(); } // GET request example const getRequestPath = '/api/v5/dex/aggregator/quote'; const getParams = { 'chainId': 42161, 'amount': 1000000000000, 'toTokenAddress': '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', 'fromTokenAddress': '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1' }; sendGetRequest(getRequestPath, getParams); // POST request example const postRequestPath = '/api/v5/mktplace/nft/ordinals/listings'; const postParams = { 'slug': 'sats' }; sendPostRequest(postRequestPath, postParams); ``` - [Node.js environment Settings](https://web3.okx.com/onchainos/docs/waas/nodejs-environment.md) # Node.js environment Settings ## 1. Import the necessary Node.js libraries First, import the necessary Node.js libraries and set up your environment variables. ```javascript const cryptoJS = require('crypto-js'); // Import encryption modules for subsequent encryption calculations const { Web3 } = require('web3'); // Import the Web3 library for interacting with Ethereum const fetch = (...args) => import('node-fetch').then(({ default: fetch }) => fetch(...args)); // Import the fetch library for making HTTP requests ``` ## 2. Set your environment variables Define base variables for subsequent requests and API urls, and initialize Web3. Web3 is a set of libraries that allow you to interact with local or remote Ethereum nodes using HTTP, IPC, or WebSocket. ```javascript const apiBaseUrl = 'https://web3.okx.com/'; // Define the underlying path of the request const web3RpcUrl = 'https://.....pro'; // The URL for the Ethereum node you want to connect to const privateKey = '0x...xxx'; // Set the private key of your wallet (replace '0x...xxx' with your actual private key). NEVER SHARE THIS WITH ANYONE! const chainId = '1'; const fromTokenAddress = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'; // Native token address const toTokenAddress = '0xdac17f958d2ee523a2206206994597c13d831ec7'; const userWalletAddress = '0x...35'; // User wallet address const secretKey = '31...D2'; // The key obtained from the previous application const apiKey = '42d0fd46-6f11-4681-a64a-9ba17d99d406'; // The api Key obtained from the previous application const passphrase = '*********'; // The password created when applying for the key const date = new Date(); // Get the current time const timestamp = date.toISOString(); // Convert the current time to the desired format const web3 = new Web3(new Web3.providers.HttpProvider(web3RpcUrl)); //Establishing web3 link ``` ## 3. Define helper functions Define helper functions that will be used to interact with the OKX API. ```javascript // Construct full API request URL const getRequestUrl = (apiBaseUrl, api, queryParams) => { return apiBaseUrl + api + '?' + new URLSearchParams(queryParams).toString(); }; const apiRequestUrl = getRequestUrl(apiBaseUrl, '/swap', swapParams); ``` ## 4. Assemble the header parameters Set the header properties. All the parameters are generic except for the apiRequestUrl parameter, which is generated based on different requests. ```javascript const headersParams = { 'Content-Type': 'application/json', 'OK-ACCESS-KEY': apiKey, 'OK-ACCESS-SIGN': cryptoJS.enc.Base64.stringify( cryptoJS.HmacSHA256(timestamp + 'GET' + '/api/v5/dex/aggregator/xxx?xxx=xxx', secretKey) ), 'OK-ACCESS-TIMESTAMP': timestamp, 'OK-ACCESS-PASSPHRASE': passphrase, }; ``` - [Supported Networks](https://web3.okx.com/onchainos/docs/waas/okx-waas-supported-networks.md) # Supported Networks ## EVM Networks | Chain | Wallet API | DEX API | Marketplace API | DeFi API | |----------------------------------|------------------------------------------|------------------------------------------------------|------------------------------------|-----------------------------| | Ethereum Mainnet | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap & Cross-chain](./dex-aggregation-root-quick-start) | [Supported](./marketplace-introduction) | [Supported](./defi-introduction) | | OP Mainnet | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap & Cross-chain](./dex-aggregation-root-quick-start) | [Supported](./marketplace-introduction) | [Supported](./defi-introduction) | | BNB Smart Chain Mainnet | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap & Cross-chain](./dex-aggregation-root-quick-start) | [Supported](./marketplace-introduction) | [Supported](./defi-introduction) | | OKT Chain | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap](./dex-aggregation-root-quick-start) | [Supported](./marketplace-introduction) | [Supported](./defi-introduction) | | X layer | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap](./dex-aggregation-root-quick-start) | [Supported](./marketplace-introduction) | [Supported](./defi-introduction) | | Polygon Mainnet | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap & Cross-chain](./dex-aggregation-root-quick-start) | [Supported](./marketplace-introduction) | [Supported](./defi-introduction) | | Arbitrum One | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap & Cross-chain](./dex-aggregation-root-quick-start) | [Supported](./marketplace-introduction) | [Supported](./defi-introduction) | | Avalanche C-Chain | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap & Cross-chain](./dex-aggregation-root-quick-start) | [Supported](./marketplace-introduction) | [Supported](./defi-introduction) | | zkSync Era Mainnet | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap & Cross-chain](./dex-aggregation-root-quick-start) | [Supported](./marketplace-introduction) | [Supported](./defi-introduction) | | Polygon zkEVM | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap & Cross-chain](./dex-aggregation-root-quick-start) | [Supported](./marketplace-introduction) | [Supported](./defi-introduction) | | Base | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap & Cross-chain](./dex-aggregation-root-quick-start) | [Supported](./marketplace-introduction) | | | Linea | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap & Cross-chain](./dex-aggregation-root-quick-start) | [Supported](./marketplace-introduction) | | | Fantom Opera | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap](./dex-aggregation-root-quick-start) | | [Supported](./defi-introduction) | | Mantle | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap & Cross-chain](./dex-aggregation-root-quick-start) | | [Supported](./defi-introduction) | | Conflux eSpace | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap](./dex-aggregation-root-quick-start) | | | | Metis Andromeda Mainnet | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap & Cross-chain](./dex-aggregation-root-quick-start) | | | | Merlin Chain | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap & Cross-chain](./dex-aggregation-root-quick-start) | | | | Blast | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap & Cross-chain](./dex-aggregation-root-quick-start) | | | | Manta Pacific Mainnet | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap & Cross-chain](./dex-aggregation-root-quick-start) | [Supported](./marketplace-introduction) | [Supported](./defi-introduction) | | opBNB Mainnet | [Supported](./walletapi-quickstart-multi-chain) | | [Supported](./marketplace-introduction) | [Supported](./defi-introduction) | | Kaia Network (Klaytn Mainnet) | [Supported](./walletapi-quickstart-multi-chain) | | [Supported](./marketplace-introduction) | | | Arbitrum Nova | [Supported](./walletapi-quickstart-multi-chain) | | [Supported](./marketplace-introduction) | | | Scroll | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap & Cross-chain](./dex-aggregation-root-quick-start) | [Supported](./marketplace-introduction) | | | Gnosis | [Supported](./walletapi-quickstart-multi-chain) | | | [Supported](./defi-introduction) | | Core Blockchain Mainnet | [Supported](./walletapi-quickstart-multi-chain) | | | [Supported](./defi-introduction) | | B^2 network | [Supported](./walletapi-quickstart-multi-chain) | | | | | Kroma | [Supported](./walletapi-quickstart-multi-chain) | | | | | Flare Mainnet | [Supported](./walletapi-quickstart-multi-chain) | | | | | Cronos Mainnet | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap](./dex-aggregation-root-quick-start) | | | | Ethereum Classic | [Supported](./walletapi-quickstart-multi-chain) | | | | | Immutable zkEVM | [Supported](./walletapi-quickstart-multi-chain) | | | | | KCC Mainnet | [Supported](./walletapi-quickstart-multi-chain) | | | | | PulseChain | [Supported](./walletapi-quickstart-multi-chain) | | | | | Omega Mainnet | [Supported](./walletapi-quickstart-multi-chain) | | | | | Endurance Smart Chain Mainnet | [Supported](./walletapi-quickstart-multi-chain) | | | | | Moonbeam | [Supported](./walletapi-quickstart-multi-chain) | | | | | Moonriver | [Supported](./walletapi-quickstart-multi-chain) | | | | | Ronin Mainnet | [Supported](./walletapi-quickstart-multi-chain) | | | | | Rangers | [Supported](./walletapi-quickstart-multi-chain) | | | | | Mode network | [Supported](./walletapi-quickstart-multi-chain) | | | | | Taiko network | [Supported](./walletapi-quickstart-multi-chain) | | | | | Bitlayer network | [Supported](./walletapi-quickstart-multi-chain) | | | | | Bob network | [Supported](./walletapi-quickstart-multi-chain) | | | | | Kava EVM | [Supported](./walletapi-quickstart-multi-chain) | | | | | EthereumPoW | [Supported](./walletapi-quickstart-multi-chain) | | | | | Celo Mainnet | [Supported](./walletapi-quickstart-multi-chain) | | | | | Ethereum Fair (DIS Chain) | [Supported](./walletapi-quickstart-multi-chain) | | | | | Gravity | [Supported](./walletapi-quickstart-multi-chain) | | | | | Wemix | [Supported](./walletapi-quickstart-multi-chain) | | | | | Lumi | [Supported](./walletapi-quickstart-multi-chain) | | | | | Sepolia | [Supported](./walletapi-quickstart-multi-chain) | | | | | ZetaChain Mainnet | | [Supported: Swap & Cross-chain](./dex-aggregation-root-quick-start) | | | | Sonic | | [Supported: Swap & Cross-chain](./dex-aggregation-root-quick-start) | | ## UTXO Networks | Chain | Wallet API | DEX API | Marketplace API | DeFi API | |----------------------------------|------------------------------------------------|---------|-----------------|----------| | Bitcoin Mainnet | [Supported](./walletapi-quickstart-multi-chain) | | [Supported: Ordinals Market](marketplace-ordinals-api) | | | Fractal Bitcoin Mainnet | [Not fully supported for transaction broadcasting](./walletapi-api-intro-query-api) | | [Supported: Ordinals Market](marketplace-ordinals-api) | | | Litecoin | [Supported](./walletapi-quickstart-multi-chain) | | | | | Doge | [Supported](./walletapi-quickstart-multi-chain) | | | | | Dash | [Supported](./walletapi-quickstart-multi-chain) | | | | | BCH | [Supported](./walletapi-quickstart-multi-chain) | | | | ## Other Networks | Chain | Wallet API | DEX API | |--------|-------------------------------------------------|---------------------------------------------------------------------| | Tron | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap & Cross-chain](./dex-aggregation-root-quick-start) | | Solana | [Supported](./walletapi-api-intro-query-api) | [Supported: Swap & Cross-chain](./dex-aggregation-root-quick-start) | | SUI | [Supported](./walletapi-quickstart-multi-chain) | [Supported: Swap & Cross-chain](./dex-aggregation-root-quick-start) | | Ton | Coming Soon | [Supported: Swap](./dex-aggregation-root-quick-start) | - [Introduction](https://web3.okx.com/onchainos/docs/waas/walletapi-introduction.md) # Introduction Wallet API offers a non-custodial wallet-centric underlying technology solution that you can flexibly use to build the on-chain services and applications. ## Service Scope The Wallet API mainly includes the following modules: **1. Address and Account Creation** **2. On-chain Asset and Coin Price Query, supporting:** - Native public chain tokens: e.g., ETH on Ethereum - Contract tokens: e.g., ERC-20, BEP-20 **3. Transaction-related functionalities, such as composing, signing, broadcasting, tracking, and history queries, supporting:** - Transactions on account model networks like EVM - Transactions on UTXO model networks like BTC **4. Other commonly used data, such as token information, gas prices, contract approval information, etc.** ## Application Scenarios Based on the above capabilities, you can build the following applications: **1. Web3 Multi-chain Wallet**, [supporting 60+ public chains](./wallet-supported-networks) **2. DApp Embedded Wallet** **3. Multi-chain Web3 Applications** **4. Exchange Wallet** Or other possible products and applications. If you want to use our services to build new product categories, feel free to join us on [Discord](https://discord.gg/JBYgQxuyeu) to talk with us. - [Quick Start](https://web3.okx.com/onchainos/docs/waas/walletapi-quickstart-intro.md) # Quick Start Based on your development goals, check out the sample cases to quickly get started with our services. - [Preparation](https://web3.okx.com/onchainos/docs/waas/walletapi-quickstart-preparation.md) # Preparation ## Create Project and API Key Before using the Wallet API, you need to first create a project on the Developer Management Platform and generate an API key. Here are the detailed steps and related resources: 1. Log in to the Developer Management Platform. 2. Create a new project. 3. Generate the API key in the project settings. We have prepared a detailed guide to help you complete these steps. You can read the [Developer Portal Guide](./introduction-to-developer-portal-interface) to get started more quickly. Additionally, you need to set up some basic configuration for API calls. ## REST Request Authentication Configuration When sending REST requests, you will need to authenticate them. We have provided a detailed [REST Authentication Guide](./rest-authentication) to help you understand and implement this process. ## Node.js Environment Setup Import the necessary Node.js libraries, set up your environment variables, and define helper functions and assemble parameters in the [Node.js Environment Setup](./nodejs-environment). - [Building an On-Chain Data Dashboard](https://web3.okx.com/onchainos/docs/waas/walletapi-quickstart-dashboard.md) # Building an On-Chain Data Dashboard Ensure that you have completed the [preparation work](./walletapi-quickstart-preparation). You can use this example to familiarize yourself with various methods of on-chain data queries. ## Method 1: Query by Address ### Query Assets Call the API to get [asset data](./walletapi-api-all-token-balances-by-address) integrated with 60+ chains, updated in seconds. ### Query Coin Prices and Information Call the API to get [coin price data](./walletapi-api-intro-tokendata) from multiple data sources including major exchanges, DEXs, and markets. ### Query Owned UTXOs and Inscriptions Call the API to get [owned UTXOs](./walletapi-api-utxos) and [inscription details](./walletapi-api-utxo-detail). ### Query Transaction History Call the API to get [full transaction history](./walletapi-api-transactions-by-address) for each address on the chain since creation. ### Query Authorizations Call the API to view [authorization details](./walletapi-api-get-approval-detail) on the address. ## Method 2: Batch Query by Account ### Step 1: Create an Account Create a wallet account ([AccountId](./walletapi-resources-definitions#accountid)) to aggregate the addresses you want to view and perform batch queries for token balances and transaction history. Implementation: Call the API to [create a wallet account](./walletapi-api-create-wallet-account). For example, subscribe to the same address across different chains as follows: ```javascript // Define your parameters const addresses = [ { "chainIndex":"1", "address":"0x561815e02bac6128bbbbc551005ddfd92a5c24db", }, { "chainIndex":"10", "address":"0x561815e02bac6128bbbbc551005ddfd92a5c24db", } ]; const getCreateWalletAccountBody = { addresses: addresses }; // Define the helper function const getCreateWalletAccountData = async () => { const apiRequestUrl = getRequestUrl( apiBaseUrl, '/api/v5/wallet/account/create-wallet-account' ); return fetch(apiRequestUrl, { method: 'post', headers: headersParams, body: JSON.stringify(getCreateWalletAccountBody), }) .then((res) => res.json()) .then((res) => { return res; }); }; const { data: createWalletAccountData } = await getCreateWalletAccountData();
### Step 2: Query Balances The wallet account can directly call the API to view the tokens held in the account. [Click here to check wallet account token balances](./walletapi-api-wallet-all-token-balances) for details. ```javascript // Define parameters const getAssetsParams = { accountId: '13886e05-1265-4b79-8ac3-b7ab46211001', }; // Define the helper function const getAssetsData = async () => { const apiRequestUrl = getRequestUrl( apiBaseUrl, '/api/v5/wallet/asset/wallet-all-token-balances', getAssetsParams ); return fetch(apiRequestUrl, { method: 'GET', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; const { data: getAssetsData } = await getAssetsData(); ``` When querying assets, you will receive a response like this: ```json { "code": "0", "data": [ { "chainIndex": "1", "tokenAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7", "symbol": "USDT", "balance": "0.688467", "tokenPrice": "0.99993", "tokenType": "1" }, { "chainIndex": "1", "tokenAddress": "0x514910771af9ca656af840dff83e8264ecf986ca", "symbol": "LINK", "balance": "0.000000366257612925", "tokenPrice": "14.108071299717093", "tokenType": "1" } ], "msg": "success" } ``` Step 3: Query Transaction History After sending a transaction, use the `GET /api/v5/wallet/post-transaction/transaction-detail-by-txhash` endpoint and provide the `txHash` to retrieve the transaction details. ```javascript // Define your parameters const params = { txhash: '0x9ab8ccccc9f778ea91ce4c0f15517672c4bd06d166e830da41ba552e744d29a5', chainIndex: '42161' }; // Define helper function const getTransactionDetailData = async () => { const apiRequestUrl = getRequestUrl( apiBaseUrl, '/api/v5/wallet/post-transaction/transaction-detail-by-txhash', params ); return fetch(apiRequestUrl, { method: 'get', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; const { data: transactionDetailData } = await getTransactionDetailData(); ``` When querying transaction history, you will receive a response like this: ```json { "code": "0", "msg": "success", "data": [ { "chainIndex": "42161", "height": "245222398", "txTime": "1724253417000", "txhash": "0x9ab8ccccc9f778ea91ce4c0f15517672c4bd06d166e830da41ba552e744d29a5", "gasLimit": "2000000", "gasUsed": "2000000", "gasPrice": "10000000", "nonce": "0", "symbol": "ETH", "amount": "0", "txStatus": "success", "methodId": "0xc9f95d32", "l1OriginHash": "0xa6a87ba2f18cc32bbae8f3b2253a29a9617ed1eb0940d80443f6e3bf9873dbad", "fromDetails": [ { "address": "0xd297fa914353c44b2e33ebe05f21846f1048cfeb", "vinIndex": "", "preVoutIndex": "", "txHash": "", "isContract": false, "amount": "" } ], "toDetails": [ { "address": "0x000000000000000000000000000000000000006e", "voutIndex": "", "isContract": false, "amount": "" } ], "internalTransactionDetails": [ { "from": "0x0000000000000000000000000000000000000000", "to": "0xd297fa914353c44b2e33ebe05f21846f1048cfeb", "isFromContract": false, "isToContract": false, "amount": "0.02", "state": "success" }, { "from": "0xd297fa914353c44b2e33ebe05f21846f1048cfeb", "to": "0x428ab2ba90eba0a4be7af34c9ac451ab061ac010", "isFromContract": false, "isToContract": false, "amount": "0.00998", "state": "success" }, { "from": "0xd297fa914353c44b2e33ebe05f21846f1048cfeb", "to": "0x428ab2ba90eba0a4be7af34c9ac451ab061ac010", "isFromContract": false, "isToContract": false, "amount": "0.009977946366846017", "state": "success" } ], "tokenTransferDetails": [] } ] } ``` By now, you have basically implemented the basic functionality needed to develop an on-chain data dashboard. Additionally, the wallet API provides a rich set of interfaces to fully meet the needs of exchange wallet developers. Please refer to the sections below for more information. - [Build Inscription Wallet](https://web3.okx.com/onchainos/docs/waas/walletapi-quickstart-inscription.md) # Build Inscription Wallet The Wallet API supports five popular inscription assets: BRC-20, Runes, ARC-20, SRC-20, and Ordinals_NFT. Please make sure you have completed the [preparation work](./walletapi-quickstart-preparation), then you can directly use this case to familiarize yourself with querying inscription data, constructing, and broadcasting inscription transactions. ## Step 1: Generate Wallet Mnemonic and Address You can use our provided [Signature SDK](./wallet-client-sdk) to create wallet mnemonics and addresses. ### npm install First, install the latest version of the Signature SDK. For the BTC network, use the following commands: ```bash npm install @okxweb3/crypto-lib npm install @okxweb3/coin-base npm install @okxweb3/coin-bitcoin ``` ### Build Locally 1. Download the project source code ```bash git clone https://github.com/okx/js-wallet-sdk.git ``` 2. Run the build script ```bash sh build.sh ``` For the BTC network, you can use the following code to create a BTC wallet object with the Signature SDK and derive the corresponding address. ```javascript import { BtcWallet,MessageTypes} from "@okxweb3/coin-bitcoin"; // btc wallet let wallet = new BtcWallet() // get mnemonic let mnemonic = await getMnemonic(128); let param = { mnemonic: mnemonic, hdPath: "m/44'/0'/0'/0/0" }; // get derived key let privateKey = await wallet.getDerivedPrivateKey(param); // get new address import { BtcWallet } from "@okxweb3/coin-bitcoin"; let wallet = new BtcWallet() // legacy address let params: NewAddressParams = { privateKey: "L22jGDH5pKE4WHb2m9r2MdiWTtGarDhTYRqMrntsjD5uCq5z9ahY" }; let address = await wallet.getNewAddress(params); // native segwit address let params2: NewAddressParams = { privateKey: "L22jGDH5pKE4WHb2m9r2MdiWTtGarDhTYRqMrntsjD5uCq5z9ahY", addressType: "segwit_native", }; let address2 = await wallet.getNewAddress(params2); // nested segwit address let params3: NewAddressParams = { privateKey: "L22jGDH5pKE4WHb2m9r2MdiWTtGarDhTYRqMrntsjD5uCq5z9ahY", addressType: "segwit_nested", }; let address3 = await wallet.getNewAddress(params3); // taproot segwit address let params4: NewAddressParams = { privateKey: "L22jGDH5pKE4WHb2m9r2MdiWTtGarDhTYRqMrntsjD5uCq5z9ahY", addressType: "segwit_taproot", }; let address4 = await wallet.getNewAddress(params4); // get the public key let publicKey = newAddress.publicKey; console.log("the corresponding public key:", publicKey); ``` ### Demo Program We have prepared an [open-source demo program](https://okx.github.io/js-wallet-sdk-demo/),to showcase the functionalities of the Signature SDK mentioned above. Get the demo program source code [here](https://github.com/okx/js-wallet-sdk-demo).
## Step 2: Create an Account In the previous step, you generated mnemonics and addresses. Now you can create an account [(AccountId)] (./walletapi-resources-definitions)to aggregate multiple addresses for batch querying of token balances and transaction history. Typically, a Web3 wallet has three concepts:

- Wallet: The owner of the mnemonic owns the wallet.
- Account: Based on the BIP-44 standard, multiple accounts can be derived from a set of mnemonics.
- Address: Each chain under each account corresponds to an address.
Call the API to [create a wallet account](./walletapi-api-create-wallet-account). For example, to create a BTC wallet account supporting different address types: ```javascript // Define your parameters const addresses = [ { "chainIndex":"0", "address":"bc1peqgjr3cwl09mmsh6kvjsvv3ffu4waha00x7xrqrt85wt3zgdwphs72ctnu", }, { "chainIndex":"0", "address":"18u8nvU5rx1drgwiT4M9sGTD9JX8r53KM9", } ]; const getCreateAccountBody = { addresses: addresses, signMessage: '1717062864123', // UNIX Timestamp in millisecond }; // Define auxiliary function const getCreateAccountData = async () => { const apiRequestUrl = getRequestUrl( apiBaseUrl, '/api/v5/wallet/account/create-wallet-account' ); return fetch(apiRequestUrl, { method: 'post', headers: headersParams, body: JSON.stringify(getCreateAccountBody), }) .then((res) => res.json()) .then((res) => { return res; }); }; const { data: createAccountData } = await getCreateAccountData(); ```
## Step 3: Construct and Send Inscription Transactions ### Get Signature Required Information First, call the `POST /api/v5/wallet/pre-transaction/sign-info` interface to query some data required for signing, such as BTC chain fees, inscription output sizes, etc. ```javascript // Define your parameters // BTC const postSignInfoBody = { chainIndex: '0', fromAddr: 'bc1psnr548clz3f4fz6jmpnw5eqzj2v2musk082wp8fvq5ac3p5ete6qg05u8u', toAddr: 'bc1psnr548clz3f4fz6jmpnw5eqzj2v2musk082wp8fvq5ac3p5ete6qg05u8u', txAmount: '0', extJson: { } }; // Define auxiliary function const signInfoData = async () => { const apiRequestUrl = getRequestUrl( apiBaseUrl, '/api/v5/wallet/pre-transaction/sign-info' ); return fetch(apiRequestUrl, { method: 'post', headers: headersParams, body: JSON.stringify(postSignInfoBody), }) .then((res) => res.json()) .then((res) => { return res; }); }; const { data: signInfoData } = await signInfoData(); ``` After querying the relevant information, you will receive a response like this: ```json { "code": "0", "msg": "success", "data": [ { "normalFeeRate": "5", "maxFeeRate": "5", "minFeeRate": "5", "inscriptionOutput": "546", "minOutput": "546", "normalCost": "1800", "maxCost": "3600", "minCost": "600" } ] } ``` ### Get Full UTXO Call the `GET /api/v5/wallet/utxo/utxo` interface to query all available UTXOs for the current address. ```json // Define your parameters // BTC const postSignInfoBody = { chainIndex: '0', fromAddr: 'bc1psnr548clz3f4fz6jmpnw5eqzj2v2musk082wp8fvq5ac3p5ete6qg05u8u', toAddr: 'bc1psnr548clz3f4fz6jmpnw5eqzj2v2musk082wp8fvq5ac3p5ete6qg05u8u', txAmount: '0', extJson: { } }; // Define auxiliary function const signInfoData = async () => { const apiRequestUrl = getRequestUrl( apiBaseUrl, '/api/v5/wallet/pre-transaction/sign-info' ); return fetch(apiRequestUrl, { method: 'get', headers: headersParams, body: JSON.stringify(postSignInfoBody), }) .then((res) => res.json()) .then((res) => { return res; }); }; const { data: signInfoData } = await signInfoData(); ``` ### Get Inscription Asset Details on UTXO Call the `POST /api/v5/wallet/utxo/utxo-detail` interface to query the inscription details on the UTXO. ```json // Define your parameters // BTC const postSignInfoBody = { chainIndex: '0', fromAddr: 'bc1psnr548clz3f4fz6jmpnw5eqzj2v2musk082wp8fvq5ac3p5ete6qg05u8u', toAddr: 'bc1psnr548clz3f4fz6jmpnw5eqzj2v2musk082wp8fvq5ac3p5ete6qg05u8u', txAmount: '0', extJson: { } }; // Define auxiliary function const signInfoData = async () => { const apiRequestUrl = getRequestUrl( apiBaseUrl, '/api/v5/wallet/pre-transaction/sign-info' ); return fetch(apiRequestUrl, { method: 'post', headers: headersParams, body: JSON.stringify(postSignInfoBody), }) .then((res) => res.json()) .then((res) => { return res; }); }; const { data: signInfoData } = await signInfoData(); ``` ### Verify Address and Build Transaction Use the signing SDK to first verify address validity and then build the transaction. ```javascript // Verify address let valid = await wallet.validAddress({ address: newAddress.address }); console.log("verify address isValid:", valid.isValid); // Sign a transaction let signParams = { privateKey: derivePrivateKey, data: { to: newAddress.address, value: new BigNumber(0), nonce: 5, gasPrice: new BigNumber(100 * 1000000000), gasLimit: new BigNumber(21000), chainId: 42 } }; let signedTx = await wallet.signTransaction(signParams); console.log("signed tx:", signedTx); ``` ### Broadcast Transaction Call the [interface](./walletapi-api-send-transaction) to broadcast the transaction to the blockchain. ```javascript // Define your parameters const postSendTransactionBody = { signedTx: "02000000000101a92808fb32063058e3c752ad2c4a0a6f8957e858dd01483ccff504d4f5ca791d0500000000fdffffff02c405000000000000225120728b5d2f0cf833264adac833e997931155b4aec3020bc87c32fa91509bb2abe61f71080000000000225120f0513064fe1e5b5c31bedff43b943f2f1211d14ab2891687241b138d214888e30140393a287212d5c7341a5d44ba2409dda5db95a854e500475ec8bf2ea0f7f63d35c849102c0f906f48d1833f3b5b7a7ca726e14fc2d715b4cbbecb8488e028baab00000000" accountId:"c79e7775-9e78-4a2d-b27f-9021f3bf5fca", address: "bc1p7pgnqe87red4cvd7ml6rh9pl9ufpr522k2y3dpeyrvfc6g2g3r3s3ae9dr", }; // Define auxiliary function const sendTransactionData = async () => { const apiRequestUrl = getRequestUrl( apiBaseUrl, 'api/v5/wallet/pre-transaction/broadcast-transaction' ); return fetch(apiRequestUrl, { method: 'post', headers: headersParams, body: JSON.stringify(postSendTransactionBody), }) .then((res) => res.json()) .then((res) => { return res; }); }; const { data: sendTransactionData } = await sendTransactionData(); ``` After broadcasting, you will receive the following response: ```json { "code": 0, "msg": "success", "data": [{ "orderId": "469356614923743232" }] } ``` Click to see the [orderId](./walletapi-resources-definitions#orderid) definition
## Step 5: Query Inscription Transaction Details After sending the transaction, use the ` GET /api/v5/wallet/post-transaction/inscription-transaction-detail-by-txhash ` interface to obtain the inscription transaction details via txhash. ```javascript // Define your parameters const params = { accountId: '13886e05-1265-4b79-8ac3-b7ab46211001', orderId: '469356614923743232', chainIndex: '1' }; // Define auxiliary function const getTransactionDetailData = async () => { const apiRequestUrl = getRequestUrl( apiBaseUrl, '/api/v5/wallet/post-transaction/transaction-detail-by-ordid', params ); return fetch(apiRequestUrl, { method: 'get', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; const { data: transactionDetailData } = await getTransactionDetailData(); ``` After successfully querying the details, you will receive a response like the following: ```json { "code": 0, "msg": "success", "data": [ { "chainIndex": "1", "orderId": "469356614923743232", "txhash": "0xcbf411766d65f3cf92839ababa73c4afec69a83442e8b67a68b5104b50a04ejb", "blockHash" : "0x3ee63382b883fc40e35da6023fb341dd01cd2ec011f992bb54cf312f517740c9", "blockHeight" : "19235519", "blockTime" : "1708026551000", "feeUsdValue" : "138.846919", "fees" : "49102595635945621", "gasLimit" : "2000000", "gasPrice" : "87504603347", "gasUsed" : "561143", "txType": "0", "txTime": "0", "txStatus": "0", "txDetail": [ { "iType" : "0", "txAmount": "0", "tokenAddress":"" "contractCall" : true, "fromAddr" : "0x3ee63382b883fc40e35da6023fb341dd01cd2ec011f992bb54cf312f517740c9", "toAddr" : "0x3ee63382b883fc40e35da6023fb341dd01cd2ec011f992bb54cf312f517740c9", "logIndex" : "-1", "status" : "SUCCESS" } ] } ] } ``` Additionally, you can subscribe to Webhooks to get real-time and accurate information on the status of your transaction after it has been sent,[See details](./walletapi-api-webhook-intro). At this point, you have basically implemented the essential functions required for developing an inscription wallet. Moreover, the wallet API provides a rich set of interfaces to meet the needs of Web3 wallet developers. For more details, please refer to the following content. - [Building a Web3 Wallet](https://web3.okx.com/onchainos/docs/waas/walletapi-quickstart-multi-chain.md) # Building a Web3 Wallet Please ensure that you have completed the [preparation work](./walletapi-quickstart-preparation). You can use this case to familiarize yourself with wallet management, querying data from various blockchains, and transaction construction and broadcasting. ## Step 1: Generate Wallet Mnemonic and Address You can use the [Signature SDK](./wallet-client-sdk) we provide to create a wallet mnemonic and address. ### npm install First, you need to install the latest version of the Signature SDK. For EVM networks, for example: ```bash npm install @okxweb3/crypto-lib npm install @okxweb3/coin-base npm install @okxweb3/coin-ethereum ``` ### Local Build 1. Download the project source code ```bash git clone https://github.com/okx/js-wallet-sdk.git ``` 2. Run the build script ```bash sh build.sh ``` Taking the ETH network as an example, you can use the Signing SDK to create an ETH wallet object and derive the corresponding address. ```javascript import { bip39, BigNumber } from "@okxweb3/crypto-lib"; import { EthWallet,MessageTypes } from "@okxweb3/coin-ethereum"; // eth wallet let wallet = new EthWallet(); // get mnemonic let mnemonic = await bip39.generateMnemonic(); console.log("generate mnemonic:", mnemonic); // get derived key const hdPath = await wallet.getDerivedPath({ index: 0 }); let derivePrivateKey = await wallet.getDerivedPrivateKey({ mnemonic: mnemonic, hdPath: hdPath }); console.log("generate derived private key:", derivePrivateKey, ",derived path: ", hdPath); // get new address let newAddress = await wallet.getNewAddress({ privateKey: derivePrivateKey }); console.log("generate new address:", newAddress.address); // get the public key let publicKey = newAddress.publicKey; console.log("the corresponding public key:", publicKey); ``` ### Demo Program We have prepared an [open-source demo program](https://okx.github.io/js-wallet-sdk-demo/) to demonstrate the features of the Signing SDK mentioned above. Get the demo program source code [here](https://github.com/okx/js-wallet-sdk-demo).
## Step 2: Create an Account You have already generated the mnemonic and address in the previous step. Now you can create an account ([AccountId](./walletapi-resources-definitions#accountid))to aggregate multiple addresses for batch querying of token balances and transaction history. Typically, a Web3 wallet involves three concepts:

- Wallet, Whoever owns the mnemonic owns the wallet.
- Account, Based on the BIP-44 standard, multiple accounts can be derived from a single set of mnemonics.
- Address, Each account has one address per chain.
Call the interface to [create a wallet account](./walletapi-api-create-wallet-account). For example, subscribing to the same address on different chains is implemented as follows: ```javascript // Define your parameters const addresses = [ { "chainIndex":"1", "address":"0x561815e02bac6128bbbbc551005ddfd92a5c24db", "publicKey":"02012db63bf0380294a6ecf87615fe869384b0510cb910a094254b6844af023ee2", "signature":"62acda5e471d9bf0099add50f4845256868d980821c161095651a918d3ef8a6b2286f512028172eabbe46ec2c9c2c20e5c40ff1fb23e1cdfdbed033ad924ce521b" }, { "chainIndex":"10", "address":"0x561815e02bac6128bbbbc551005ddfd92a5c24db", "publicKey":"02012db63bf0380294a6ecf87615fe869384b0510cb910a094254b6844af023ee2", "signature":"62acda5e471d9bf0099add50f4845256868d980821c161095651a918d3ef8a6b2286f512028172eabbe46ec2c9c2c20e5c40ff1fb23e1cdfdbed033ad924ce521b" } ]; const getCreateAccountBody = { addresses: addresses, signMessage: '1717062864123', // UNIX Timestamp in millisecond }; // Define auxiliary function const getCreateAccountData = async () => { const apiRequestUrl = getRequestUrl( apiBaseUrl, '/api/v5/wallet/account/create-account' ); return fetch(apiRequestUrl, { method: 'post', headers: headersParams, body: JSON.stringify(getCreateAccountBody), }) .then((res) => res.json()) .then((res) => { return res; }); }; const { data: createAccountData } = await getCreateAccountData(); ``` Beside, if you want to create a watch-only account, call the `POST /api/v5/wallet/account/create-watch-only-account`. Click [here](./walletapi-api-create-watch-only-account) for details.
## Step 3: Construct and Send Transactions ### Get Signing Information First, call the `POST /api/v5/wallet/pre-transaction/sign-info` interface to query the data required for the transaction, such as gas price, gas limit, nonce. Take ETH for an example: ```javascript // Define your parameters // EVM const postSignInfoBody = { chainIndex: '1', fromAddr: '0xdf54b6c6195ea4d948d03bfd818d365cf175cfc2', toAddr: '0x1e80c39051f078ee34763282cbb36ffd88b40c65', txAmount: '123000000000000', extJson: { inputData: '041bbc6fa102394773c6d8f6d634320773af4' } }; // TRON const postSignInfoBody = { "chainIndex": "195", "fromAddr": "TDnSmJ15nmwg5jmYmXWFVgBX53XxfbNHsC", "toAddr": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "txAmount": "0", "extJson": { "permissionType": 1, "feeLimit": 300000, "inputData": "0x095ea7b3000000000000000000000000d73c5e36d47eed32f0327f9d3f04b49384e90fab0000000000000000000000000000000000000000000000000000000000000000" } }; // Define auxiliary function const signInfoData = async () => { const apiRequestUrl = getRequestUrl( apiBaseUrl, '/api/v5/wallet/pre-transaction/sign-info' ); return fetch(apiRequestUrl, { method: 'post', headers: headersParams, body: JSON.stringify(postSignInfoBody), }) .then((res) => res.json()) .then((res) => { return res; }); }; const { data: signInfoData } = await signInfoData(); ``` ### Verify Address and Build Transaction Use the Signing SDK to verify the address and build the transaction. ```javascript // Verify address let valid = await wallet.validAddress({ address: newAddress.address }); console.log("verify address isValid:", valid.isValid); // Sign the transaction let signParams = { privateKey: derivePrivateKey, data: { to: newAddress.address, value: new BigNumber(0), nonce: 5, gasPrice: new BigNumber(100 * 1000000000), gasLimit: new BigNumber(21000), chainId: 42 } }; let signedTx = await wallet.signTransaction(signParams); console.log("signed tx:", signedTx); ``` ### Broadcast Transaction Call the [interface](./walletapi-api-send-transaction) to broadcast the transaction to the chain. ```javascript // Define your parameters const postSendTransactionBody = { "signedTx": "0x02f8720182029f8411e1a3008504bbe2e94682520894d73c5e36d47eed32f0327f9d3f04b49384e90fab85e8d4a5100080c080a0ba380a9be31efabc4c8cfccbb555f8af3c21073d6eca01f180ebebb8942c6f30a0779e6e16a504c413cb9902ceb33ab7e89a533bc13b74477dfa6b6c76dc41fac2 "accountId": "5f45a951-4a8b-4cd9-b20a-3b337b71efcc", "chainIndex": "1", "address": "0x238193be9e80e68eace3588b45d8cf4a7eae0fa3", }; // Define auxiliary function const sendTransactionData = async () => { const apiRequestUrl = getRequestUrl( apiBaseUrl, 'api/v5/wallet/pre-transaction/broadcast-transaction' ); return fetch(apiRequestUrl, { method: 'post', headers: headersParams, body: JSON.stringify(postSendTransactionBody), }) .then((res) => res.json()) .then((res) => { return res; }); }; const { data: sendTransactionData } = await sendTransactionData(); ``` After broadcasting, you will receive a response like this: ```json { "code": 0, "msg": "success", "data": [{ "orderId": "469356614923743232" }] } ``` Click to view the definition of [orderId](./walletapi-resources-definitions#orderid).
## Step 4: Query Transaction Details After sending the transaction, use the [interface](./walletapi-api-order-id-transaction-list) get the transaction details.You can also query by transaction hash, see [here](./walletapi-api-transaction-detail-by-txhash). ```javascript // Define your parameters const params = { accountId: '13886e05-1265-4b79-8ac3-b7ab46211001', orderId: '469356614923743232', chainIndex: '1' }; // Define auxiliary function const getTransactionDetailData = async () => { const apiRequestUrl = getRequestUrl( apiBaseUrl, '/api/v5/wallet/post-transaction/orders', params ); return fetch(apiRequestUrl, { method: 'get', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; const { data: transactionDetailData } = await getTransactionDetailData(); ``` When the details are successfully queried, you will receive a response like this: ```json { "code": 0, "msg": "success", "data": [ { "chainIndex": "1", "orderId": "469356614923743232", "txhash": "0xcbf411766d65f3cf92839ababa73c4afec69a83442e8b67a68b5104b50a04ejb", "blockHash" : "0x3ee63382b883fc40e35da6023fb341dd01cd2ec011f992bb54cf312f517740c9", "blockHeight" : "19235519", "blockTime" : "1708026551000", "feeUsdValue" : "138.846919", "fees" : "49102595635945621", "gasLimit" : "2000000", "gasPrice" : "87504603347", "gasUsed" : "561143", "txType": "0", "txTime": "0", "txStatus": "0", "txDetail": [ { "iType" : "0", "txAmount": "0", "tokenAddress":"" "contractCall" : true, "fromAddr" : "0x3ee63382b883fc40e35da6023fb341dd01cd2ec011f992bb54cf312f517740c9", "toAddr" : "0x3ee63382b883fc40e35da6023fb341dd01cd2ec011f992bb54cf312f517740c9", "logIndex" : "-1", "status" : "SUCCESS" } ] } ] } ``` Additionally, you can subscribe to Webhooks to get real-time and accurate information about the status of transactions. [Click here for details](./walletapi-api-webhook-intro).
At this point, you have basically implemented the basic functions needed to develop a Web3 wallet. Additionally, Wallet API provides a rich range of interfaces to fully meet the needs of Web3 wallet developers. For details, please refer to the following content. - [On-Chain Information Query](https://web3.okx.com/onchainos/docs/waas/walletapi-api-intro-query-api.md) # On-Chain Information Query The on-chain information query provides core data API interfaces related to Web3 development, including chain data, asset data, coin prices and project information, transaction history, and authorization data. - [Supported Blockchains](https://web3.okx.com/onchainos/docs/waas/walletapi-api-get-supported-blockchain.md) {/* api-page */} # Supported Blockchains Returns information about all blockchain networks currently supported by Wallet API, except for the API on this [part](./walletapi-api-intro-tokendata)
Such as logos and unique identifiers for main chain coins on networks like Bitcoin and Ethereum. ### Request Path GET `https://web3.okx.com/api/v5/wallet/chain/supported-chains` ### Request Parameters None ### Response Parameters | Parameter | Type | Description | |-----------|--------|-------------------| | name | String | Chain name | | logoUrl | String | Chain logo URL | | shortName | String | Chain short name | | chainIndex| String | Chain unique identifier |
### Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v5/wallet/chain/supported-chains' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response Example ```json { "code": "0", "data": [ { "name": "Ethereum", "logoUrl": "http://www.eth.org/eth.png", "shortName": "ETH", "chainIndex": "1" } ], "msg": "" } ```
- [Coin Prices and Project Information](https://web3.okx.com/onchainos/docs/waas/walletapi-api-intro-tokendata.md) # Coin Prices and Project Information The coin prices and project information section supports querying information about cryptocurrencies, including their prices, circulation, supply, and project websites. The scope of chain support is not affected by this API [Supported Blockchains](./walletapi-api-get-supported-blockchain) - [Token Index Price](https://web3.okx.com/onchainos/docs/waas/walletapi-api-get-current-pricelist.md) {/* api-page */} # Token Index Price The index Price refers to a currency price calculated from the prices of multiple third-party data sources. Batch query for in de token prices. - Supports index prices for native token and other tokens. - Supports index prices for inscription tokens on the Bitcoin chain such as BRC-20, Runes, ARC-20, and SRC-20. - Supports index prices for BRC-20 inscription tokens on the Fractal Bitcoin chain. Maximum 100 token prices can be queried per request.Request parameters should be passed in the form of an array. ### Request Path POST `https://web3.okx.com/api/v5/wallet/token/current-price` ### Request Parameters | Parameter | Type | Required | Description | |--------------|--------|----------|-------------| | chainIndex | String | Yes | Unique identifier of the blockchain | | tokenAddress | String | Yes | Token address.
`1`: Pass an empty string `""` to query the native token of the corresponding chain.
`2`: Pass the specific token contract address to query the corresponding token.
`3`: Different inscription tokens are passed in the following formats:
`FBRC-20`: Use `fbtc_fbrc20_name`, such as `fbtc_fbrc20_babymusk`
`BRC-20`: Use `btc-brc20-tick(name)`, such as `btc-brc20-ordi`
`Runes`: Use `btc-runesMain-tickId`, such as `btc-runesMain-840000:2`
`SRC-20`: Use `btc-src20-name`, such as `btc-src20-utxo`
|
### Response Parameters | Parameter | Type | Description | |--------------|--------|-------------------------------| | price | String | Token price | | time | String | Timestamp of the price, Unix timestamp in milliseconds | | chainIndex | String | Unique identifier of the blockchain | | tokenaddress | String | Token address.|
### Request Example ``` shell curl --location --request POST 'https://web3.okx.com/api/v5/wallet/token/current-price' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '[ { "chainIndex": "1", "tokenAddress":"0xdac17f958d2ee523a2206206994597c13d831ec7" }, { "chainIndex":"1", "tokenAddress": "0xdac17f955d2ee523a2206206994597c13d831ein" }, { "chainIndex": "0", "tokenAddress": "btc-arc20-00009b954c9f1358de9c089f95ec420132e4106a89c8fbb3cfda198ae1e5f9d5i0" }, { "chainIndex": "0", "tokenAddress": "btc-runesMain-840000:2" } ]' ``` ### Response Example ``` json { "code": 0, "msg": "success", "data": [ { "chainIndex": "1", "tokenAddress": "0xc18360217d8f7ab5e7c516566761ea12ce7f9d72" "time": "1716892020000", "price": "26.458143090226812", }, { "chainIndex": "0", "tokenAddress": "btc-brc20-ordi", "time": "1724147119541", "price": "32.430139864000000000" }, { "chainIndex": "0", "tokenAddress": "btc-arc20-00009b954c9f1358de9c089f95ec420132e4106a89c8fbb3cfda198ae1e5f9d5i0", "time": "1724153703045", "price": "0.003558564230000000" }, { "chainIndex": "0", "tokenAddress": "btc-runesMain-840000:2", "time": "1724145196000", "price": "0.000455104500000000" } ] } ```
- [Real-time Token Price](https://web3.okx.com/onchainos/docs/waas/walletapi-api-get-realtime-pricelist.md) {/* api-page */} # Real-time Token Price Batch query for real-time token prices. Supports real-time prices for non-native tokens. Maximum 100 token prices can be queried per request.Request parameters should be passed in the form of an array. ### Request Path POST `https://web3.okx.com/api/v5/wallet/token/real-time-price` ### Request Parameters | Parameter | Type | Required | Description | |--------------|--------|----------|-------------| | chainIndex | String | Yes | Unique identifier of the blockchain | | tokenAddress | String | Yes | Token address. | ### Response Parameters | Parameter | Type | Description | |--------------|--------|-------------------------------| | price | String | Token price | | time | String | Timestamp of the price, Unix timestamp in milliseconds | | chainIndex | String | Unique identifier of the blockchain | | tokenaddress | String | Token address.| ### Request Example ``` shell curl --location --request POST 'https://web3.okx.com/api/v5/wallet/token/real-time-price' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '[ { "chainIndex": "1", "tokenAddress":"0xdac17f958d2ee523a2206206994597c13d831ec7" } ]' ``` ### Response Example ``` json { "code": 0, "msg": "success", "data": [ { "chainIndex": "1", "tokenAddress": "0xc18360217d8f7ab5e7c516566761ea12ce7f9d72" "time": "1716892020000", "price": "26.458143090226812", } ] } ``` - [Historical Token Price](https://web3.okx.com/onchainos/docs/waas/walletapi-api-get-historical-price.md) {/* api-page */} # Historical Token Price Query historical prices for a specific token. - Supports historical prices for native token and other tokens. - Supports historical prices for inscription tokens on the Bitcoin chain such as BRC-20, Runes, ARC-20, and SRC-20. - Supports historical prices for BRC-20 inscription tokens on the Fractal Bitcoin chain. ### Request Path GET `https://web3.okx.com/api/v5/wallet/token/historical-price` ### Request Parameters | Parameter | Type | Required | Description | |--------------|--------|----------|----------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier of the blockchain | | tokenAddress | String | No | Token address.
`1`: Pass an empty string `""` to query the native token of the corresponding chain.
`2`: Pass the specific token contract address to query the corresponding token.
`3`: Different inscription tokens are passed in the following formats:
`FBRC-20`: Use `fbtc_fbrc20_name`, such as `fbtc_fbrc20_babymusk`
`BRC-20`: Use `btc-brc20-tick(name)`, such as `btc-brc20-ordi`
`Runes`: Use `btc-runesMain-tickId`, such as `btc-runesMain-840000:2`
`SRC-20`: Use `btc-src20-name`, such as `btc-src20-utxo`
| | limit | String | No | Number of entries per query, default is 50, maximum is 200 | | cursor | String | No | Cursor position, defaults to the first entry | | begin | String | No | Start time to query historical prices after. Unix timestamp in milliseconds | | end | String | No | End time to query historical prices before. If neither begin nor end is provided, query historical prices before the current time. Unix timestamp in milliseconds | | period | String | No | Time interval unit:
`1m`: 1 minute
`5m`: 5 minutes
`30m`: 30 minutes
`1h`: 1 hour
`1d`: 1 day (default) |
### Response Parameters | Parameter | Type | Description | |-----------|--------|----------------------| | prices | Array | List of historical prices | | >time | String | Timestamp of the minute (whole minute) | | >price | String | Cryptocurrency price (precision 18 decimal places) |
### Request Example ``` shell For EVM: curl --location --request GET 'https://web3.okx.com/api/v5/wallet/token/historical-price?chainIndex=1&limit=5&begin=1700040600000&period=5m' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' For BTC: curl --location --request GET 'https://web3.okx.com/api/v5/wallet/token/historical-price?chainIndex=0&limit=5&period=1m&tokenAddress=btc-brc20-ordi' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response Example ```json { "code": "0", "msg": "success", "data": [ { "cursor": "31", "prices": [ { "time": "1700040600000", "price": "1994.430000000000000000" }, { "time": "1700040300000", "price": "1994.190000000000000000" }, { "time": "1700040000000", "price": "1992.090000000000000000" }, { "time": "1700039700000", "price": "1992.190000000000000000" }, { "time": "1700039400000", "price": "1990.190000000000000000" } ] } ] } ```
- [Project Information](https://web3.okx.com/onchainos/docs/waas/walletapi-api-token-detail.md) {/* api-page */} # Project Information Query additional information about a single token, such as token contract address, official token website URL, and social media links. - Supports project information for native token and other tokens. - Supports project information for inscription tokens on the Bitcoin chain such as BRC-20, Runes, ARC-20, and SRC-20. - Supports project information for BRC-20 inscription tokens on the Fractal Bitcoin chain. ### Request Path GET `https://web3.okx.com/api/v5/wallet/token/token-detail` ### Request Parameters | Parameter | Type | Required | Description | |--------------|--------|----------|-------------| | chainIndex | String | Yes | Unique identifier of the blockchain | | tokenAddress | String | No | Token address.
`1`: Pass an empty string `""` to query the native token of the corresponding chain.
`2`: Pass the specific token contract address to query the corresponding token.
`3`: Different inscription tokens are passed in the following formats:
`FBRC-20`: Use `fbtc_fbrc20_name`, such as `fbtc_fbrc20_babymusk`
`BRC-20`: Use `btc-brc20-tick(name)`, such as `btc-brc20-ordi`
`Runes`: Use `btc-runesMain-tickId`, such as `btc-runesMain-840000:2`
`SRC-20`: Use `btc-src20-name`, such as `btc-src20-utxo`
|
### Response Parameters | Parameter | Type | Description | |-----------------|--------|--------------------------------------------------------| | logoUrl | String | URL of the token's logo | | officialWebsite | String | URL of the official website of the token | | socialUrls | Object | Social media links | | > twitter | Array | Twitter link(s), if available | | > facebook | Array | Facebook link(s), if available | | > reddit | Array | Reddit link(s), if available | | > messageboard | Array | Message board link(s), if available | | > chat | Array | Chat link(s), if available | | > github | Array | GitHub link(s), if available | | > whitepaper | Array | Whitepaper link(s), if available | | > announcement | Array | Announcement link(s), if available | | decimals | String | Token decimals | | tokenAddress | String | Token address.If the return is an empty string `""`, it means the query is for the native token of the corresponding blockchain. | | chainIndex | String | Unique identifier of the blockchain | | chainName | String | Name of the blockchain | | symbol | String | Token symbol | | name | String | Token name | | maxSupply | String | Maximum supply (across multiple chains, some data may be empty). Precision of 15 digits | | totalSupply | String | Total supply (across multiple chains, some data may be empty). Precision of 15 digits | | volume24h | String | 24-hour trading volume in USD. Precision of 15 digits. Includes all liquidity pools accessible via OKX DEX. | | marketCap | String | Project market capitalization in USD. Precision of 15 digits |
### Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v5/wallet/token/token-detail?chainIndex=56""&tokenAddress=0x6f620ec89b8479e97a6985792d0c64f237566746' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ ``` ### Response Example ``` json { "code": "0", "msg": "success", "data": [ { "logoUrl": "https://static.oklink.com/cdn/web3/currency/token/bnb-wpc-0x6f620ec89b8479e97a6985792d0c64f237566746.png/type=png_350_0", "officialWebsite": "https://www.wepiggy.com/", "socialUrls": { "messageboard": [ "https://wepiggy-com.medium.com/" ], "github": [ "https://github.com/WePiggy" ], "twitter": [ "https://twitter.com/wepiggydotcom" ], "chat": [ "https://t.me/wepiggy;https://discord.com/invite/pew9k58" ], "reddit": [ "https://reddit.com/r/WePiggy/" ] }, "decimals": "18", "tokenAddress": "0x6f620ec89b8479e97a6985792d0c64f237566746", "chainIndex": "56", "chainName": "BNB Chain", "symbol": "wpc", "maxSupply": "200000000.000000000000000", "totalSupply": "", "volume24h": "283632981.281666040000000", "marketCap": "34510982165.370000000000000" } ] } ```
- [Get Asset by Address](https://web3.okx.com/onchainos/docs/waas/walletapi-api-intro-asset-address.md) # Get Asset by Address Provides various asset queries by address dimension. - [Total Value](https://web3.okx.com/onchainos/docs/waas/walletapi-api-total-token-value-address.md) {/* api-page */} # Total Value Get the total balance of all tokens and DeFi assets under the specified address, with support for filtering out risk airdrop tokens. ### Request URL GET `https://web3.okx.com/api/v5/wallet/asset/total-value-by-address` ### Request Parameters | Parameter | Type | Required | Description | | ------------------| ------- | -------- | ------------------------------------------------------------------ | | address | String | Yes | Get the total valuation for the address | | chains | String | Yes | Query the total balance of the multiple chains, which can be separated by ",". Supports up to 50 chains | | assetType | String | No | Type of asset to query, defaults to total balance of all assets. 0: Query total balance of all assets, including tokens and DeFi assets; 1: Query only token balance; 2: Query only DeFi balance | | excludeRiskToken | Boolean | No | Option to filter out potentially risky airdrop tokens. Defaults to filtering. true: filter, false: do not filter | ### Response Parameters | Parameter | Type | Description | | --- | --- | --- | | totalValue | String | Returns the total asset balance based on the query asset type, expressed in USD | ### Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v5/wallet/asset/total-value-by-address?address=0x0b32aa5c1e71715206fe29b7badb21ad95f272c0&chains=1&assetType=0' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response Example ``` json { "code": "0", "msg": "success", "data": [ { "totalValue": "172.895057177065864522056725546579939398" } ] } ``` - [Total Token Balances](https://web3.okx.com/onchainos/docs/waas/walletapi-api-all-token-balances-by-address.md) {/* api-page */} # Total Token Balances Retrieve the list of token balances for an address across multiple chains or specified chains. The balance query supports: - Chain native tokens - ERC20 tokens on EVM chains - BRC-20, ARC-20, Runes, and SRC-20 tokens in the Bitcoin ecosystem - Fractal Bitcoin chain's BRC-20 tokens Additionally, this interface supports filtering out risky airdrop tokens. ### Request Path GET `https://web3.okx.com/api/v5/wallet/asset/all-token-balances-by-address` ### Request Parameters | Parameter | Type | Required | Description | |----------------|--------|----------|-----------------------------------------| | address | String | Yes | Address | | chains | Array | Yes | When filtering the chains for querying asset details, multiple chains should be separated by commas (`,`). A maximum of 50 chains is supported. | | filter | String | No | `0`: Filter out risk airdrop tokens
`1`: Do not filter
Default is to filter. |
### Response Parameters | Parameter | Type | Description | |---------------|--------|------------------------------------------| | tokenAssets | Array | List of token balances | | >chainIndex | String | Unique identifier for the chain | | >tokenAddress | String | Contract address | | >address | String | Address | | >symbol | String | Token symbol | | >balance | String | Token balance | | >rawBalance | String | Raw balance of token address. More chains will be supported soon. For unsupported chains, this field is empty. | | >tokenPrice | String | Token unit value, priced in USD | | >tokenType | String | Token type:
`1`: token
`2`: inscription | | >transferAmount | String | The balance of BRC-20, FBRC-20, and other inscription assets that can be directly transferred or traded, commonly referred to as the transferable balance. | | >availableAmount | String | The amount of BRC-20, FBRC-20, and other inscription assets that need to complete the inscription process before they can be traded or transferred, usually referred to as the available balance or pending inscription balance. | | >isRiskToken | Boolean | `true`: flagged as a risk airdrop token
`false`: not flagged |
### Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v5/wallet/asset/all-token-balances-by-address?address=0xEd0C6079229E2d407672a117c22b62064f4a4312&chains=1&filter=1' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response Example ``` json { "code": "0", "msg": "success", "data": [ { "tokenAssets": [ { "chainIndex": "1", "tokenAddress": "0x386ae941d4262b0ee96354499df2ab8442734ec0", "symbol": "PT-sUSDE-27FEB2025", "balance": "47042180.520700015", "tokenPrice": "0.968391562089677097", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0", "symbol": "wstETH", "balance": "7565.892480395067", "tokenPrice": "4321.611627695311", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", "symbol": "WBTC", "balance": "329.10055205", "tokenPrice": "98847.8", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0x23878914efe38d27c4d67ab83ed1b93a74d4086a", "symbol": "aEthUSDT", "balance": "30057379.938443", "tokenPrice": "0.99978", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0x657e8c867d8b37dcc18fa4caead9c45eb088c642", "symbol": "eBTC", "balance": "271.94970471", "tokenPrice": "99094.345321371", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8", "symbol": "aEthWETH", "balance": "6080.001975381972", "tokenPrice": "3634.32", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0xe00bd3df25fb187d6abbb620b3dfd19839947b81", "symbol": "PT-sUSDE-27MAR2025", "balance": "19016580.895408865", "tokenPrice": "0.952031186961110727", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0xa17581a9e3356d9a858b789d68b4d866e593ae94", "symbol": "cWETHv3", "balance": "3000.000734740809", "tokenPrice": "3663.74", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0x9d39a5de30e57443bff2a8307a4256c8797a3497", "symbol": "sUSDe", "balance": "4863500.628333919", "tokenPrice": "1.144688569528375454", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0xec5a52c685cc3ad79a6a347abace330d69e0b1ed", "symbol": "PT-LBTC-27MAR2025", "balance": "46.02912324", "tokenPrice": "97165.169717785655331396", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0x8236a87084f8b84306f72007f36f2618a5634494", "symbol": "LBTC", "balance": "38.09998", "tokenPrice": "99187.19184268864", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0xbeef047a543e45807105e51a8bbefcc5950fcfba", "symbol": "steakUSDT", "balance": "482651.8612595832", "tokenPrice": "1.063", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0x4c9edd5852cd905f086c759e8383e09bff1e68b3", "symbol": "USDe", "balance": "69564", "tokenPrice": "0.99977", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0x8be3460a480c80728a8c4d7a5d5303c85ba7b3b9", "symbol": "sENA", "balance": "42294.989425", "tokenPrice": "1.19", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "", "symbol": "ETH", "balance": "8.135546539084933", "tokenPrice": "3638.63", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0xbf5495efe5db9ce00f80364c8b423567e58d2110", "symbol": "ezETH", "balance": "5.270854886240325", "tokenPrice": "3763.152404188635320082", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0x6b175474e89094c44da98b954eedeac495271d0f", "symbol": "DAI", "balance": "1196.2693184870445", "tokenPrice": "1.0002", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0xc00e94cb662c3520282e6f5717214004a7f26888", "symbol": "COMP", "balance": "0.007643", "tokenPrice": "84.43345772756197", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0x9abfc0f085c82ec1be31d30843965fcc63053ffe", "symbol": "Q*", "balance": "900", "tokenPrice": "0.000419255747329174", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0xa1290d69c65a6fe4df752f95823fae25cb99e5a7", "symbol": "rsETH", "balance": "0.00007090104120006", "tokenPrice": "3765.640772858747921444", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0x56015bbe3c01fe05bc30a8a9a9fd9a88917e7db3", "symbol": "CAT", "balance": "0.42", "tokenPrice": "0.06242994543936436", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0xec53bf9167f50cdeb3ae105f56099aaab9061f83", "symbol": "EIGEN", "balance": "0.002496149915967488", "tokenPrice": "4.018538365202288", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0x58d97b57bb95320f9a05dc918aef65434969c2b2", "symbol": "MORPHO", "balance": "0.001409373661132556", "tokenPrice": "3.3568669630371337", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0xaf5191b0de278c7286d6c7cc6ab6bb8a73ba2cd6", "symbol": "STG", "balance": "0.000009547670354338", "tokenPrice": "0.49707759500034454", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0xba3335588d9403515223f109edc4eb7269a9ab5d", "symbol": "GEAR", "balance": "0.000009005734110189", "tokenPrice": "0.012329598382413718", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0x35fa164735182de50811e8e2e824cfb9b6118ac2", "symbol": "eETH", "balance": "0.000000000000000001", "tokenPrice": "3637.93", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0xae7ab96520de3a18e5e111b5eaab095312d7fe84", "symbol": "stETH", "balance": "0.000000000000000001", "tokenPrice": "3637.93", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0xa3931d71877c0e7a3148cb7eb4463524fec27fbd", "symbol": "sUSDS", "balance": "67435907.43236613", "tokenPrice": "0", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0xa8705a14c79fa1cded70875510211fec822b3c30", "symbol": "BEEX", "balance": "5000000", "tokenPrice": "0", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0xabc0abace9fb9625fcefbedc423e8f94225bd251", "symbol": "TANUKI", "balance": "3548102.746002181", "tokenPrice": "0", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" }, { "chainIndex": "1", "tokenAddress": "0x356b8d89c1e1239cbbb9de4815c39a1474d5ba7d", "symbol": "syrupUSDT", "balance": "1750000", "tokenPrice": "0", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "0xed0c6079229e2d407672a117c22b62064f4a4312" } ] } ] } ```
- [Specific Token Balance](https://web3.okx.com/onchainos/docs/waas/walletapi-api-specific-token-balance-by-address.md) {/* api-page */} # Specific Token Balance Query the balance of a specific token under an address. ### Request Path POST `https://web3.okx.com/api/v5/wallet/asset/token-balances-by-address` ### Request Parameters | Parameter | Type | Required | Description | |----------------|--------|----------|-----------------------------------------| | address | String | Yes | Address | | tokenAddresses | Array | Yes | List of tokens addresses to query. Maximum of 20 items. | | >chainIndex | String | Yes | Unique identifier for the chain | | >tokenAddress | String | Yes | Token address.
`1`: Pass an empty string `""` to query the native token of the corresponding chain.
`2`: Pass the specific token contract address to query the corresponding token.
`3`: Different inscription tokens are passed in the following formats:
`FBRC-20`: Use `fbtc_fbrc20_name`, such as `fbtc_fbrc20_babymusk`
`BRC-20`: Use `btc-brc20-tick(name)`, such as `btc-brc20-ordi`
`Runes`: Use `btc-runesMain-tickId`, such as `btc-runesMain-840000:2`
`SRC-20`: Use `btc-src20-name`, such as `btc-src20-utxo`
| | filter | String | No | `0`: Filter out risky airdrop tokens
`1`: Do not filter out risky airdrop tokens
Default is to filter |
### Response Parameters | Parameter | Type | Description | |--------------|--------|-----------------------------------------| | tokenAssets | Array | List for token balances | | >chainIndex | String | Unique identifier for the chain | | >tokenAddress | String | Token address.If the return is an empty string `""`, it means the query is for the native token of the corresponding blockchain. | | >address | String | Address | | >symbol | String | Token symbol | | >balance | String | Token balance. | | >rawBalance | String | Raw balance of token address.More chains will be supported soon. For unsupported chains, this field is empty. | | >tokenPrice | String | Token price in USD | | >tokenType | String | Token type:
`1`: token
`2`: inscription | | >transferAmount | String | The balance of BRC-20, FBRC-20, and other inscription assets that can be directly transferred or traded, commonly referred to as the transferable balance. | | >availableAmount | String | The amount of BRC-20, FBRC-20, and other inscription assets that need to complete the inscription process before they can be traded or transferred, usually referred to as the available balance or pending inscription balance. | | >isRiskToken | Boolean | `true`: flagged as a risk airdrop token
`false`: not flagged |
### Request Example ```shell curl --location --request POST 'https://web3.okx.com/api/v5/wallet/asset/token-balances' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '{ "address": "0x50c476a139aab23fdaf9bca12614cdd54a4244e3", "tokenAddresses": [ { "chainIndex": "1", "tokenAddress": "" } ] }' ``` ### Response Example ``` json { "code": "0", "msg": "success", "data": [ { "tokenAssets": [ { "chainIndex": "1", "tokenAddress": "", "symbol": "eth", "balance": "0", "tokenPrice": "3640.43", "tokenType": "1", "isRiskToken": false, "transferAmount": "0", "availableAmount": "0", "rawBalance": "", "address": "" } ] } ] } ```
--- - [Get Owned UTXO](https://web3.okx.com/onchainos/docs/waas/walletapi-api-utxos.md) {/* api-page */} # Get Owned UTXO Query UTXOs under a specified address on UTXO chains such as BTC, Fractal BTC etc. The results are sorted in descending order by asset size, with a maximum of 10,000 records returned. ### Request Path GET `https://web3.okx.com/api/v5/wallet/utxo/utxos` ### Request Parameters | Parameter | Type | Required | Description | |------------|--------|----------|------------------------------| | chainIndex | String | Yes | Unique identifier for the chain | | address | String | Yes | Address information, required | | cursor | String | No | Cursor, defaults to the first position | | limit | String | No | Default is 50, max is 100 | ### Response Parameters | Parameter | Type | Description | |-------------|-------|-----------------------------------------------------------| | utxos | Array | UTXOs for the specified address | | >txHash | String| Transaction hash | | >voutIndex | String| Identifies which output position the UTXO is in; together with `txHash`, uniquely maps to a specific UTXO | | >amount | String| Amount of the UTXO, in satoshis | | >spendStatus| String| UTXO Spending Status
`1`: spending,
`2`: unspent | | cursor | String| Cursor |
### Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/wallet/utxo/utxos?chainIndex=0&address=bc1p8qfrmxdlmynr076uu28vlszxavwujwe7dus0r8y9thrnp5lgfh6qu2ctrr' --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### 响应示例 ``` json { "code": "0", "msg": "success", "data": [ { "cursor": "1", "utxos": [ { "txHash": "9e334346dd977cd766895c930e3921265abddb19fda4df0aa5cfd7d9201ed30a", "voutIndex": "0", "amount": "0.001", "spendStatus": "2" }, { "txHash": "d23531d511a841b67022aad0d21d82d66e1b35f023670398579540e84e23255c", "voutIndex": "1", "amount": "0.0008485", "spendStatus": "2" }, { "txHash": "5af52eda570c7f368793cd10788ce92bd2cbbf0668210306b82e63dd721c236a", "voutIndex": "1", "amount": "0.00084643", "spendStatus": "2" }, { "txHash": "54d4a7c116db0fb329e458afa2e9004244d43865fce40179f75a5adc9c006fdc", "voutIndex": "1", "amount": "0.00084083", "spendStatus": "2" }, { "txHash": "1cb254487dac6b52dab68c9566b90b9423667f8789c1eeeb1936571cc702005e", "voutIndex": "2", "amount": "0.00040348", "spendStatus": "2" }, { "txHash": "562428df1f5cdcaca9f6183dc0fe9d8a4f9e310a2c8fce4a5d3a6341e04f1455", "voutIndex": "1", "amount": "0.0001", "spendStatus": "2" }, { "txHash": "7c0dbe192e5595f23cf7a65e4497edd5c98ccf20e3299c1fafa19db6485b29b9", "voutIndex": "0", "amount": "0.0001", "spendStatus": "2" }, { "txHash": "0b70ed133dab27f44f115c81198a73853ef7d225c16f1fa8da3a618dcee45a8b", "voutIndex": "0", "amount": "0.00009065", "spendStatus": "2" }, { "txHash": "c1ce0a65ea9d13915a3703be1dc56cdfb75cf187aaf5fbf94af2f577f2834f3b", "voutIndex": "1", "amount": "0.00007924", "spendStatus": "2" }, { "txHash": "d3fe9ff28b85ca494ea5ac99414cfd92fbf4c18948ed5e805b2b908763c70559", "voutIndex": "0", "amount": "0.000018", "spendStatus": "2" }, { "txHash": "c8b69de2e3e0f89a2c6d73570c5f86b49d2f2a7635d8e7c9e85e593ab20ec9f7", "voutIndex": "0", "amount": "0.000012", "spendStatus": "2" }, { "txHash": "a1af403781f8a78be8fcd3b1c3f7d3834f9c5c96e96ab7de2c591abe95ad1b77", "voutIndex": "0", "amount": "0.000012", "spendStatus": "2" }, { "txHash": "dcf6575f35040c3203181925e46cb65d8663c950f04c38ec836a1047bc4b6e1d", "voutIndex": "0", "amount": "0.000012", "spendStatus": "2" }, { "txHash": "a4323a33b894710b023b15ec1cc04b31a305026401edcaa1efbd63e30ef1c29f", "voutIndex": "0", "amount": "0.000012", "spendStatus": "2" }, { "txHash": "b44859f6496c394b65290f66aea756516cce13b71a243530da6b4c0cd05187a5", "voutIndex": "0", "amount": "0.000012", "spendStatus": "2" }, { "txHash": "8409b14c213ca2980141ee7706b790109b83d0c16a2748f11936a23cac1c2cda", "voutIndex": "0", "amount": "0.000012", "spendStatus": "2" }, { "txHash": "562428df1f5cdcaca9f6183dc0fe9d8a4f9e310a2c8fce4a5d3a6341e04f1455", "voutIndex": "0", "amount": "0.000012", "spendStatus": "2" }, { "txHash": "c6408557c17429f29a77372a0911e3d6a7849a2b1e1dc2dda96b1085b8262013", "voutIndex": "0", "amount": "0.000012", "spendStatus": "2" }, { "txHash": "a9cd8b4a9c751578cf81cdcf324f7c7461ed12624d6eeac67eab541732e4f34f", "voutIndex": "0", "amount": "0.000012", "spendStatus": "2" }, { "txHash": "02c036196f148a9cdd9fc8abc7b8ef124feb84375a1d708126fab6d319bee7a1", "voutIndex": "0", "amount": "0.000012", "spendStatus": "2" }, { "txHash": "bf9536057243e0021ecd7f4a40934bbec766cfeacee85569131165f8bd3d19e9", "voutIndex": "0", "amount": "0.000012", "spendStatus": "2" }, { "txHash": "c98cee07c44d26b47e351df12757e88d052fea6ee7ab8588e2c1d68324d5388c", "voutIndex": "0", "amount": "0.000012", "spendStatus": "2" }, { "txHash": "f230741451130da4e15bbbe37f4beda7bbaf9b5b4e881e79ac9f94a920c7730e", "voutIndex": "0", "amount": "0.00001", "spendStatus": "2" }, { "txHash": "0ffc438bb4a5ef6a79108485fe4334a98f4dcbc8b9d914f211e67f3c720a1cfe", "voutIndex": "0", "amount": "0.00001", "spendStatus": "2" }, { "txHash": "8f1387b1f67f0b04923a9980818645c45fe55724c8ab91ee00930fcf12407734", "voutIndex": "0", "amount": "0.00001", "spendStatus": "2" }, { "txHash": "9caa4f86c9a368800ad0f94648bede27ed0229142eb89a49d54bcce97239a000", "voutIndex": "0", "amount": "0.00001", "spendStatus": "2" }, { "txHash": "ed031c5c5eabe4f137d95b6a8ae714eff54e42887cf80f78ded88a36f3d75dad", "voutIndex": "0", "amount": "0.00001", "spendStatus": "2" }, { "txHash": "d3fe9ff28b85ca494ea5ac99414cfd92fbf4c18948ed5e805b2b908763c70559", "voutIndex": "6", "amount": "0.000006", "spendStatus": "2" }, { "txHash": "09add0ddb2444f2077c4ddfaafe8ba79855237467d2d3ceaf74d13ec0135a33f", "voutIndex": "1", "amount": "0.00000546", "spendStatus": "2" }, { "txHash": "ef2cf264fc5ac437446c9f82c396241a8d84d0af35333d14eb780758c7dfb8fa", "voutIndex": "1", "amount": "0.00000546", "spendStatus": "2" }, { "txHash": "5443eca0ec477505b26c2ff7d8479f218d093df552132d542547865a8d5489d1", "voutIndex": "0", "amount": "0.00000546", "spendStatus": "2" }, { "txHash": "7ad7d948cba112cbb0122979578714ad3157bf17ee397f55d6f9b542d5360388", "voutIndex": "1", "amount": "0.00000546", "spendStatus": "2" }, { "txHash": "52aaab23cfe17dccad63220647d9c0cb77a45bd1334d324bba487472c2d37501", "voutIndex": "0", "amount": "0.00000546", "spendStatus": "2" }, { "txHash": "6e5c6c1206e2ff076dcddda6fbacbd6faf42d49a512adab7b9732b1099680273", "voutIndex": "1", "amount": "0.00000546", "spendStatus": "2" }, { "txHash": "7345405bb0fb6b846e3c1bfac8b9ef5dfec727444fcf6ad41c74c8f5b6cb99db", "voutIndex": "0", "amount": "0.00000546", "spendStatus": "2" }, { "txHash": "4f1e0f6842bd595362d74558f31105977d64060b6c587b3be257c6e648f1d44c", "voutIndex": "0", "amount": "0.00000546", "spendStatus": "2" }, { "txHash": "703a5caa76b3bb97114c6eed4d533d99f44210ed000313b4b8d5878a9bc26a36", "voutIndex": "1", "amount": "0.00000546", "spendStatus": "2" }, { "txHash": "69f9ff6843ea684fe68751adb8fb2fe1ae8caf553999c389bf5fcacf018c4f48", "voutIndex": "0", "amount": "0.00000546", "spendStatus": "2" }, { "txHash": "4c59b50c43a00b6db36129a9bcd16e88b39948070dd110660fee2b1ff61545da", "voutIndex": "0", "amount": "0.00000546", "spendStatus": "2" }, { "txHash": "2361f87d211d6b2982647e9ca776c2368daad41609d1ae25a45f95bf5e26b896", "voutIndex": "2", "amount": "0.00000546", "spendStatus": "2" }, { "txHash": "9b83ac2f681ec69cddf330949a1dd0215d10e7ec45bbd9741680449218ac376d", "voutIndex": "0", "amount": "0.00000546", "spendStatus": "2" }, { "txHash": "6eca7731240f4e3b8d68a25183e17f1c7079fb0fca60ea2836eef65d7cfbe2cf", "voutIndex": "0", "amount": "0.00000546", "spendStatus": "2" }, { "txHash": "a8e5e909db42a0ddbcb58964d0dbdafb0c810303d275584d53614c47b06422fa", "voutIndex": "0", "amount": "0.00000546", "spendStatus": "2" }, { "txHash": "ee50b94275d8b57bd4bb9a5b6978f58615b7ab6ce925624e2cddd7adfd13e75e", "voutIndex": "0", "amount": "0.00000546", "spendStatus": "2" }, { "txHash": "6688f647df1a320a5b9c37a95b127777082085702eaec98cba53d428e4a80ad4", "voutIndex": "2", "amount": "0.00000546", "spendStatus": "2" }, { "txHash": "6dd734bb29e4c6b978351fe527632fa2546716f9d2e6f65a3e804f077147a15e", "voutIndex": "0", "amount": "0.00000546", "spendStatus": "2" }, { "txHash": "2e9d38d44c130d692a82a07d73e722463c494f0b4a552d21e0612be00e7a9809", "voutIndex": "0", "amount": "0.00000546", "spendStatus": "2" }, { "txHash": "f5e53dcfbf891fbe6c44865930921d30d060a8a65a585fdd6f1ca0c25baa93f9", "voutIndex": "0", "amount": "0.00000546", "spendStatus": "2" }, { "txHash": "a9cd8b4a9c751578cf81cdcf324f7c7461ed12624d6eeac67eab541732e4f34f", "voutIndex": "1", "amount": "0.00000546", "spendStatus": "2" }, { "txHash": "7ccfaaab90e45b2a51729a0ab79d270dbf2616d42c118f55a9e9bb9f33ecfed3", "voutIndex": "0", "amount": "0.00000546", "spendStatus": "2" } ] } ] } ```
- [Check Inscriptions on UTXO](https://web3.okx.com/onchainos/docs/waas/walletapi-api-utxo-detail.md) {/* api-page */} # Check Inscriptions on UTXO - Query the quantity and detailed information of Runes, BRC-20, ARC-20, and Ordinals NFT assets on a specific UTXO on the Bitcoin chain. - Query the quantity and detailed information of BRC-20 assets on a specific UTXO on the Fractal Bitcoin chain. ### Request Path GET `https://web3.okx.com/api/v5/wallet/utxo/utxo-detail` ### Request Parameters | Parameter | Type | Required | Description | |------------|--------|----------|-------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain | | txHash | String | Yes | Transaction hash corresponding to the UTXO | | voutIndex | String | Yes | Identifies which output position the UTXO is in; together with txHash, uniquely maps to a specific UTXO | ### Response Parameters | Parameter | Type | Description | |--------------------|--------|----------------------------------------------------------------------------------------------------------| | address | String | Address | | txhash | String | Transaction hash corresponding to the UTXO | | voutIndex | String | Identifies which output position the UTXO is in; together with txhash, uniquely maps to a specific UTXO | | unresolved | Array | Lists protocols that have not completed block parsing, making it uncertain if the UTXO contains corresponding assets | | utxoStatus | String | UTXO Status
`pending`: Pending
`confirmed`: Confirmed
`Not found` : Not found | | btcAssets | Array | Detailed inscription assets on the current UTXO, with a maximum of 1,000 entries per asset | | >protocol | String | Protocol type
`1`:BRC-20
`2`:ARC-20
`3`:Runes
`4`:ordi_nft | | >tokenAmount | String | The quantity of transferable token assets on the UTXO | | >eventType | String | The specific transaction event for BRC-20 | | >decimal | String | Precision; returns empty if not available | | >symbol | String | Token name; returns empty if not available | | >inscriptionNumber | String | On-chain minting number inscriptions_number | | >nftId | String | Unique identifier of the NFT, txhash+i+0, applicable only for Ordinals protocol (i.e., BRC-20 and Ordinals NFT assets) | | >nftOffset | String | NFT location offset, indicating where the inscription is positioned on the UTXO, applicable only for Ordinals protocol (i.e., BRC-20 and Ordinals NFT assets) |
### Request Example ``` shell ``` ### Response Example ``` json { "code": "0", "msg": "success", "data": [ { "addresses": [ "bc1p8qfrmxdlmynr076uu28vlszxavwujwe7dus0r8y9thrnp5lgfh6qu2ctrr" ], "txHash": "cd7b77b068142ee1b099a360aeb287b5e02d4603a4523cb12d18cbd58aa47985", "voutIndex": "0", "utxoStatus":"confirmed" , "unresolved": [], "btcAssets": [ { "protocol": "4", "tokenAmount": "", "eventType": "", "decimal": "0", "symbol": "", "inscriptionNumber": "11896131", "nftId": "0b7c063d14d73cdb83e3454643fc1e4a3701bd5dc2f9550e5ab303247a68f7cai0", "nftOffset": "0" } ] } ] } ```
- [Get Approvals](https://web3.okx.com/onchainos/docs/waas/walletapi-api-get-approval-detail.md) {/* api-page */} # Get Approvals Retrieve details of which projects a single address has approved. Includes approved assets and amounts for each project. ### Request Path Get `https://web3.okx.com/api/v5/wallet/security/approvals` ### Request Parameters | Parameter | Type | Required | Description | |-------------|--------|----------|-------------------------------------| | addressList | Array | Yes | List of addresses, up to 20 | | >chainIndex | String | Yes | Unique identifier of the blockchain | | >address | String | Yes | Address information | | limit | String | No | Number of records per query, default is 50, max is 100 | | cursor | String | No | Cursor position, default is the first | ### Response Parameters | Parameter | Type | Description | |---------------------|--------|-------------------------------------------------------| | chainIndex | String | Unique identifier of the blockchain | | cursor | String | Cursor | | approvalProjects | Array | List of authorized projects | | >projectName | String | Project name | | >projectIcon | String | Project icon URL | | >approveAddress | String | Approved project address | | >tokens | Array | List of authorized tokens for the project | | >coinId | String | Coin identifier | | >imageUrl | String | Token logo URL | | >symbol | Array | Token symbol | | >status | String | Approval status:
`1`: Success
`2`: Pending cancellation
`3`: Pending approval | | >tokenAddress | String | Token contract address | | >approvalNum | String | Approved amount, specific authorization amount = approvalNum / 10 ^ precision |
### Request Example ``` shell curl --location --request POST 'https://web3.okx.com/api/v5/wallet/security/approvals' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '{ addressList:[ { "chainIndex":"0", "address":"3HyNd5YsqxyuieicbpKGfV2nBXgMn41dSd", } ], "limit": "10", "cursor": "1" }' ``` ### Response Example ``` json { "code": "0", "msg": "", "data": [ { "cursor":"100", "chainIndex": "1", "approvalProjects": [ { "projectIcon": "https://static.oklink.com/cdn/explorer/defi/uniswapv2.png", "projectName": "Uniswap", "approvalAddress": "0x2c34a2fb1d0b4f55de51e1d0bdefaddce6b7cdd6", "tokens": [ { "approvalNum": "2744484", "imageUrl": "https://static.coinall.ltd/cdn/wallet/logo/tusd.png", "symbol": "TUSD", "status": "1", "tokenAddress": "" } ] } ] } ] } ```
- [Get Asset by Account](https://web3.okx.com/onchainos/docs/waas/walletapi-api-intro-asset-account.md) # Get Asset by Account Provides various asset queries by account dimension. - [Total Value](https://web3.okx.com/onchainos/docs/waas/walletapi-api-total-token-value-account.md) {/* api-page */} # Total Value Retrieve the total balance of all tokens and DeFi assets under an account. Supports filtering of risky airdrop tokens. ### Request Path GET `https://web3.okx.com/api/v5/wallet/asset/total-value` ### Request Parameters | Parameter | Type | Required | Description | | ------------------| ------- | -------- | ------------------------------------------------------------------ | | accountId | String | Yes | Query total value for the account | | chains | String | No | Filter chains for which to query total assets, separated by ",". Supports up to 50 chains | | assetType | String | No | Query balance type. Default is to query all asset balances. 0: Query total balance for all assets, including tokens and DeFi assets. 1: Query only token balance. 2: Query only DeFi balance. | | excludeRiskToken | Boolean | No | Option to filter out risky airdrop tokens. Default is to filter. true: filter, false: do not filter | ### Response Parameters | Parameter | Type | Description | | --- | --- | --- | | totalValue | String | Total asset balance based on the query type, returned in USD | ### Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v5/wallet/asset/total-value?accountId=e7dba4c2-666d-496a-ad92-768d29291fee&chains=' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response Example ``` json { "code": "0", "msg": "success", "data": [ { "totalValue": "1172.895057177065864522056725546579939398" } ] } ``` - [Total Token Balances](https://web3.okx.com/onchainos/docs/waas/walletapi-api-wallet-all-token-balances.md) {/* api-page */} # Total Token Balances Query the token balance list for a wallet account across multiple chains or a specified chain. Balance query supports: - Chain native tokens - ERC20 tokens on EVM chains - BRC-20, ARC-20, Runes, and SRC-20 tokens in the Bitcoin ecosystem - Fractal Bitcoin chain's BRC-20 tokens Additionally, this interface supports filtering out risky airdrop tokens. ### Request Path GET `https://web3.okx.com/api/wallet/asset/wallet-all-token-balances` ### Request Parameters | Parameter | Type | Required | Description | |-----------|--------|----------|----------------------------------| | accountId | String | Yes | Unique identifier for the account. | | chains | Array | No | When filtering the chains for querying asset details, multiple chains should be separated by commas (`,`). A maximum of 50 chains is supported.| | filter | String | No | `0`: Filter risk tokens
`1`: Do not filter risk tokens
default is to filter |
### Response Parameters | Parameter | Type | Description | |---------------|--------|---------------------------------------------------| | tokenAssets | Array | Token balances | | >chainIndex | String | Unique identifier for the chain | | >tokenAddress | String | Contract address | | >address | String | Wallet address | | >symbol | String | Token symbol | | >balance | String | Token amount | | >rawBalance | String | Raw balance of token address. More chains will be supported soon. For unsupported chains, this field is empty. | | >tokenPrice | String | Token value in USD | | >tokenType | String | Token type:
`1`: token
`2`: inscription | | >isRiskToken | Boolean | `true`: Risk token
`false`: Not a risk token | | timeStamp | String | Timestamp when the token was retrieved, Unix timestamp in milliseconds |
### Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v5/wallet/asset/wallet-all-token-balances?filter=&chains=1&accountId=31f55853-d430-42c5-b4c6-710d39848cd1' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response Example ``` json { "code": "0", "data": [ { "tokenAssets": [ { "chainIndex": "1", "tokenAddress": "0xf4d2888d29d722226fafa5d9b24f9164c092421e", "symbol": "LOOKS", "balance": "0.6908810093750312", "rawBalance": "", "tokenPrice": "0.035834243057603148", "tokenType": "1", "isRiskToken": false, "address":"0xa03400e098f4421b34a3a44a1b4e571419517687" }, { "chainIndex": "1", "tokenAddress": "", "symbol": "ETH", "balance": "8", "rawBalance": "", "tokenPrice": "2650.43", "tokenType": "1", "isRiskToken": false, "address":"0xa03400e098f4421b34a3a44a1b4e571419517687" } ], "timeStamp": "1724153197342" } ], "msg": "success" } ```
- [Specific Token Balance](https://web3.okx.com/onchainos/docs/waas/walletapi-api-token-balances.md) {/* api-page */} # Specific Token Balance Query the balance of certain specific tokens under a wallet account. ### Request Path POST `https://web3.okx.com/api/v5/wallet/asset/token-balances` ### Request Parameters | Parameter | Type | Required | Description | |----------------|--------|----------|-----------------------------------------| | accountId | String | Yes | Unique identifier for the account | | tokenAddresses | Array | Yes | List of tokens. Maximum list size is 20 | | >chainIndex | String | Yes | Unique identifier for the chain | | >tokenAddress | String | Yes | Token address.
`1`: Pass an empty string `""` to query the native token of the corresponding chain.
`2`: Pass the specific token contract address to query the corresponding token.
`3`: Different inscription tokens are passed in the following formats:
`FBRC-20`: Use `fbtc_fbrc20_name`, such as `fbtc_fbrc20_babymusk`
`BRC-20`: Use `btc-brc20-tick(name)`, such as `btc-brc20-ordi`
`Runes`: Use `btc-runesMain-tickId`, such as `btc-runesMain-840000:2`
`SRC-20`: Use `btc-src20-name`, such as `btc-src20-utxo`
|
### Response Parameters | Parameter | Type | Description | |--------------|--------|-----------------------------------------| | tokenAssets | Array | List for token balances | | >chainIndex | String | Unique identifier for the chain | | >tokenAddress | String | Token address.If the return is an empty string `""`, it means the query is for the native token of the corresponding blockchain. | | >symbol | String | Token symbol | | >balance | String | Token balance | | >rawBalance | String | Raw balance of token address. More chains will be supported soon. For unsupported chains, this field is empty. | | >tokenPrice | String | Token price in USD | | >tokenType | String | Token type:
`1`: token
`2`: inscription | | >isRiskToken | Boolean | `true`: flagged as a risk airdrop token
`false`: not flagged |
### Request Example ``` shell curl --location --request POST 'https://web3.okx.com/api/v5/wallet/asset/token-balances' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '{ "accountId": "4686531e-3adb-469a-8000-8fd1c2097f68", "tokenAddresses": [ { "chainIndex": "1", "tokenAddress": "" }, { "chainIndex": "0", "tokenAddress": "btc-brc20-psat" } ] }' ``` ### Response Example ``` json { "code": "0", "msg": "success", "data": [ { "tokenAssets": [ { "chainIndex": "1", "tokenAddress": "", "symbol": "ETH", "balance": "0.07210371955388872", "rawBalance": "", "tokenPrice": "2650.43", "tokenType": "1", "isRistToken": false }, { "chainIndex": "0", "tokenAddress": "btc-brc20-psat", "symbol": "psat", "balance": "1", "rawBalance": "", "tokenPrice": "140", "tokenType": "2", "isRiskToken": false } ] } ] } ```
- [Transaction History](https://web3.okx.com/onchainos/docs/waas/walletapi-api-intro-post-transaction-data-api.md) # Transaction History The transaction history section supports querying transaction summaries and details, including inscription transactions. The transactions is only reserved for half a year - [Get History by Address](https://web3.okx.com/onchainos/docs/waas/walletapi-api-transactions-by-address.md) {/* api-page */} # Get History by Address Query the transaction history under the address dimension, sorted in descending chronological order. ### Request Path GET `https://web3.okx.com/api/v5/wallet/post-transaction/transactions-by-address` ### Request Parameters | Parameter | Type | Required | Description | |-------------- |-------- |---------- |--------------------------------------------------------------------------------------------------------------- | | address | String | Yes | Address to query the transaction history for | | chainIndex | String | No | Unique identifier for the chain, e.g. ETH=3 | | tokenAddress | String | No | Token contract address. Used to filter transactions for a specific token | | tokenAddress | String | No | Token contract address; if empty, query addresses with main chain currency balance;if not pass, query all | | begin | String | No | Start time, queries transactions after this time. Unix timestamp, in milliseconds | | end | String | No | End time, queries transactions before this time. If both begin and end are not provided, queries transactions before the current time. Unix timestamp, in milliseconds | | cursor | String | No | Cursor | | limit | String | No | Number of records to return, defaults to the most recent 20 records.
Up to a maximum of 20 records for query on single chain.
Up to a maximum of 100 records for query on multiple chain. | |
### Response Parameters | Parameter | Type | Description | |----------------- |--------------------------------- |----------------------------------------------------- | | transactionList | Array | List of transactions | | >chainIndex | String | Chain ID | | >txHash | String | Transaction hash | | >iType | String | EVM Transaction tier type
`0`: Outer main chain coin transfer
`1`: Contract inner main chain coin transfer
`2`: Token transfer | | >methodId | String | Contract Function Call | | >nonce | String | The nth transaction initiated by the sender address | | >txTime | String | Transaction time in Unix timestamp format, in milliseconds, e.g., 1597026383085 | | >from | Array | Transaction input | | >>address | String | Sending/input address, comma-separated for multi-signature transactions | | >>amount | String | Input amount | | >to | Array | Transaction output | | >>address | String | Receiving/output address, comma-separated for multiple addresses | | >>amount | String | Output amount | >tokenAddress | String | Token contract address | | >amount | String | Transaction amount | | >symbol | String | Currency symbol corresponding to the transaction amount | | >txFee | String | Transaction fee | | >txStatus | String | Transaction status: `success` for successful transactions, `fail` for failed transactions, `pending` for pending transactions | | >hitBlacklist | Boolean | `false`: Not in blacklist, `true`: In blacklist | | >tag | String | Tag type for blacklisted addresses, including phishing, contract vulnerabilities, etc. `Deprecated` | | cursor | String | Cursor |
### Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v5/wallet/post-transaction/transactions-by-address?addresses=0x50c476a139aab23fdaf9bca12614cdd54a4244e4&chains=1' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response Example ``` json { "code": "0", "msg": "success", "data": [ { "cursor": "1706197403", "transactionList": [ { "chainIndex": "1", "txHash": "0x963767695543cfb7804039c470b110b87adf9ab69ebc002b571523b714b828ca", "methodId": "", "nonce": "", "txTime": "1724213411000", "from": [ { "address": "0xae7ab96520de3a18e5e111b5eaab095312d7fe84" "amount": "" } ], "to": [ { "address": "0x50c476a139aab23fdaf9bca12614cdd54a4244e4" "amount": "" } ], "tokenAddress": "0xe13c851c331874028cd8f681052ad3367000fb13", "amount": "1", "symbol": "claim rewards on stethdao.net", "txFee": "", "txStatus": "success", "hitBlacklist": true, "tag": "Risk Airdrop", "iType": "2" } ] } ] } ```
- [Get History by Account ](https://web3.okx.com/onchainos/docs/waas/walletapi-api-transaction-list.md) {/* api-page */} # Get History by Account Query all or specific chain transaction history under the account dimension, sorted in descending chronological order. ### Request Path GET `https://web3.okx.com/api/v5/wallet/post-transaction/transactions` ### Request Parameters | Parameter | Type | Required | Description | |-------------- |-------- |---------- |--------------------------------------------------------------------------------------------------------------- | | accountId | String | Yes | Unique identifier for the account | | chainIndex | String | No | Unique identifier for the chain, e.g. ETH=3 | | tokenAddress | String | No | Token contract address; if empty, query addresses with main chain currency balance;if not pass, query all | | begin | String | No | Start time, queries transactions after this time. Unix timestamp, in milliseconds | | end | String | No | End time, queries transactions before this time. If both begin and end are not provided, queries transactions before the current time. Unix timestamp, in milliseconds | | cursor | String | No | Cursor | | limit | String | No | Number of records to return, defaults to the most recent 20 records, up to a maximum of 20 records | | ### Response Parameters | Parameter | Type | Description | |---------------- |-------- |----------------------------------------------------- | | transactionList | Array | List of transactions | | >chainIndex | String | Chain ID | | >txHash | String | Transaction hash | | >iType | String | EVM transaction layer type
`0`: External main chain coin transfer
`1`: Contract internal main chain coin transfer
`2`: Token transfer | | >methodId | String | Method | | >nonce | String | The number of transactions initiated by the sender address | | >txTime | String | Transaction time; Unix timestamp in milliseconds, e.g., 1597026383085 | | >from | Array | Transaction inputs | | >>address | String | Sender/input address, separated by commas for multi-signature transactions | | >>amount | String | Input amount | | >to | Array | Transaction outputs | | >>address | String | Receiver/output address, separated by commas for multi-signature transactions | | >>amount | String | Output amount | | >tokenAddress | String | Token contract address | | >amount | String | Transaction amount | | >symbol | String | Currency symbol for the transaction amount | | >txFee | String | Transaction fee | | >txStatus | String | Transaction status; success, fail, pending, etc. | | >hitBlacklist | Boolean | false: not in blacklist true: in blacklist | | >tag | String | Blacklist tag type, including types like phishing, network phishing, and contract vulnerabilities.`Deprecated` | | cursor | String | Cursor |
### Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v5/wallet/post-transaction/transactions?accountId=31f55853-d430-42c5-b4c6-710d39848cd1' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ ``` ### Response Example ``` json { "code": "0", "msg": "success", "data": [ { "cursor": "1724212391", "transactions": [ { "chainIndex": "0", "txHash": "5fd7e21515b088e2c47641779d53de4ff3b982c7d71a5e85f06f32d8cd4c5bcc", "methodId": "", "nonce": "", "txTime": "1724250342000", "from": [ { "address": "bc1pm7fxkgcrqghf2rtxdw4hupvdpqkped7azyrh2mukedrw2p0cj3hsxt8ph3" "amount": "0.000432" } ], "to": [ { "address": "bc1pm7fxkgcrqghf2rtxdw4hupvdpqkped7azyrh2mukedrw2p0cj3hsxt8ph3" "amount": "0.00010" }, { "address": "bc1pm7fxkgcrqghf2rtxdw4hupvdpqkped7azyrh2mukedrw2p0cj3hsxt8ph3" "amount": "0.00032738" } ], "tokenAddress": "", "amount": "", "symbol": "BTC", "txFee": "0.00000462", "txStatus": "success", "hitBlacklist": false, "tag": "", "iType": "" }, { "chainIndex": "1", "txHash": "0x307ced97491fdeea9acb141cb3d07939ef3291f28c06c0cacd1cc1f8c435bbe1", "methodId": "", "nonce": "945", "txTime": "1724056787000", "from": [ { "address": "0x50c476a139aab23fdaf9bca12614cdd54a4244e4" "amount": "" } ], "to": [ { "address": "0x2491889438e5130a4cf629fbc93ae31aad742d8b" "amount": "" } ], "tokenAddress": "", "amount": "0.00001", "symbol": "ETH", "txFee": "1.89E-23", "txStatus": "success", "hitBlacklist": false, "tag": "", "iType": "0" } ] } ] } ```
- [Get Specific Transaction](https://web3.okx.com/onchainos/docs/waas/walletapi-api-transaction-detail-by-txhash.md) {/* api-page */} # Get Specific Transaction Retrieve details of a transaction based on `txHash`. The Wallet API decomposes a transaction and its internal transactions into sub-transactions based on asset type:
`0`: Outer layer mainnet coin transfer
`1`: Inner layer mainnet coin transfer in a contract
`2`: Token transfer The Wallet API decomposes a transaction into sub-transactions based on asset type. For EVM transactions, different sub-transaction types include:
`0`: Outer layer mainnet coin transfer
`1`: Inner layer mainnet coin transfer in a contract
`2`: Token transfer
### Request Path GET `https://web3.okx.com/api/v5/wallet/post-transaction/transaction-detail-by-txhash` ### Request Parameters | Parameter | Type | Required | Description | |--------------------|----------------|------------------|--------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain | | txHash | String | Yes | Transaction hash | | iType | String | No | Layer type for EVM transactions
`0`: Outer layer mainnet coin transfer
`1`: Inner layer mainnet coin transfer
`2`: Token transfer |
### Response Parameters | Parameter | Type | Description | |------------------------------------|----------------|----------------------------------------------------------------| | chainIndex | String | Unique identifier for the chain | | height | String | Block height where the transaction occurred | | txTime | String | Transaction time; Unix timestamp in milliseconds | | txhash | String | Transaction hash | | txStatus | String | Transaction status:
`1`: pending
`2`: success
`3`: fail | | gasLimit | String | Gas limit | | gasUsed | String | Gas used | | gasPrice | String | Gas price | | txFee | String | Transaction fee. | | nonce | String | Nonce | | amount | String | Transaction amount | | symbol | String | Currency symbol for the transaction amount | | methodId | String | Contract method ID | | fromDetails | Array | Details of transaction inputs | | >address | String | Sender/input address | | >vinIndex | String | Index of the input in the current transaction | | >preVoutIndex | String | Index of the output in the previous transaction | | >txhash | String | Transaction hash, used with `preVoutIndex` to uniquely identify the UTXO | | >isContract | Boolean | Whether the sender address is a contract (true: yes; false: no) | | >amount | String | Transaction amount | | toDetails | Array | Details of transaction outputs | | >address | String | Receiver/output address | | >voutIndex | String | Output index | | >isContract | Boolean | Whether the receiver address is a contract (true: yes; false: no) | | >amount | String | Transaction amount | | internalTransactionDetails | Array | Internal transaction details | | >from | String | Sender address for the internal transaction | | >to | String | Receiver address for the internal transaction | | >isFromContract | Boolean | Whether the sender address is a contract (true: yes; false: no) | | >isToContract | Boolean | Whether the receiver address is a contract (true: yes; false: no) | | >amount | String | Transaction amount | | >txStatus | String | Transaction status | | tokenTransferDetails | Array | Token transfer details | | >from | String | Sender address for token transfer | | >to | String | Receiver address for token transfer | | >isFromContract | Boolean | Whether the sender address is a contract (true: yes; false: no) | | >isToContract | Boolean | Whether the receiver address is a contract (true: yes; false: no) | | >tokenContractAddress | String | Token contract address | | >symbol | String | Token symbol | | >amount | String | Token amount | | l1OriginHash | String | Hash of the L1 transaction executed |
### Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/wallet/post-transaction/transaction-detail-by-txhash?txHash=0x9ab8ccccc9f778ea91ce4c0f15517672c4bd06d166e830da41ba552e744d29a5&chainIndex=42161' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response Example Example with ETH ``` json { "code": "0", "msg": "success", "data": [ { "chainIndex": "42161", "height": "245222398", "txTime": "1724253417000", "txhash": "0x9ab8ccccc9f778ea91ce4c0f15517672c4bd06d166e830da41ba552e744d29a5", "gasLimit": "2000000", "gasUsed": "2000000", "gasPrice": "10000000", "txFee":"", "nonce": "0", "symbol": "ETH", "amount": "0", "txStatus": "success", "methodId": "0xc9f95d32", "l1OriginHash": "0xa6a87ba2f18cc32bbae8f3b2253a29a9617ed1eb0940d80443f6e3bf9873dbad", "fromDetails": [ { "address": "0xd297fa914353c44b2e33ebe05f21846f1048cfeb", "vinIndex": "", "preVoutIndex": "", "txHash": "", "isContract": false, "amount": "" } ], "toDetails": [ { "address": "0x000000000000000000000000000000000000006e", "voutIndex": "", "isContract": false, "amount": "" } ], "internalTransactionDetails": [ { "from": "0x0000000000000000000000000000000000000000", "to": "0xd297fa914353c44b2e33ebe05f21846f1048cfeb", "isFromContract": false, "isToContract": false, "amount": "0.02", "txStatus": "success" }, { "from": "0xd297fa914353c44b2e33ebe05f21846f1048cfeb", "to": "0x428ab2ba90eba0a4be7af34c9ac451ab061ac010", "isFromContract": false, "isToContract": false, "amount": "0.00998", "txStatus": "success" }, { "from": "0xd297fa914353c44b2e33ebe05f21846f1048cfeb", "to": "0x428ab2ba90eba0a4be7af34c9ac451ab061ac010", "isFromContract": false, "isToContract": false, "amount": "0.009977946366846017", "txStatus": "success" } ], "tokenTransferDetails": [] } ] } For BTC example: { "code": "0", "msg": "success", "data": [ { "chainIndex": "0", "height": "858056", "txTime": "1724403746000", "txhash": "0538eec298699ff4b7cc07163c7216c48fe40caed492a3c655382bf0ae63db1a", "gasLimit": "", "gasUsed": "", "gasPrice": "", "txFee":"", "nonce": "", "symbol": "BTC", "amount": "", "txStatus": "success", "methodId": "", "l1OriginHash": "", "fromDetails": [ { "address": "bc1py4kmmdsae08zd6jlfdkcr9gzagxrs3z5elw2hjyc5u883a8ah7ps98s0mn", "vinIndex": "0", "preVoutIndex": "1", "txHash": "b7b1460db2e7fff53cb1da10ad5351bd9a684668f21968a6b292dfe019605c4c", "isContract": false, "amount": "0.00001296" } ], "toDetails": [ { "address": "bc1p7pgnqe87red4cvd7ml6rh9pl9ufpr522k2y3dpeyrvfc6g2g3r3s3ae9dr", "voutIndex": "0", "isContract": false, "amount": "0.00000546" } ], "internalTransactionDetails": [], "tokenTransferDetails": [] } ] } ```
- [Get Inscription Transactions](https://web3.okx.com/onchainos/docs/waas/walletapi-api-inscription-transaction-detail-by-txhash.md) {/* api-page */} # Get Inscription Transactions Query token inscription transaction details by transaction hash. - Supports querying transaction details for Runes, BRC-20, SRC-20, ARC-20, and Ordinals NFT on the BTC chain. - Supports querying transaction details for BRC-20 on the Fractal Bitcoin chain. ### Request Path GET `https://web3.okx.com/api/v5/wallet/post-transaction/inscription-transaction-detail-by-txhash` ### Request Parameters | Parameter | Type | Required | Description | |--------------|--------|----------|-------------------------------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain | | txHash | String | Yes | Transaction hash | | protocol | String | Yes | Protocol Type
`1`: BRC-20
`2`: ARC-20
`3`: Runes
`4`: Ordinals NFT
`5`:SRC-20
If not specified, defaults to BRC-20 | | cursor | String | No | Cursor | | limit | String | No | Number of entries to return, default is 20, maximum is 100 |
### Response Parameters | Parameter | Type | Description | |---------------------- |-------- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | transactionDetails | Array | Transaction details | | >txStatus | String | Transaction status
Success: `success`
Fail: `fail`
Pending transactions not supported | | >from | String | Sender(s), separated by commas for multisig addresses | | >to | String | Receiver(s), separated by commas for multisig addresses | | >eventType | String | Transaction type
BRC-20: `deploy`, `mint`, `inscribeTransfer`, `transfer`
Runes: `Etch`, `Mintoutput`, `Burninput`, `Mint`
ARC-20: `atomical-create-ft`, `ft-color-split`, `ft-color-regular`, `distributed-mint`
SRC-20: `mint`, `transfer`, `deploy`
Ordinals NFT: `mint`, `transfer` | | >protocol | String | Protocol type
`1`:BRC-20
`2`:ARC-20
`3`:Runes
`4`:ordi_nft
`5`: SRC-20 | | >txHash | String | Transaction hash | | >blockHash | String | Block hash | | >height | String | Block height at which the transaction occurred | | >txTime | String | Transaction time; in Unix timestamp format (milliseconds), e.g., 1597026383085 | | >amount | String | Transaction amount | | >symbol | String | Token name | | >tokenInscriptionId | String | Inscription token ID
For Runes: returns `Rune ID`
For BRC-20 tokens: returns the token's `Inscription ID`, the unique identifier for the token
For ARC-20 tokens: returns the token's `Atomical ID`
For other inscription tokens, this field returns empty | | >inscriptionNumber | String | Inscription number involved in each transaction | | >outputIndex | String | UTXO index corresponding to Runes token transfers, applicable only to Runes tokens | | cursor | String | Cursor |
### Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/wallet/post-transaction/inscription-transaction-detail-by-txhash?chainIndex=0&limit=10&txHash=18ccb1bc8c931cf4253065c2a5612fed7bd0eabd0a34139485b34305bcfc2b18&protocol=2' --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response Example ``` json { "code": "0", "msg": "success", "data": [ { "cursor": "", "transactionDetails": [ { "txHash": "18ccb1bc8c931cf4253065c2a5612fed7bd0eabd0a34139485b34305bcfc2b18", "blockHash": "00000000000000000000bcf4a44104b9cc54dc3a6e3b8a1007d73077e4fe224b", "height": "854743", "txTime": "1722394665000", "from": "", "to": "bc1pltwpza8fz00aqjf0s6z5pvhzrtwpj5nk75m5x7st7rqnq6tkqa2skhcs40", "amount": "1454", "symbol": "quark", "eventType": "ft-color-regular", "tokenInscriptionId": "9125f03bcf9325f6071762b9aee00b461a0b43ed157c336e2e89e07f47ea6f66i0", "protocol": "2", "txStatus": "success", "inscriptionId": "", "inscriptionNumber": "", "outputIndex": "" }, { "txHash": "18ccb1bc8c931cf4253065c2a5612fed7bd0eabd0a34139485b34305bcfc2b18", "blockHash": "00000000000000000000bcf4a44104b9cc54dc3a6e3b8a1007d73077e4fe224b", "height": "854743", "txTime": "1722394665000", "from": "", "to": "bc1pm7fxkgcrqghf2rtxdw4hupvdpqkped7azyrh2mukedrw2p0cj3hsxt8ph3", "amount": "546", "symbol": "quark", "eventType": "ft-color-regular", "tokenInscriptionId": "9125f03bcf9325f6071762b9aee00b461a0b43ed157c336e2e89e07f47ea6f66i0", "protocol": "2", "txStatus": "success", "inscriptionId": "", "inscriptionNumber": "", "outputIndex": "" } ] } ] } ```
- [Wallet Account Management](https://web3.okx.com/onchainos/docs/waas/walletapi-api-intro-account-api.md) # Wallet Account Management Provides API interfaces for managing wallet accounts, supporting operations to add, delete, update, and query wallet account addresses. - [Create Account](https://web3.okx.com/onchainos/docs/waas/walletapi-api-create-wallet-account.md) {/* api-page */} # Create Account Bind multiple addresses to create a wallet account. The supported chains return all tokens by default, and it allows aggregated queries for asset and transaction history. The number of addresses that can be aggregated in a wallet account has an upper limit, which is based on the number of chains [we support](./walletapi-resources-supported-networks). ### Request Path POST `https://web3.okx.com/api/v5/wallet/account/create-wallet-account` ### Request Parameters | Parameter | Type | Required | Description | |-------------|--------|----------|--------------------------------------------------------------------------------------------------------------| | addresses | Array | Yes | List of addresses. (Maximum 50 addresses per call, for subsequent additions, use [Update Account](./walletapi-api-update-watch-only-account)) | | >chainIndex | String | Yes | Unique identifier of the chain | | >address | String | Yes | Address | ### Response Parameters | Parameter | Type | Description | |-----------|--------|--------------------------------| | accountId | String | Unique identifier of the wallet account | ### Request Example ```shell curl --location --request POST 'https://web3.okx.com/api/v5/wallet/account/create-wallet-account' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '{ "addresses": [ { "chainIndex":"1", "address":"0x561815e02bac6128bbbbc551005ddfd92a5c24db" },{ "chainIndex":"0", "address":"bc1p939endmmt6pvz7ukeywpfsazz57cc4vdu3d0qerz6crhgrtmerfssls5wy" } ] }' ``` ### Response Example ``` json { "code": "0", "data": [ { "accountId": "13886e05-1265-4b79-8ac3-b7ab46217655" } ], "msg": "success" } ``` - [Update Account](https://web3.okx.com/onchainos/docs/waas/walletapi-api-update-wallet-account.md) {/* api-page */} # Update Account Change the addresses bound under a specific wallet account. ### Request Path POST `https://web3.okx.com/api/v5/wallet/account/update-wallet-account` ### Request Parameters | Parameter | Type | Required | Description | |-------------|--------|----------|-------------------------------------------------------------------| | accountId | String | Yes | Unique identifier of the account | | updateType | String | Yes | `add`: Add addresses
`delete`: Delete addresses | | addresses | Array | Yes | List of addresses. (Maximum 50 addresses per call) | | >chainIndex | String | Yes | Unique identifier of the chain | | >address | String | Yes | Address |
### Response Parameters None
### Request Example ```shell curl --location --request POST 'https://web3.okx.com/api/v5/wallet/account/update-wallet-account' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '{ "accountId": "13886e05-1265-4b79-8ac3-b7ab46217655", "updateType": "add", "addresses": [ { "chainIndex":"1", "address":"0x561815e02bac6128bbbbc551005ddfd92a5c24db" },{ "chainIndex":"0", "address":"bc1p939endmmt6pvz7ukeywpfsazz57cc4vdu3d0qerz6crhgrtmerfssls5wy" } ] }' ``` ### Response Example ``` json { "code": "0", "data": [], "msg": "success" } ```
- [Delete Account](https://web3.okx.com/onchainos/docs/waas/walletapi-api-delete-account.md) {/* api-page */} # Delete Account Delete an existing account. ### Request Path POST `https://web3.okx.com/api/v5/wallet/account/delete-account` ### Request Parameters | Parameter | Type | Required | Description | |-----------|--------|----------|--------------------------------| | accountId | String | Yes | Unique identifier of the account | ### Response Parameters None ### Request Example ```shell curl --location --request POST 'https://web3.okx.com/api/v5/wallet/account/delete-account' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '{ "accountId": "13886e05-1265-4b79-8ac3-b7ab46217655" }' ``` ### Response Example ``` json { "code": "0", "data": [], "msg": "success" } ``` - [Get Accounts](https://web3.okx.com/onchainos/docs/waas/walletapi-api-accounts.md) {/* api-page */} # Get Accounts List accounts created under the project. ### Request Path GET `https://web3.okx.com/api/v5/wallet/account/accounts` ### Request Parameters | Parameter | Type | Required | Description | | --- | --- | --- | --- | | limit | String | No | Number of items to query each time, default is 50, maximum is 100 | | cursor | String | No | Cursor position, defaults to the first one | ### Response Parameters | Parameter | Type | Description | | --- | --- | --- | | cursor | String | Cursor | | accounts | Array | List of accounts | | >accountId | String | Unique identifier of the account | | >accountType | String | `0`: Wallet account
`1`: Watch-only account |
### Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v5/wallet/account/accounts' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ ``` ### Response Example ``` json { "code": "0", "data": [ { "cursor": "50", "accounts": [ { "accountId": "0xdf54b6c6195ea4d948d03bfd818d365cf175cfc2", "accountType": "0" }, { "accountId": "0x04ad62387d1f1c7034087bbe4d16163d06fae42d", "accountType": "1" } ] } ], "msg": "success" } ```
- [Get Addresses Under Account](https://web3.okx.com/onchainos/docs/waas/walletapi-api-account-detail.md) {/* api-page */} # Get Addresses Under Account Query the addresses bound under a specific account. ### Request Path GET `https://web3.okx.com/api/v5/wallet/account/account-detail` ### Request Parameters | Parameter | Type | Required | Description | | --- | --- | --- | --- | | accountId | String | Yes | Unique identifier of the account | | chainIndex | String | No | Unique identifier of the chain | | limit | String | No | Number of items to query each time, default is 50, maximum is 100 | | cursor | String | No | Cursor position, defaults to the first one | ### Response Parameters | Parameter | Type | Description | | --- | --- | --- | | cursor | String | Cursor | | addresses | Array | Address list | | >chainIndex | String | Unique identifier of the chain | | >address | String | Address | ### Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v5/wallet/account/account-detail?accountId=44486e05-3235-2f8e-5fe2-a8ab46217863' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response Example ``` json { "code": "0", "data": [ { "cursur": "50", "addresses": [ { "chainIndex": "1", "address":"0xdf54b6c6195ea4d948d03bfd818d365cf175cfc2" }, { "chainIndex": "3", "address":"0x04ad62387d1f1c7034087bbe4d16163d06fae42d" } ] } ], "msg": "success" } ``` - [Transaction Broadcasting](https://web3.okx.com/onchainos/docs/waas/walletapi-api-intro-transaction-api.md) # Transaction Broadcasting The Transaction Broadcasting API interface provides services for obtaining signature data, broadcasting transactions, and tracking transactions after they are sent. - [Pre-Transaction Information](https://web3.okx.com/onchainos/docs/waas/walletapi-api-intro-pre-transaction.md) # Pre-Transaction Information The pre-transaction information section mainly includes obtaining relevant data and verification before a transaction. - [Sign Info](https://web3.okx.com/onchainos/docs/waas/walletapi-api-sign-info.md) {/* api-page */} # Sign Info This API can retrieve all information needed to assemble a transaction at once (gas-limit, gas-price, nonce). ### Request Path POST `https://web3.okx.com/api/v5/wallet/pre-transaction/sign-info` ### Request Parameters | Parameter | Type | Required | Description | |------------|--------|----------|-----------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain | | fromAddr | String | Yes | From address | | toAddr | String | Yes | To address | | txAmount | String | No | Native token amount for the transaction, default is 0. Must include this parameter when involving mainnet coin transfer, otherwise it will affect the calculation of gas limit,passed in the smallest unit of the chain native token, such as ETH wei. | | extJson | Object | Yes | Extension parameters, used to add calldata and other information | **extJson** | Parameter | Type | Required | Description | |-----------|--------|----------|-------------| | inputData | String | No | calldata | | protocol | String | No | Query for specific protocol:
`1`: BRC-20
`2`: ARC-20
`3`: Runes
`4`: ordi_nft | | tokenAddress | String | No | Only appliable to `Solana` | | permissionType | String | No | Only appliable to `Tron`
`1`:owner permission
`2`: witness permission
`1` by default | | feeLimit | String | No | Only appliable to `Tron`. Required if interact with contract, `30000000` by default |
### Response Parameters #### EVM | Parameter | Type | Description | |------------------|---------|-------------------| | gasLimit | String | Gas consumption | | nonce | String | Current Number, This endpoint only returns the on-chain nonce. For example, if the maximum nonce that has successfully been confirmed on-chain for the current address is 10, the result of the request will be 11. If you need the nonce from the memory pool, please refer to [Get Nonce](./walletapi-api-nonce). | | gasPrice | Object | Gas consumption price | | >normal | String | Medium gas price, in wei | | >min | String | Low gas price, in wei | | >max | String | High gas price, in wei | | >supporteip1559 | Boolean | Whether supports EIP 1559 | | >eip1559Protocol | Object | EIP 1559 protocol detail | ##### eip1559 Protocol | Parameter | Type | Description | |---------------------|--------|----------------------------------------------------------------------------------| | eip1559Protocol | Object | EIP 1559 protocol detail | | >baseFee | String | Base fee | | >proposePriorityFee | String | Medium priority fee, in wei | | >safePriorityFee | String | Low priority fee, in wei | | >fastPriorityFee | String | High priority fee, in wei | #### UTXO | Parameter | Type | Description | |-------------------|--------|--------------------------------------------| | normalFeeRate | String | Medium fee rate | | maxFeeRate | String | High fee rate | | minFeeRate | Object | Low fee rate | | inscriptionOutput | String | Inscription output size | | minOutput | String | Minimum inscription output size, in Satoshi (usually 546 Satoshi) | | normalCost | String | Single inscription transaction cost, in Satoshi | | maxCost | String | Maximum single inscription transaction cost, in Satoshi | | minCost | String | Minimum single inscription transaction cost, in Satoshi | #### Solana | Parameter | Type | Description | | ----------------- | ------ | ------------------------------------------------------------------------ | | baseFee | String | Base fee | | priorityFee | String | Priority fee | | >normalUnitPrice | Object | Normal price | | >minUnitPrice | String | Minimum price | | >maxUnitPrice | String | Maximum price | | recentBlockHash | String | Recent block hash | | lastValidBlockHeight | String | Last valid block | | fromAddressRent | String | Rent for fromAddress | | toAddressRent | String | Rent for toAddress | | tokenAccountInfo | String | Token account information for fromAddress. Exists if token-transfer happened. | | >lamports | String | Lamports | | >ownerAddress | String | From address | | >mintAddress | String | Token address | | >tokenAccountAddress | String | Token account address | | >decimal | String | Decimal | #### Tron | Parameter | Type | Description | | ----------------- | ------ | ------------------------------------------------------------------------ | | fee | String | Fee | | refBlockBytes | String | Reference block bytes.
The 6th to 8th bytes (not included) of the reference block height are used to help verify whether the transaction is based on the valid state of the current blockchain and prevent forked transaction replay | | refBlockHash | Object | Recenteference block hash.
The 8th to 16th bytes (not included) of the reference block hash are used. If the transaction's ref_block_hash does not match the actual existing block hash, the transaction may be rejected or marked as invalid. | | expiration | String | Expiration time | | timestamp | String | Timestamp |
### Request Example ```shell curl --location --request POST 'https://web3.okx.com/api/v5/wallet/pre-transaction/sign-info' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '{ "accountId":"0x04ad62387d1f1c7034087bbe4d16163d06fae42d", "chainIndex": "1", "tokenAddress": "0xdf54b6c6195ea4d948d03bfd818d365cf175cfc2" }' ``` ### Response Example ```json // EVM { "code": "0", "data": [ { "gasLimit": "21000", "nonce": "15", "gasPrice": { "normal": "21289500000", "min": "15670000000", "max": "29149000000", "supportEip1559": true, "eip1599Protocol": { "suggestBaseFee": "15170000000", "baseFee": "15170000000", "proposePriorityFee": "810000000", "safePriorityFee": "500000000", "fastPriorityFee": "3360000000" } } } ], "msg": "" } // UTXO/ BRC-20 { "code": "0", "data": [ { "normalFeeRate": "27", "maxFeeRate": "35", "minFeeRate": "22", "inscriptionOutput": "546", "minOutput": "1500", "normalCost": "1800", "maxCost": "3600", "minCost": "600" } ] } //Solana { "code": "0", "msg": "success", "data": [ { "baseFee": "5000", "priorityFee": { "normalUnitPrice": "4325963", "minUnitPrice": "4325963", "maxUnitPrice": "4325963" }, "recentBlockHash": "C7Qq7cLjBQSU2eTS7458DDe1HvmBubLv9wi4NMH9GGtc", "lastValidBlockHeight": "280957599", "fromAddressRent": "890880", "toAddressRent": "0", "tokenAccountInfo": { "lamports": "2039280", "ownerAddress": "HnRfqMVCpYAvTVRZJJtrR5j2Kx8qvz4HvE3eL4hUgheV", "mintAddress": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", "tokenAccountAddress": "CFYZjn1dVWzbwDq7zuXtwa2NystiqA4QALKqMoA98TB6", "decimal": "6" } } ] } // TRON { "code": "0", "msg": "success", "data": [ { "fee": "3150000", "refBlockBytes": "8cfe", "refBlockHash": "dc8399fedb8cf542", "expiration": "1732088289000", "timestamp": "1732084764202" } ] } ```
- [Gas Price](https://web3.okx.com/onchainos/docs/waas/walletapi-api-gas-price.md) {/* api-page */} # Gas Price Dynamically obtain estimated gas prices for various chains, supporting EIP-1559, and covering EVM and UTXO model networks. ### Request Path GET `https://web3.okx.com/api/v5/wallet/pre-transaction/gas-price` ### Request Parameters | Parameter | Type | Required | Description | |------------|--------|----------|-----------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain | ### Response Parameters #### EVM | Parameter | Type | Description | |------------------|---------|-----------------------------------| | >normal | String | Medium gas price, in wei | | >min | String | Low gas price, in wei | | >max | String | High gas price, in wei | | >supporteip1559 | Boolean | Whether supports 1559 | | >eip1559Protocol | Object | 1559 protocol | ##### eip1559 Protocol | Parameter | Type | Description | |---------------------|--------|--------------------------------------| | eip1559Protocol | Object | Structure of 1559 protocol | | >suggestBaseFee | String | Suggested base fee = base fee * 1.25, in wei | | >baseFee | String | Base fee, in wei | | >proposePriorityFee | String | Medium priority fee, in wei | | >safePriorityFee | String | Low priority fee, in wei | | >fastPriorityFee | String | High priority fee, in wei | #### BRC-20/UTXO | Parameter | Type | Description | |-------------------|--------|--------------------------------------------| | normalFeeRate | String | Medium fee rate | | maxFeeRate | String | High fee rate | | minFeeRate | Object | Low fee rate | | inscriptionOutput | String | Inscription output size | | minOutput | String | Minimum inscription output size, in Satoshi (usually 546 Satoshi) | | normalCost | String | Single inscription transaction cost, in Satoshi | | maxCost | String | Maximum single inscription transaction cost, in Satoshi | | minCost | String | Minimum single inscription transaction cost, in Satoshi | ### Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/wallet/pre-transaction/gas-price?chainIndex=1' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response Example ```json // EVM { "code": "0", "data": [ { "normal" : "21289500000", // Medium gas price "min" : "15670000000", // Low gas price "max" : "29149000000", // High gas price "supportEip1559" : true, // Whether supports 1559 "erc1599Protocol": { "suggestBaseFee" : "15170000000", // Suggested base fee "baseFee" : "15170000000", // Base fee "proposePriorityFee" : "810000000", // Medium priority fee "safePriorityFee" : "500000000", // Low priority fee "fastPriorityFee" : "3360000000" // High priority fee } } ], "msg": "" } // UTXO { "code": "0", "data": [ { "normalFeeRate": "27", "maxFeeRate": "35", "minFeeRate": "22", "inscriptionOutput": "546", "minOutput": "1500", "normalCost": "1800", "maxCost": "3600", "minCost": "600" } ], "msg": "" } ``` - [Gas Limit](https://web3.okx.com/onchainos/docs/waas/walletapi-api-gas-limit.md) {/* api-page */} # Gas Limit Retrieve estimated Gas Limit consumption through pre-execution of transaction information. ### Request Path POST `https://web3.okx.com/api/v5/wallet/pre-transaction/gas-limit` ### Request Parameters | Parameter | Type | Required | Description | |------------|--------|----------|------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain | | fromAddr | String | Yes | From address | | toAddr | String | Yes | To address | | txAmount | String | No | Amount of main chain coins for the transaction. Default is 0. Required for mainnet transfers to calculate gaslimit properly,passed in the smallest unit of the mainnet coin, such as ETH wei. | | extJson | Object | No | Additional parameters for calldata and other information | extJson | Parameter | Type | Required | Description | |-----------|--------|----------|-------------| | inputData | String | No | Calldata | ### Response Parameters | Parameter | Type | Description | |-----------|--------|-------------------| | gasLimit | String | Estimated gas limit | ### Request Example ``` shell curl --location --request POST 'https://web3.okx.com/api/v5/wallet/pre-transaction/gas-limit' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '{ "fromAddr": "0x383c8208b4711256753b70729ba0cf0cda55efad", "toAddr": "0x4ad041bbc6fa102394773c6d8f6d634320773af4", "txAmount": "31600000000000000", "chainIndex": "1", "extJson": { "inputData":"041bbc6fa102394773c6d8f6d634320773af4" } }' ``` ### Response Example ```json { "code": "0", "data": [ { "gasLimit": "652683" } ], "msg": "" } ``` - [Nonce](https://web3.okx.com/onchainos/docs/waas/walletapi-api-nonce.md) {/* api-page */} # Nonce Supports querying Nonce on EVM chains, returning the nonce that is about to be confirmed on-chain and the pending nonce in the memory pool. For example, if the highest confirmed nonce for the current address is 10, and the memory pool has nonce 11 and 12 pending, the returned nonce would be 11, and `pendingNonce` would be 13. ### Request Path GET `https://web3.okx.com/api/v5/wallet/pre-transaction/nonce` ### Request Parameters | Parameter | Type | Required | Description | | ---------- | ------ | -------- | ------------------------- | | chainIndex | String | Yes | Unique identifier for the chain | | address | String | Yes | Address | ### Response Parameters | Parameter | Type | Description | | ------------ | ------ | ------------------------- | | nonce | String | Nonce available for on-chain confirmation | | pendingNonce | String | Pending nonce in the memory pool | ### Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/wallet/pre-transaction/nonce?chainIndex=1&address=0x1ucda' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response Example ```json { "code": "0", "data": [ { "nonce": "15", "pendingNonce": "21" } ], "msg": "success" } ``` - [SUI Object](https://web3.okx.com/onchainos/docs/waas/walletapi-api-sui-object.md) {/* api-page */} # SUI Object Retrieve all objects on the SUI network. ### Request Path POST `https://web3.okx.com/api/v5/wallet/pre-transaction/sui-object` ### Request Parameters | Parameter | Type | Required | Description | |------------|--------|----------|------------------------------------------------------------------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain | | address | String | Yes | Wallet address | | tokenAddress | String | Yes | Token address | | limit | String | No | Number of entries per query, default is 50, maximum is 50 | | cursor | Object | No | Cursor position, defaults to the first entry | ### Response Parameters | Parameter | Type | Description | |-----------|--------|-------------------| | tokenAddress | String| Token address | | objects | Array | Object list | | >amount | String| token balance | | >digest | String| A 32-byte transaction summary indicating the last transaction that included this object as an output| | >version | String| 8-byte unsigned integer version, monotonically increasing with each transaction that modifies it| | >objectId | String| A 32-byte globally unique ID. The object ID is derived from the digest of the transaction that created the object and a counter of the number of IDs generated by the encoding transaction. | | cursor | String| Next cursor| ### Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v5/wallet/pre-transaction/sui-object?chainIndex=784&address=0x935029ca5219502a47ac9b69f556ccf6e2198b5e7815cf50f68846f723739cbd&cursor=0x00b6bbf25a188b36c9307909d99449b95d15e08c3a6f0333814d5bddccff5176' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response Example ```json { "code": "0", "msg": "success", "data": [ { "tokenAddress": "0x2::sui::SUI", "cursor": "0x014f206e9de4bf4fbfc4dcc4bca0e2a8e58ff066beb33f7ff64d6ad5beb48419", "objects": [ { "amount": "10000004114400", "digest": "2izKmAEDZ4dRMPSJaxycRJMuaMVnWBtKSCg24Hx7KwoE", "version": "368758084", "objectId": "0x014e81bf02d343f87fda11814bca88ee775c1721a61dbc1910f18ea5b13a53c2" }, { "amount": "500019226840", "digest": "5sMxZk5MvJDCGxjdT8uCkDbEPXRwyhh8zRWuLzDjqsqJ", "version": "333512928", "objectId": "0x014f206e9de4bf4fbfc4dcc4bca0e2a8e58ff066beb33f7ff64d6ad5beb48419" } ] } ] } ``` - [Address Validation](https://web3.okx.com/onchainos/docs/waas/walletapi-api-validate-address.md) {/* api-page */} # Address Validation Provide an address to determine if it is a valid user or contract address, and whether it has hit blacklist check. ### Request Path GET `https://web3.okx.com/api/v5/wallet/pre-transaction/validate-address` ### Request Parameters | Parameter | Type | Required | Description | |------------|--------|----------|------------------------------------| | chainIndex | String | Yes | Unique identifier for the chain | | address | String | Yes | Address | ### Response Parameters | Parameter | Type | Description | |-----------|--------|-------------------------------------------| | addressType | String | `0`: Invalid address format
`1`: Valid user address
`2`: Valid contract address | | hitBlacklist | Boolean | `false`: Did not hit a blacklisted address
`true`: Hit a blacklisted address | | tag | String | Types of blacklist tags. `Deprecated` |
### Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v5/wallet/validate-address?chainIndex=1&address=0xdf54b6c6195ea4d948d03bfd818d365cf175cfc2&addressType=0' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response Example ```json { "code": "0", "data": [ { "addressType": "1" "hitBlacklist":"true" "tag":"HoneyPot" } ], "msg": "success" } ```
- [Transaction Broadcast](https://web3.okx.com/onchainos/docs/waas/walletapi-api-send-transaction.md) {/* api-page */} # Transaction Broadcast Broadcast transactions to the specified blockchain.
Transaction Broadcast API is available to our enterprise customers only. If you are interested, please contact us: dexapi@okx.com. ### Request Path POST `https://web3.okx.com/api/v5/wallet/pre-transaction/broadcast-transaction` ### Request Parameters | Parameter | Type | Required | Description | |------------ |-------- |----------|------------------------------------------------------------------------| | signedTx | String | Yes | The transaction string after being signed | | chainIndex | String | Yes | Unique identifier for the chain, e.g., ETH=3. For more details, see the chain index list | | address | String | Yes | Address. | | accountId | String | No | Wallet account ID. It can be used later to check the transactions sent from the account | ### Response Parameters | Parameter | Type | Description | |-----------|--------|--------------------| | orderId | String | Unique transaction identifier |
### Request Example ``` shell curl --location --request POST 'https://web3.okx.com/api/v5/wallet/pre-transaction/broadcast-transaction' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \ --data-raw '{ "signedTx":"0x08b47112567534ad041bbc6fa102394773c6d8f6d634320773af4da55efa", "accountId":"44486e05-3235-2f8e-5fe2-a8ab46217863", "address": "0x383c8208b4711256753b70729ba0cf0cda55efad", "chainIndex": "3", }' ``` ### Response Example ```json { "code": "0", "data": [ { "orderId": "0x383c8208b4711256753b70729ba0cf0cda55efad" } ], "msg": "" } ```
- [Transaction Order](https://web3.okx.com/onchainos/docs/waas/walletapi-api-order-id-transaction-list.md) {/* api-page */} # Transaction Order Get the list of orders sent from Transaction API.This supports querying transactions on EVM and UTXO model networks, sorted in descending order by time. ### Request Path GET `https://web3.okx.com/api/v5/wallet/post-transaction/orders` ### Request Parameters | Parameter | Type | Required | Description | |------------ |-------- |----------|----------------------------------------------------| | address | String | No | Query list by address. Either address or account ID is required.If both are provided, the account ID takes precedence. | | accountId | String | No | Query list by account ID. Either address or account ID is required | | chainIndex | String | No | Unique identifier for the chain | | txStatus | String | No | Transaction status:
`1`: Pending
`2`: Success
`3`: Failed | | orderId | String | No | Unique identifier for the transaction order | | cursor | String | No | Cursor | | limit | String | No | Number of records returned, default is the most recent 20, maximum is 100 |
### Response Parameters | Parameter | Type | Description | |------------ |-------- |-----------------------------------------------------| | chainIndex | String | Unique identifier for the chain | | address | String | Address | | accountId | String | Unique identifier for the account | | orderId | String | Order ID | | txStatus | String | Transaction status:
`1`: Pending
`2`: Success
`3`: Failed | | txHash | String | Transaction hash | | limit | String | Number of records returned, default is the most recent 20, maximum is 100 |
### Request Example ``` shell curl --location --request GET 'https://web3.okx.com/api/v5/wallet/post-transaction/orders?accountId=c79e7775-9e78-4a2d-b27f-9021f3bf5fca&chainIndex=1' \ --header 'Content-Type: application/json' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response Example ``` json { "code": "0", "msg": "success", "data": [ { "chainIndex": "1", "accountId": "c79e7775-9e78-4a2d-b27f-9021f3bf5fca", "orderId": "016cf21d020be6c2f071dad9bbd8ec5cb9342fa8", "address": "0x238193be9e80e68eace3588b45d8cf4a7eae0fa3", "txHash": "0xb240e65dd9156b4a450be72f6c9fe41be6f72397025bb465b21a96ee9871a589", "txstatus": "2" }, { "chainIndex": "1", "accountId": "c79e7775-9e78-4a2d-b27f-9021f3bf5fca", "orderId": "592051a92a744627022955be929ecb5c9e777705", "address": "0x238193be9e80e68eace3588b45d8cf4a7eae0fa3", "txHash": "0xc401ffcd2a2b4b1db42ce68dfde8e63c0a1e9653484efb2873dbf5d0cbeb227a", "txstatus": "1" } ] } ```
--- - [Signing SDK](https://web3.okx.com/onchainos/docs/waas/wallet-client-sdk.md) # Signing SDK - [Javascript Signing SDK](https://web3.okx.com/onchainos/docs/waas/private-key-wallet-javascript-sdk.md) # Javascript Signing SDK ## Overview Js-wallet-sdk is a wallet solution based on TypeScript/JavaScript language that includes various public chains' different cryptographic algorithms and common functionalities. You can use it for creating private keys, addresses, assembling transactions, and performing signatures, among other things. This document will provide a detailed guide on how to use this SDK. Currently, it supports various mainstream blockchains, with each token format having its own independent module implementation. We will continue to add support for more blockchains in the future. ### Supported platforms As a Javascript SDK, it supports various browsers and JavaScript environments, and can be easily integrated into Web applications, mobile applications, or desktop applications. ## Installation and building ### NPM building To use the Signing SDK, you first need to install it. You can use npm install to get the latest version. Our Signing SDK supports two types of packages: public packages and single coin modules. Public packages are for all currencies: ```bash npm install @okxweb3/crypto-lib npm install @okxweb3/coin-base ``` Integration of individual currencies, taking ETH and BTC as examples: Integration of ETH: ```bash npm install @okxweb3/coin-ethereum ``` Integration of BTC: ```bash npm install @okxweb3/coin-bitcoin ``` ### Local building To build the SDK locally: 1) Download the project source code ```bash git clone https://github.com/okx/js-wallet-sdk.git ``` 2) Run the build script ```bash sh build.sh ``` ## Main features Here is a specific introduction to the functions of each module in the Signing SDK. - crypto-lib: This module provides commonly used security encryption algorithms and signature algorithms, etc. - coin-base: This module provides a common interface for coins. - coin-*: This module implements methods for building and signing transactions for each coin. Each coin has a corresponding module, such as coin-ethereum, coin-bitcoin, etc. These modules provide transaction building and signing methods for specific coins. ## Packages | Package name | Module | Description | | --- | --- | --- | | [@okxweb3/coin-base](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-base/README.md) | coin-base | We provide common functions for these chains or currencies, making access to these chains very simple. | | [@okxweb3/crypto-lib](https://github.com/okx/js-wallet-sdk/blob/main/packages/crypto-lib/README.md) | crypto-lib | We provide common functions about bip32, bip39, ecdsa, ed25519, etc. | | [@okxweb3/coin-aptos](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-aptos/README.md) | coin-aptos | Aptos SDK is used to interact with the Aptos blockchain, containing various functions that can be used for web3 wallets. | | [@okxweb3/coin-bitcoin](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-bitcoin/README.md) | coin-bitcoin | Bitcoin SDK is used to interact with the Bitcoin mainnet or testnet, containing various functions that can be used for web3 wallets. The SDK not only supports Bitcoin, but also supports the following chains: BTC, BSV, DOGE, LTC, TBTC. | | [@okxweb3/coin-cosmos](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-cosmos/README.md) | coin-cosmos | Cosmos SDK is used to interact with the Cosmos blockchain, containing various functions that can be used for web3 wallets. | | [@okxweb3/coin-eos](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-eos/README.md) | coin-eos | EOS SDK is used to interact with the EOS blockchain, containing various functions that can be used for web3 wallets. The SDK not only supports EOS, but also supports WAX. | | [@okxweb3/coin-ethereum](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-ethereum/README.md) | coin-ethereum | Ethereum SDK is used to interact with the Ethereum blockchain or Evm blockchain, containing various functions that can be used for web3 wallets. | | [@okxweb3/coin-flow](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-flow/README.md) | coin-flow | Flow SDK is used to interact with the Flow blockchain, containing various functions that can be used for web3 wallets. | | [@okxweb3/coin-near](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-near/README.md) | coin-near | Near SDK is used to interact with the Near Protocol, containing the main functions needed when interacting with the Near ecosystem. | | [@okxweb3/coin-polkadot](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-polkadot/README.md) | coin-polkadot | Polkadot SDK is used to interact with the Polkadot blockchain, containing the main functions needed when interacting with the Polkadot ecosystem. | | [@okxweb3/coin-solana](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-solana/README.md) | coin-solana | Solana SDK is used to interact with the Solana chain, containing the main functions needed when interacting with the Solana ecosystem. | | [@okxweb3/coin-stacks](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-stacks/README.md) | coin-stacks | Stacks SDK is used to interact with the Stacks blockchain, containing various functions that can be used for web3 wallets. | | [@okxweb3/coin-starknet](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-starknet/README.md) | coin-starknet | Starknet SDK is used to interact with the Starknet blockchain, containing various functions that can be used for web3 wallets. | | [@okxweb3/coin-sui](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-sui/README.md) | coin-sui | SUI SDK is used to interact with the SUI blockchain, containing various functions that can be used for web3 wallets. | | [@okxweb3/coin-tron](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-tron/README.md) | coin-tron | TRX SDK is used to interact with the TRON blockchain, containing various functions that can be used for web3 wallets. | | [@okxweb3/coin-zkspace](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-zkspace/README.md) | coin-zkspace | ZKSpace SDK is used to interact with ZK contracts, containing various functions that can be used for web3 wallets. The SDK not only supports ZKSpace, but also supports zkSync. | ### coin-base The base package is the common basic module for all currencies, providing common interface method definitions, such as: random private key generation, private key derivation, obtaining derivation paths, etc. At present, the implementation packages of individual currencies have basically implemented common interface methods, but the functions supported by different currencies may vary slightly. For more details, you can refer to the function descriptions of each coin implementation package. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-base ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | validPrivateKey | Validate a private key | | | signMessage | Sign a message | | | verifyMessage | Verify a signed message | | | ecRecover | Recover a signature to a public key | | | getAddressByPublicKey | Get an address through a public key | | | getHardWareRawTransaction | Get the raw transaction of the hardware | | | getHardWareSignedTransaction | Get the signed transaction of the hardware | | | getHardWareMessageHash | Get the message hash of the hardware | | | calcTxHash | Get a transaction hash through a raw transaction | | | getRawTransaction | Generate raw transaction data | | | validSignedTransaction | Check a signed transaction | | | estimateFee | Estimate gas fees | | For more detailed information about the functions supported by the coin-base package and use cases, you can view the github document for more detailed content: [coin-base function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-base/README.md#supporting-functions). ### crypto-lib This is a library that includes implementations of commonly used security encryption and signature algorithms such as bip32, bip39, ecdsa, ed25519, etc. For example: - Common bip32 functions: These functions are mainly used to handle and operate tasks related to the Bitcoin Improvement Payment Protocol (BIP32). - bip39 mnemonic generation, public/private key, and message signing functions: These functions are mainly used to handle and operate tasks related to the Bitcoin Improvement Payment Protocol (BIP39), such as generating mnemonics, public/private keys, and signing messages. - Common hash and encoding/decoding functions: These functions are mainly used to handle common hash and encoding/decoding tasks, such as SHA256 hashing, Base64 encoding/decoding, etc. - Common ed5519 signature functions: These functions are mainly used to handle and operate tasks related to the ed5519 signature algorithm. - Common ecdsa signature functions: These functions are mainly used to handle and operate tasks related to the Elliptic Curve Digital Signature Algorithm (ECDSA). To get the latest version of the package via npm: ```bash npm install @okxweb3/crypto-lib ``` For more detailed information about the functions supported by the crypto-lib package and use cases, you can view the github document for more detailed content: [crypto-lib function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/crypto-lib/README.md#provides). ### coin-aptos Aptos SDK is mainly used to integrate Aptos blockchain, containing functions such as private key generation, private key derivation, address generation, and transaction transfer. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-aptos ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | signMessage | Sign a message | | | verifyMessage | Verify a signed message | | | calcTxHash | Get a transaction hash through a raw transaction | | | validSignedTransaction | Check a signed transaction | | Aptos transaction support types are: "transfer", "tokenTransfer", "tokenMint", "tokenBurn", "tokenRegister", "dapp", "simulate", "offerNft", "claimNft", "offerNft_simulate", "claimNft_simulate" For more detailed information about the functions supported by the coin-aptos package and use cases, you can view the github document for more detailed content: [coin-aptos function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-aptos/README.md#usage). ### coin-bitcoin coin-bitcoin is an SDK for integrating Bitcoin blockchain. It supports both the Bitcoin mainnet and testnet, and provides a series of functional methods, making it easier for developers to interact with the Bitcoin blockchain. In addition to BTC, it also supports other cryptocurrencies such as BSV, DOGE, LTC, and TBTC. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-bitcoin ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | signMessage | Sign a message | | | verifyMessage | Verify a signed message | | | calcTxHash | Get a transaction hash through a raw transaction | | | validSignedTransaction | Check a signed transaction | | | getAddressByPublicKey | Get an address through a public key | | For more detailed information about the functions supported by the coin-bitcoin package and use cases, you can view the github document for more detailed content: [coin-bitcoin function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-bitcoin/README.md#using-bitcoin-sdk). ### coin-cosmos Cosmos SDK is a toolkit for integrating with the Cosmos blockchain, providing a series of functional methods, including generating private keys, deriving private keys, generating addresses, and transferring transactions. It supports currencies including: - Atom - Axelar - Cronos - Evmos - Iris - Juno - Kava - Kujira - Osmos - Secret - Sei - Stargaze - Terra To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-cosmos ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | signMessage | Sign a message | | | verifyMessage | Verify a signed message | | | calcTxHash | Get a transaction hash through a raw transaction | | | validSignedTransaction | Check a signed transaction | | | getAddressByPublicKey | Get an address through a public key | | For more detailed information about the functions supported by the coin-cosmos package and use cases, you can view the github document for more detailed content: [coin-cosmos function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-cosmos/README.md#using-cosmos-sdk). ### coin-eos EOS SDK is a toolkit for integrating with the EOS blockchain. It provides a series of functional methods, including generating private keys, deriving private keys, generating addresses, and transaction serialization. In addition to EOS, it also supports the Wax coin. These functional methods make it easier for developers to interact with the EOS blockchain, including creating and managing wallets, sending and receiving transactions, and querying blockchain information. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-eos ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | calcTxHash | Get a transaction hash through a raw transaction | | For more detailed information about the functions supported by the coin-eos package and use cases, you can view the github document for more detailed content: [coin-eos function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-eos/README.md#using-eos-sdk). ### coin-ethereum Ethereum SDK is a toolkit for integrating with the Ethereum blockchain and other blockchains that support EVM (Ethereum Virtual Machine). It provides a series of functional methods, including generating private keys, deriving private keys, generating addresses, and transferring transactions. These functional methods make it easier for developers to interact with the Ethereum blockchain, including creating and managing wallets, sending and receiving transactions, and querying blockchain information. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-ethereum ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | validPrivateKey | Validate a private key | | | signMessage | Sign a message | | | verifyMessage | Verify a signed message | | | ecRecover | Recover a signature to a public key | | | getAddressByPublicKey | Get an address through a public key | | | getHardWareRawTransaction | Get the raw transaction of the hardware | | | getHardWareSignedTransaction | Get the signed transaction of the hardware | | | getHardWareMessageHash | Get the message hash of the hardware | | | calcTxHash | Get a transaction hash through a raw transaction | | | getRawTransaction | Generate raw transaction data | | | validSignedTransaction | Check a signed transaction | | For more detailed information about the functions supported by the coin-ethereum package and use cases, you can view the github document for more detailed content: [coin-ethereum function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-ethereum/README.md#using-ethereum-sdk). ### coin-flow Flow blockchain is a next-generation, future-oriented blockchain platform, specifically designed for high-performance applications and games. Flow SDK is a toolkit for integrating with the Flow blockchain. It provides a series of functional methods, enabling developers to interact more conveniently with the Flow blockchain. The specific functionalities offered by the SDK can facilitate the development of applications on the Flow blockchain. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-flow ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | validateAddress | Validate an address | | | signTransaction | Sign a transaction | | Flow supports two types of transactions: Account and Transfer. For more detailed information about the functions supported by the coin-flow package and use cases, you can view the github document for more detailed content: [coin-flow function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-flow/README.md#using-flow-sdk). ### coin-near Near Protocol is a scalable blockchain platform that achieves high throughput and low latency transaction processing by using a novel consensus mechanism and sharding technology. Near SDK allows developers to interact more conveniently with the Near blockchain. Near SDK is a toolkit for integrating with the Near Protocol, containing the main functions needed when interacting with the Near ecosystem. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-near ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getAddress | Get an address through a seed | | | validateAddress | Validate an address | | | signTransaction | Sign a transaction | | | transfer | Transfer a coin | | | fullAccessKey | Get a full access key | | | publicKeyFromSeed | Get a public key from a seed | | For more detailed information about the functions supported by the coin-near package and use cases, you can view the github document for more detailed content: [coin-near function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-near/README.md#using-near-sdk). ### coin-polkadot Polkadot is a multi-chain heterogeneous blockchain platform, which allows various blockchain networks to run in parallel with a shared security model, and can also realize seamless transfer of information and value between chains. Polkadot SDK is a toolkit for integrating with the Polkadot blockchain, containing the main functions needed when interacting with the Polkadot ecosystem. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-polkadot ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getAddress | Get an address through a seed | | | validateAddress | Validate an address | | | SignTx | Sign a transaction | | For more detailed information about the functions supported by the coin-polkadot package and use cases, you can view the github document for more detailed content: [coin-polkadot function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-polkadot/README.md#using-polkadot-sdk). ### coin-solana Solana is a high-performance blockchain platform that achieves high throughput and low latency transaction processing through an innovative consensus algorithm and block generation mechanism. Solana SDK is a toolkit for integrating the Solana blockchain, containing the main functions needed when interacting with the Solana ecosystem. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-solana ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | signMessage | Sign a message | | | calcTxHash | Get a transaction hash through a raw transaction | | | validSignedTransaction | Check a signed transaction | | | getHardWareRawTransaction | Get the raw transaction of the hardware | | | getHardWareSignedTransaction | Get the signed transaction of the hardware | | | getHardWareMessageHash | Get the message hash of the hardware | | For more detailed information about the functions supported by the coin-solana package and use cases, you can view the github document for more detailed content: [coin-solana function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-solana/README.md#using-solana-sdk). ### coin-stacks Stacks is an open-source blockchain platform that allows developers to build smart contracts and decentralized applications on the Stacks blockchain. Stacks SDK is mainly used to integrate Stacks blockchain, containing various functions that can be used for web3 wallets. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-stacks ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | signMessage | Sign a message | | | verifyMessage | Verify a signed message | | | calcTxHash | Get a transaction hash through a raw transaction | | | getRawTransaction | Get a raw transaction | | For more detailed information about the functions supported by the coin-stacks package and use cases, you can view the github document for more detailed content: [coin-stacks function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-stacks/README.md#using-stacks-sdk). ### coin-starknet StarkNet is a decentralized, scalable blockchain network that uses zero-knowledge proof technology to enhance the efficiency and security of transaction processing. StarkNet SDK is a toolkit for integrating the StarkNet blockchain, providing a series of functional methods that make it easier for developers to interact with the StarkNet blockchain. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-starknet ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | signMessage | Sign a message | | | verifyMessage | Verify a signed message | | For more detailed information about the functions supported by the coin-starknet package and use cases, you can view the github document for more detailed content: [coin-starknet function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-starknet/README.md#using-starknet-sdk). ### coin-sui SUI SDK is a toolkit for integrating the SUI blockchain, containing various functions that can be used for web3 wallets. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-sui ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | signMessage | Sign a message | | | calcTxHash | Get a transaction hash through a raw transaction | | Note: Unlike secp256k1, ed25519 only supports hard mode derivation for private keys. For more details, refer to: https://github.com/satoshilabs/slips/blob/master/slip-0010.md For more detailed information about the functions supported by the coin-sui package and use cases, you can view the github document for more detailed content: [coin-sui function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-sui/README.md#usage). ### coin-tron TRON SDK is a toolkit for integrating the TRON blockchain, containing various functions that can be used for web3 wallets. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-tron ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | validPrivateKey | Validate a private key | | | signMessage | Sign a message | | | verifyMessage | Verify a signed message | | | ecRecover | Recover a signature to a public key | | | getAddressByPublicKey | Get an address through a public key | | | getHardWareRawTransaction | Get the raw transaction of the hardware | | | getHardWareSignedTransaction | Get the signed transaction of the hardware | | | getHardWareMessageHash | Get the message hash of the hardware | | | calcTxHash | Get a transaction hash through a raw transaction | | | getRawTransaction | Generate raw transaction data | | | validSignedTransaction | Check a signed transaction | | For more detailed information about the functions supported by the coin-tron package and use cases, you can view the github document for more detailed content: [coin-tron function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-tron/README.md#using-trx-sdk). ### coin-zkspace ZKSpace SDK is mainly used to integrate ZK contracts, containing various functions that can be used for web3 wallets. In addition to ZKSpace, it also supports zkSync. To get the latest version of the package via npm: ```bash npm install @okxweb3/coin-zkspace ``` Supported functions: | Function name | Functionality | Remarks | | --- | --- | --- | | getRandomPrivateKey | Generate a random private key | | | getDerivedPrivateKey | Generate a private key from DerivePriKeyParams | | | getNewAddress | Get a new address through a private key | | | validAddress | Validate an address | | | signTransaction | Sign a transaction | | | getDerivedPath | Get a bip44 path | | | validPrivateKey | Validate a private key | | | signMessage | Sign a message | | | verifyMessage | Verify a signed message | | | ecRecover | Recover a signature to a public key | | | getAddressByPublicKey | Get an address through a public key | | | getHardWareRawTransaction | Get the raw transaction of the hardware | | | getHardWareSignedTransaction | Get the signed transaction of the hardware | | | getHardWareMessageHash | Get the message hash of the hardware | | | calcTxHash | Get a transaction hash through a raw transaction | | | getRawTransaction | Generate raw transaction data | | The transaction signature supports data types including: transfer and changePubkey. For more detailed information about the functions supported by the coin-zkspace package and use cases, you can view the github document for more detailed content: [coin-zkspace function functions](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-zkspace/README.md#using-zkspace-sdk). ## Test cases On github, there is a `tests` directory under the package corresponding to each module, which contains test cases for various coin modules. You can learn more about the usage of functions in the SDK through these test cases. | Coin family | Test case | Remarks | | --- | --- | --- | | BTC | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-bitcoin/tests/btc.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-bitcoin/tests/btc.test.ts) | | | ETH | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-ethereum/tests/eth.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-ethereum/tests/eth.test.ts) | | | Cosmos | [https://github.com/okx/js-wallet-sdk/tree/main/packages/coin-cosmos/tests](https://github.com/okx/js-wallet-sdk/tree/main/packages/coin-cosmos/tests) | | | Aptos | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-aptos/tests/aptos.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-aptos/tests/aptos.test.ts) | | | EOS | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-eos/tests/eos.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-eos/tests/eos.test.ts) | | | Solana | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-solana/tests/sol.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-solana/tests/sol.test.ts) | | | Stacks | [https://github.com/okx/js-wallet-sdk/tree/main/packages/coin-stacks/tests](https://github.com/okx/js-wallet-sdk/tree/main/packages/coin-stacks/tests) | | | Starknet | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-starknet/tests/crypto.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-starknet/tests/crypto.test.ts) | | | SUI | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-sui/tests/crypto.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-sui/tests/crypto.test.ts) | | | TRON | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-tron/tests/trx.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-tron/tests/trx.test.ts) | | | Zkspace | [https://github.com/okx/js-wallet-sdk/tree/main/packages/coin-zkspace/tests](https://github.com/okx/js-wallet-sdk/tree/main/packages/coin-zkspace/tests) | | | Flow | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-flow/tests/flow.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-flow/tests/flow.test.ts) | | | Near | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-near/tests/near.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-near/tests/near.test.ts) | | | Polkadot | [https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-polkadot/tests/dot.test.ts](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-polkadot/tests/dot.test.ts) | | ## Supported coins | Coin family | Coin | Derivation path | | --- | --- | --- | | BTC | BTC | Regular address:
m/44'/0'/0/0'/0
SegWit:
m/49'/0'/0/0'/0
m/84'/0'/0/0'/0
m/86'/0'/0/0'/0 | | BTC | BCH | m/44'/145'/0'/0/0 | | BTC | BSV | m/44'/236'/0'/0/0 | | BTC | LTC | m/44'/2'/0'/0/0 | | BTC | Doge | m/44'/3'/0'/0/0 | | BTC | TBTC | m/44'/0'/0/0'/0 | | BTC | Omni USDT | m/44'/0'/0/0'/0 | | ETH | ETH | m/44'/60'/0'/0/0 | | ETH | Arbitrum One | m/44'/60'/0'/0/0 | | ETH | Arbitrum Nova | m/44'/60'/0'/0/0 | | ETH | Avalanche C | m/44'/60'/0'/0/0 | | ETH | Boba | m/44'/60'/0'/0/0 | | ETH | BNB Chain | m/44'/60'/0'/0/0 | | ETH | Base | m/44'/60'/0'/0/0 | | ETH | Core | m/44'/60'/0'/0/0 | ETH | Cronos(EVM) | m/44'/60'/0'/0/0 | | ETH | Celo | m/44'/60'/0'/0/0 | | ETH | Conflux(EVM) | m/44'/60'/0'/0/0 | | ETH | Endurance | m/44'/60'/0'/0/0 | | ETH | EthereumPoW | m/44'/60'/0'/0/0 | | ETH | EthereumFair | m/44'/60'/0'/0/0 | | ETH | Filecoin EVM | m/44'/60'/0'/0/0 | | ETH | Fantom | m/44'/60'/0'/0/0 | | ETH | Flare | m/44'/60'/0'/0/0 | | ETH | Gnosis | m/44'/60'/0'/0/0 | | ETH | Goerli | m/44'/60'/0'/0/0 | | ETH | HAQQ Network | m/44'/60'/0'/0/0 | | ETH | Klaytn | m/44'/60'/0'/0/0 | | ETH | KCC | m/44'/60'/0'/0/0 | | ETH | Kava EVM | m/44'/60'/0'/0/0 | | ETH | Linea | m/44'/60'/0'/0/0 | | ETH | Metis | m/44'/60'/0'/0/0 | | ETH | Moonebeam | m/44'/60'/0'/0/0 | | ETH | Moonriver | m/44'/60'/0'/0/0 | | ETH | Mantle | m/44'/60'/0'/0/0 | | ETH | Omega Network | m/44'/60'/0'/0/0 | | ETH | OKTC | m/44'/60'/0'/0/0 | | ETH | Optimism | m/44'/60'/0'/0/0 | | ETH | opBNB | m/44'/60'/0'/0/0 | | ETH | Polygon | m/44'/60'/0'/0/0 | | ETH | Polygon zkEVM | m/44'/60'/0'/0/0 | | ETH | PulseChain | m/44'/60'/0'/0/0 | | ETH | Sepolia | m/44'/60'/0'/0/0 | | ETH | zkSync Era | m/44'/60'/0'/0/0 | | ETH | ZetaChian | m/44'/60'/0'/0/0 | | Cosmos | Atom | m/44'/118'/0'/0/0 | | Cosmos | Axelar | m/44'/118'/0'/0/0 | | Cosmos | Cronos | m/44'/394'/0'/0/0 | | Cosmos | Osmos | m/44'/118'/0'/0/0 | | Cosmos | Evmos | m/44'/60'/0'/0/0 | | Cosmos | Iris | m/44'/118'/0'/0/0 | | Cosmos | Juno | m/44'/118'/0'/0/0 | | Cosmos | Kava | m/44'/459'/0'/0/0 | | Cosmos | Kujira | m/44'/118'/0'/0/0 | | Cosmos | Secret | m/44'/529'/0'/0/0 | | Cosmos | Sei | m/44'/118'/0'/0/0 | | Cosmos | Stargaze | m/44'/118'/0'/0/0 | | Cosmos | Terra | m/44'/330'/0'/0/0 | | Aptos | Aptos | m/44'/637'/0'/0/0 | | EOS | EOS | m/44'/194'/0'/0/0 | | Solana | Solana | m/44'/501'/0'/0/0 | | Stacks | Stacks | m/44'/5757'/0'/0/0 | | ETH lay2 | Starknet | m/44'/9004'/0'/0/0 | | SUI | SUI | m/44'/784'/0'/0/0 | | TRX | TROM | m/44'/195'/0'/0/0 | | ETH lay2 | ZKSpace | m/44'/60'/0'/0/0 | | ETH lay2 | zkSync | m/44'/60'/0'/0/0 | - [Go Signing SDK](https://web3.okx.com/onchainos/docs/waas/private-key-wallet-go-sdk.md) # Go Signing SDK ## Overview Go-wallet-sdk is a wallet solution based on Go language that includes various public chains' different cryptographic algorithms and common functionalities. You can use it for creating private keys, addresses, assembling transactions, and performing signatures, among other things. This document will provide a detailed guide on how to use this SDK. Currently, it supports various mainstream blockchains, with each token format having its own independent module implementation. We will continue to add support for more blockchains in the future. ### Supported platforms As a Go SDK, it can be easily integrated into Web applications, mobile applications, or desktop applications. ## Installation and building ### Go GET To use the Signing SDK, you first need to install it. You can use `go get` to get the latest version. Our Signing SDK supports two types of packages: public packages and single coin modules. Public packages are for all currencies: ```bash go get -u github.com/okx/go-wallet-sdk/crypto ``` Integration of individual currencies, taking ETH and BTC as examples: Integration of ETH: ```bash go get -u github.com/okx/go-wallet-sdk/coins/ethereum ``` Integration of BTC: ```bash go get -u github.com/okx/go-wallet-sdk/coins/bitcoin ``` ## Main features Here is a specific introduction to the functions of each module in the Signing SDK. - crypto: This module provides commonly used security encryption algorithms and signature algorithms, etc. - coins: This module implements methods for building and signing transactions for each coin. Each coin has a corresponding module, such as ethereum, bitcoin, etc. These modules provide transaction building and signing methods for specific coins. ## Packages | Package name | Module | Description | | --- | --- | --- | | [github.com/okx/go-wallet-sdk/crypto](https://github.com/okx/go-wallet-sdk/tree/main/crypto) | crypto | We provide common functions about bip32, bip39, ecdsa, ed25519, etc. | | [github.com/okx/go-wallet-sdk/coins/aptos](https://github.com/okx/go-wallet-sdk/tree/main/coins/aptos) | aptos | Aptos SDK is used to interact with the Aptos blockchain, containing various functions that can be used for web3 wallets. | | [github.com/okx/go-wallet-sdk/coins/bitcoin](https://github.com/okx/go-wallet-sdk/tree/main/coins/bitcoin) | bitcoin | Bitcoin SDK is used to interact with the Bitcoin mainnet or testnet, containing various functions that can be used for web3 wallets. The SDK not only supports Bitcoin, but also supports the following chains: BTC, BSV, DOGE, LTC, TBTC. | | [github.com/okx/go-wallet-sdk/coins/cosmos](https://github.com/okx/go-wallet-sdk/tree/main/coins/cosmos) | cosmos | Cosmos SDK is used to interact with the Cosmos blockchain, containing various functions that can be used for web3 wallets. | | [github.com/okx/go-wallet-sdk/coins/eos](https://github.com/okx/go-wallet-sdk/tree/main/coins/eos) | eos | EOS SDK is used to interact with the EOS blockchain, containing various functions that can be used for web3 wallets. The SDK not only supports EOS, but also supports WAX. | | [github.com/okx/go-wallet-sdk/coins/ethereum](https://github.com/okx/go-wallet-sdk/tree/main/coins/ethereum) | ethereum | Ethereum SDK is used to interact with the Ethereum blockchain or Evm blockchain, containing various functions that can be used for web3 wallets. | | [github.com/okx/go-wallet-sdk/coins/flow](https://github.com/okx/go-wallet-sdk/tree/main/coins/flow) | flow | Flow SDK is used to interact with the Flow blockchain, containing various functions that can be used for web3 wallets. | | [github.com/okx/go-wallet-sdk/coins/near](https://github.com/okx/go-wallet-sdk/tree/main/coins/near) | near | Near SDK is used to interact with the Near Protocol, containing the main functions needed when interacting with the Near ecosystem. | | [github.com/okx/go-wallet-sdk/coins/polkadot](https://github.com/okx/go-wallet-sdk/tree/main/coins/polkadot) | polkadot | Polkadot SDK is used to interact with the Polkadot blockchain, containing the main functions needed when interacting with the Polkadot ecosystem. | | [github.com/okx/go-wallet-sdk/coins/solana](https://github.com/okx/go-wallet-sdk/tree/main/coins/solana) | solana | Solana SDK is used to interact with the Solana chain, containing the main functions needed when interacting with the Solana ecosystem. | | [github.com/okx/go-wallet-sdk/coins/stacks](https://github.com/okx/go-wallet-sdk/tree/main/coins/stacks) | stacks | Stacks SDK is used to interact with the Stacks blockchain, containing various functions that can be used for web3 wallets. | | [github.com/okx/go-wallet-sdk/coins/starknet](https://github.com/okx/go-wallet-sdk/tree/main/coins/starknet) | starknet | Starknet SDK is used to interact with the Starknet blockchain, containing various functions that can be used for web3 wallets. | | [github.com/okx/go-wallet-sdk/coins/sui](https://github.com/okx/go-wallet-sdk/tree/main/coins/sui) | sui | SUI SDK is used to interact with the SUI blockchain, containing various functions that can be used for web3 wallets. | | [github.com/okx/go-wallet-sdk/coins/tron](https://github.com/okx/go-wallet-sdk/tree/main/coins/tron) | tron | TRX SDK is used to interact with the TRON blockchain, containing various functions that can be used for web3 wallets. | | [github.com/okx/go-wallet-sdk/coins/zkspace](https://github.com/okx/go-wallet-sdk/tree/main/coins/zkspace) | zkspace | ZKSpace SDK is used to interact with ZK contracts, containing various functions that can be used for web3 wallets. The SDK not only supports ZKSpace, but also supports zkSync. | ### crypto This is a library that includes implementations of commonly used security encryption and signature algorithms such as BIP32, BIP39, ECDSA, ED25519, etc. For example: - Common BIP32 functions: These functions are mainly used to handle and operate tasks related to the Bitcoin Improvement Payment Protocol (BIP32). - BIP39 mnemonic generation, public/private key, and message signing functions: These functions are mainly used to handle and operate tasks related to the Bitcoin Improvement Payment Protocol (BIP39), such as generating mnemonics, public/private keys, and signing messages. - Common hash and encoding/decoding functions: These functions are mainly used to handle common hash and encoding/decoding tasks, such as SHA256 hashing, Base64 encoding/decoding, etc. - Common ED25519 signature functions: These functions are mainly used to handle and operate tasks related to the ED25519 signature algorithm. - Common ECDSA signature functions: These functions are mainly used to handle and operate tasks related to the Elliptic Curve Digital Signature Algorithm (ECDSA). To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/crypto ``` ### aptos-sdk Aptos SDK is mainly used to integrate Aptos blockchain, containing functions such as private key generation, private key derivation, address generation, and transaction transfer. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/aptos ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Generate a new address from a private key | | ValidateAddress | Validate an address | | SignRawTransaction | Sign a transaction | Aptos transaction support types are: "transfer", "tokenTransfer", "tokenMint", "tokenBurn", "tokenRegister", "dapp", "simulate", "offerNft", "claimNft", "offerNft_simulate", "claimNft_simulate" For more detailed information about the functions supported by the aptos-sdk package and use cases, you can view the github document for more detailed content: [coin-aptos function functions](https://github.com/okx/go-wallet-sdk/blob/main/coins/aptos/). ### bitcoin-sdk coin-bitcoin is an SDK for integrating the Bitcoin blockchain. It supports both the Bitcoin mainnet and testnet, and provides a series of functional methods, making it easier for developers to interact with the Bitcoin blockchain. In addition to BTC, it also supports other cryptocurrencies such as BSV, DOGE, LTC, and TBTC. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/bitcoin ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get a new address through a private key | | SignTx | Sign a transaction | | GenerateUnsignedPSBTHex | Generate a PSBT transaction | For more detailed information about the functions supported by the bitcoin-sdk package and use cases, you can view the github document for more detailed content: [coin-bitcoin function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/bitcoin). ### cosmos-sdk Cosmos SDK is a toolkit for integrating with the Cosmos blockchain, providing a series of functional methods, including generating private keys, deriving private keys, generating addresses, and transferring transactions. It supports currencies including: - Atom - Axelar - Cronos - Evmos - Iris - Juno - Kava - Kujira - Osmos - Secret - Sei - Stargaze - Terra To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/cosmos ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get a new address through a private key | | Transfer | Sign a transaction | | SignMessage | Sign a message | For more detailed information about the functions supported by the cosmos-sdk package and use cases, you can view the github document for more detailed content: [coin-cosmos function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/cosmos). ### eos-sdk EOS SDK is a toolkit for integrating with the EOS blockchain. It provides a series of functional methods, including generating private keys, deriving private keys, generating addresses, and transaction serialization. In addition to EOS, it also supports the Wax coin. These functional methods make it easier for developers to interact with the EOS blockchain, including creating and managing wallets, sending and receiving transactions, and querying blockchain information. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/eos ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get a new address through a private key | | SignTransaction | Sign a transaction | For more detailed information about the functions supported by the eos-sdk package and use cases, you can view the github document for more detailed content: [coin-eos function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/eos). ### ethereum-sdk Ethereum SDK is a toolkit for integrating with the Ethereum blockchain and other blockchains that support EVM (Ethereum Virtual Machine). It provides a series of functional methods, including generating private keys, deriving private keys, generating addresses, and transferring transactions. These functional methods make it easier for developers to interact with the Ethereum blockchain, including creating and managing wallets, sending and receiving transactions, and querying blockchain information. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/ethereum ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get a new address through a private key | | SignTransaction | Sign a transaction | | SignMessage | Sign a message | For more detailed information about the functions supported by the coin-ethereum package and use cases, you can view the github document for more detailed content: [coin-ethereum function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/ethereum). ### flow-sdk Flow blockchain is a next-generation, future-oriented blockchain platform, specifically designed for high-performance applications and games. Flow SDK is a toolkit for integrating with the Flow blockchain. It provides a series of functional methods, enabling developers to interact more conveniently with the Flow blockchain. The specific functionalities offered by the SDK can facilitate the development of applications on the Flow blockchain. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/flow ``` Supported functions: | Function name | Functionality | | --- | --- | | CreateNewAccountTx | Create a new account | | SignTx | Sign a transaction | Flow supports two types of transactions: Account and Transfer. For more detailed information about the functions supported by the coin-flow package and use cases, you can view the github document for more detailed content: [coin-flow function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/flow). ### near-sdk Near Protocol is a scalable blockchain platform that achieves high throughput and low latency transaction processing by using a novel consensus mechanism and sharding technology. Near SDK allows developers to interact more conveniently with the Near blockchain. Near SDK is a toolkit for integrating with the Near Protocol, containing the main functions needed when interacting with the Near ecosystem. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/near ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAccount | Get an address through a seed | | SignTransaction | Sign a transaction | | Transfer | Transfer a coin | | FullAccessKey | Get a full access key | | PublicKeyFromSeed | Get a public key from a seed | For more detailed information about the functions supported by the near-sdk package and use cases, you can view the github document for more detailed content: [coin-near function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/near). ### polkadot-sdk Polkadot is a multi-chain heterogeneous blockchain platform, which allows various blockchain networks to run in parallel with a shared security model, and can also realize seamless transfer of information and value between chains. Polkadot SDK is a toolkit for integrating with the Polkadot blockchain, containing the main functions needed when interacting with the Polkadot ecosystem. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/polkadot ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get an address through a seed | | SignTx | Sign a transaction | For more detailed information about the functions supported by the polkadot-sdk package and use cases, you can view the github document for more detailed content: [coin-polkadot function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/polkadot). ### solana-sdk Solana is a high-performance blockchain platform that achieves high throughput and low latency transaction processing through an innovative consensus algorithm and block generation mechanism. Solana SDK is a toolkit for integrating the Solana blockchain, containing the main functions needed when interacting with the Solana ecosystem. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/solana ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get a new address through a private key | | SignTransaction | Sign a transaction | For more detailed information about the functions supported by the solana-sdk package and use cases, you can view the github document for more detailed content: [coin-solana function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/solana). ### stacks-sdk Stacks is an open-source blockchain platform that allows developers to build smart contracts and decentralized applications on the Stacks blockchain. Stacks SDK is mainly used to integrate Stacks blockchain, containing various functions that can be used for web3 wallets. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/stacks ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get a new address through a private key | | Transfer | Sign a transaction | For more detailed information about the functions supported by the stacks-sdk package and use cases, you can view the github document for more detailed content: [coin-stacks function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/stacks). ### starknet-sdk StarkNet is a decentralized, scalable blockchain network that uses zero-knowledge proof technology to enhance the efficiency and security of transaction processing. StarkNet SDK is a toolkit for integrating the StarkNet blockchain, providing a series of functional methods that make it easier for developers to interact with the StarkNet blockchain. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/starknet ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get a new address through a private key | | CreateSignedContractTx | Sign a transaction | For more detailed information about the functions supported by the starknet-sdk package and use cases, you can view the github document for more detailed content: [coin-starknet function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/starknet). ### sui-sdk SUI SDK is a toolkit for integrating the SUI blockchain, containing various functions that can be used for web3 wallets. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/sui ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get a new address through a private key | | SignTransaction | Sign a transaction | | SignMessage | Sign a message | Note: Unlike SECP256K1, ED25519 only supports hard mode derivation for private keys. For more details, refer to: https://github.com/satoshilabs/slips/blob/master/slip-0010.md For more detailed information about the functions supported by the sui-sdk package and use cases, you can view the github document for more detailed content: [coin-sui function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/sui). ### tron-sdk TRON SDK is a toolkit for integrating the TRON blockchain, containing various functions that can be used for web3 wallets. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/tron ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get a new address through a private key | | SignTransaction | Sign a transaction | For more detailed information about the functions supported by the tron-sdk package and use cases, you can view the github document for more detailed content: [coin-tron function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/tron). ### zkspace-sdk ZKSpace SDK is mainly used to integrate ZK contracts, containing various functions that can be used for web3 wallets. In addition to ZKSpace, it also supports zkSync. To get the latest version of the package via `go get`: ```bash go get -u github.com/okx/go-wallet-sdk/coins/zkspace ``` Supported functions: | Function name | Functionality | | --- | --- | | NewAddress | Get a new address through a private key | | CreateSignTransferTx | Sign a transaction | The transaction signature supports data types including: transfer and changePubkey. For more detailed information about the functions supported by the coin-zkspace package and use cases, you can view the github document for more detailed content: [coin-zkspace function functions](https://github.com/okx/go-wallet-sdk/tree/main/coins/zkspace). ## Test Cases On GitHub, each module has a corresponding `tests` directory under its package. This directory contains test cases for various coin modules. You can learn more about the usage of functions in the SDK through these test cases. | Coin Family | Test Case | | --- | --- | | BTC | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-bitcoin/tests/btc.test.ts) | | ETH | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-ethereum/tests/eth.test.ts) | | Cosmos | [Test Case](https://github.com/okx/js-wallet-sdk/tree/main/packages/coin-cosmos/tests) | | Aptos | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-aptos/tests/aptos.test.ts) | | EOS | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-eos/tests/eos.test.ts) | | Solana | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-solana/tests/sol.test.ts) | | Stacks | [Test Case](https://github.com/okx/js-wallet-sdk/tree/main/packages/coin-stacks/tests) | | Starknet | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-starknet/tests/crypto.test.ts) | | SUI | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-sui/tests/crypto.test.ts) | | TRON | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-tron/tests/trx.test.ts) | | Zkspace | [Test Case](https://github.com/okx/js-wallet-sdk/tree/main/packages/coin-zkspace/tests) | | Flow | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-flow/tests/flow.test.ts) | | Near | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-near/tests/near.test.ts) | | Polkadot | [Test Case](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-polkadot/tests/dot.test.ts) | ## Supported Coins | Coin Family | Coin | Derivation Path | | --- | --- | --- | | BTC | BTC | Regular address:
m/44'/0'/0/0'/0
SegWit:
m/49'/0'/0/0'/0
m/84'/0'/0/0'/0
m/86'/0'/0/0'/0 | | BTC | BCH | m/44'/145'/0'/0/0 | | BTC | BSV | m/44'/236'/0'/0/0 | | BTC | LTC | m/44'/2'/0'/0/0 | | BTC | Doge | m/44'/3'/0'/0/0 | | BTC | TBTC | m/44'/0'/0/0'/0 | | BTC | Omni USDT | m/44'/0'/0/0'/0 | | ETH | ETH | m/44'/60'/0'/0/0 | | ETH | Arbitrum One | m/44'/60'/0'/0/0 | | ETH | Arbitrum Nova | m/44'/60'/0'/0/0 | | ETH | Avalanche C | m/44'/60'/0'/0/0 | | ETH | Boba | m/44'/60'/0'/0/0 | | ETH | BNB Chain | m/44'/60'/0'/0/0 | | ETH | Base | m/44'/60'/0'/0/0 | | ETH | Core | m/44'/60'/0'/0/0 | | ETH | Cronos(EVM) | m/44'/60'/0'/0/0 | | ETH | Celo | m/44'/60'/0'/0/0 | | ETH | Conflux(EVM) | m/44'/60'/0'/0/0 | | ETH | Endurance | m/44'/60'/0'/0/0 | | ETH | EthereumPoW | m/44'/60'/0'/0/0 | | ETH | EthereumFair | m/44'/60'/0'/0/0 | | ETH | Filecoin EVM | m/44'/60'/0'/0/0 | | ETH | Fantom | m/44'/60'/0'/0/0 | | ETH | Flare | m/44'/60'/0'/0/0 | | ETH | Gnosis | m/44'/60'/0'/0/0 | | ETH | Goerli | m/44'/60'/0'/0/0 | | ETH | HAQQ Network | m/44'/60'/0'/0/0 | | ETH | Klaytn | m/44'/60'/0'/0/0 | | ETH | KCC | m/44'/60'/0'/0/0 | | ETH | Kava EVM | m/44'/60'/0'/0/0 | | ETH | Linea | m/44'/60'/0'/0/0 | | ETH | Metis | m/44'/60'/0'/0/0 | | ETH | Moonebeam | m/44'/60'/0'/0/0 | | ETH | Moonriver | m/44'/60'/0'/0/0 | | ETH | Mantle | m/44'/60'/0'/0/0 | | ETH | Omega Network | m/44'/60'/0'/0/0 | | ETH | OKTC | m/44'/60'/0'/0/0 | | ETH | Optimism | m/44'/60'/0'/0/0 | | ETH | opBNB | m/44'/60'/0'/0/0 | | ETH | Polygon | m/44'/60'/0'/0/0 | | ETH | Polygon zkEVM | m/44'/60'/0'/0/0 | | ETH | PulseChain | m/44'/60'/0'/0/0 | | ETH | Sepolia | m/44'/60'/0'/0/0 | | ETH | zkSync Era | m/44'/60'/0'/0/0 | | ETH | ZetaChian | m/44'/60'/0'/0/0 | | Cosmos | Atom | m/44'/118'/0'/0/0 | | Cosmos | Axelar | m/44'/118'/0'/0/0 | | Cosmos | Cronos | m/44'/394'/0'/0/0 | | Cosmos | Osmos | m/44'/118'/0'/0/0 | | Cosmos | Evmos | m/44'/60'/0'/0/0 | | Cosmos | Iris | m/44'/118'/0'/0/0 | | Cosmos | Juno | m/44'/118'/0'/0/0 | | Cosmos | Kava | m/44'/459'/0'/0/0 | | Cosmos | Kujira | m/44'/118'/0'/0/0 | | Cosmos | Secret | m/44'/529'/0'/0/0 | | Cosmos | Sei | m/44'/118'/0'/0/0 | | Cosmos | Stargaze | m/44'/118'/0'/0/0 | | Cosmos | Terra | m/44'/330'/0'/0/0 | | Aptos | Aptos | m/44'/637'/0'/0/0 | | EOS | EOS | m/44'/194'/0'/0/0 | | Solana | Solana | m/44'/501'/0'/0/0 | | Stacks | Stacks | m/44'/5757'/0'/0/0 | | ETH Layer 2 | Starknet | m/44'/9004'/0'/0/0 | | SUI | SUI | m/44'/784'/0'/0/0 | | TRX | TRON | m/44'/195'/0'/0/0 | | ETH Layer 2 | ZKSpace | m/44'/60'/0'/0/0 | | ETH Layer 2 | zkSync | m/44'/60'/0'/0/0 | - [Resources](https://web3.okx.com/onchainos/docs/waas/walletapi-resources.md) # Resources - [Definitions](https://web3.okx.com/onchainos/docs/waas/walletapi-resources-definitions.md) # Definitions Here we summarize some common parameters you will encounter when using Wallet API services. You can learn their definitions and usage scenarios. ## accountId **accountId** is a unique identifier assigned by Wallet API to an account. Its function is to associate multiple chains and addresses for aggregated queries of assets and transaction history. ## chainIndex **chainIndex** is the unique identifier for a blockchain within the Wallet API service. For chains following the EVM architecture and EIP-155 protocol, the standard chainIndex is used. For other chains like BTC and Solana that do not have a unified ID standard, we use the cointype parameter from the BIP44 specification as the chain identifier. In other special cases, we will ensure the uniqueness of the ID before assigning it. Example chainIndexes are as follows: | Blockchain Network | chainIndex | eip155chainId | |:----------------:|:----------:|:-------------:| | Bitcoin Mainnet | 0 | | | Ethereum Mainnet | 1 | 1 | | OP Mainnet | 10 | 10 | | ZKSpace | 13 | | | Flare Mainnet | 14 | 14 | | Cronos Mainnet | 25 | 25 | You can check [here](./walletapi-resources-supported-networks) for a full list of supported blockchain networks and their chainIndexes. ## orderId **orderId** is a unique identifier assigned to each transaction within the Wallet API system. Using orderId for queries ensures that even if a transaction is not on the blockchain, it is recorded within the system, ensuring full visibility of the transaction process. - [View chainIndex](https://web3.okx.com/onchainos/docs/waas/walletapi-resources-supported-networks.md) # View chainIndex chainIndex: A custom identifier defined by the Wallet API service, which may differ slightly from the chainId of EIP-155.

EIP-155 chainId: The chainId specified in [EIP-155](https://eips.ethereum.org/EIPS/eip-155). You can check detailed chainId information through [this link](https://chainid.network/).
| No. | Network Name | chainIndex | Supported | |-------|---------------------------|------------|------------| | 1 | BTC | 0 | Supported | | 2 | Ethereum | 1 | Supported | | 3 | Litecoin | 2 | Supported | | 4 | Dogecoin | 3 | Supported | | 5 | Dash | 5 | Supported | | 6 | Optimism | 10 | Supported | | 7 | Flare | 14 | Supported | | 8 | Cronos | 25 | Supported | | 9 | BNB Smart Chain | 56 | Supported | | 10 | Ethereum Classic | 61 | Supported | | 11 | OKTC | 66 | Supported | | 12 | Gnosis | 100 | Supported | | 13 | Polygon | 137 | Supported | | 14 | Bitcoin Cash | 145 | Supported | | 15 | Manta Pacific | 169 | Supported | | 16 | Tron | 195 | Supported | | 17 | X layer | 196 | Supported | | 18 | opBNB | 204 | Supported | | 19 | B^2 network | 223 | Supported | | 20 | Fantom | 250 | Supported | | 21 | Kroma | 255 | Supported | | 22 | KCC | 321 | Supported | | 23 | zkSync Era | 324 | Supported | | 24 | PulseChain | 369 | Supported | | 25 | Omega Network | 408 | Supported | | 26 | Endurance | 648 | Supported | | 27 | Conflux | 1030 | Supported | | 28 | Metis | 1088 | Supported | | 29 | Polygon zkEVM | 1101 | Supported | | 30 | Core | 1116 | Supported | | 31 | Moonbeam | 1284 | Supported | | 32 | Moonriver | 1285 | Supported | | 33 | Ronin | 2020 | Supported | | 34 | Rangers | 2025 | Supported | | 35 | Kava EVM | 2222 | Supported | | 36 | Merlin Chain | 4200 | Supported | | 37 | Mantle | 5000 | Supported | | 38 | Base | 8453 | Supported | | 39 | Immutable zkEVM | 13371 | Supported | | 40 | MODE_ETH | 34443 | Supported | | 41 | Arbitrum One | 42161 | Supported | | 42 | Arbitrum Nova | 42170 | Supported | | 43 | Celo | 42220 | Supported | | 44 | Avalanche C | 43114 | Supported | | 45 | Linea | 59144 | Supported | | 46 | Kaia network (Klaytn) | 8217 | Supported | | 47 | Blast | 81457 | Supported | | 48 | Chilizi | 88888 | Not Supported | | 49 | EthereumPoW | 10001 | Supported | | 50 | TAIKO_ETH | 167000 | Supported | | 51 | BITLAYER_BTC | 200901 | Supported | | 52 | Ethereum Fair(DIS chain) | 513100 | Supported | | 53 | BOB_ETH | 60808 | Supported | | 54 | Scroll | 534352 | Supported | | 55 | Sepolia | 11155111 | Supported | | 56 | Fractal Bitcoin Mainnet | 70000061 | Supported | | 57 | Solana | 501 | Supported | | 58 | SUI | 784 | Supported | | 59 | Gravity | 1625 | Supported | | 60 | Wemix | 1111 | Supported | | 61 | Lumi | 94168 | Supported | | 62 | Sonic | 146 | Supported | - [Error Codes](https://web3.okx.com/onchainos/docs/waas/walletapi-resources-errorcode.md) # Error Codes The current error codes and messages returned by the Wallet API are as follows. You can refer to the list for more details. | Error Code | HTTP Status Code | Message | |------------|------------------|----------------------------------------------| | 50001 | 200 | Service temporarily unavailable, try again | | 50026 | 500 | System busy, try again later | | 81104 | 200 | Blockchain not supported | | 81105 | 200 | Wallet verification error | | 81106 | 200 | Address must be in lowercase | | 81107 | 200 | Too many wallet addresses | | 81108 | 200 | Wallet type mismatch | | 81109 | 200 | Address update error | | 81150 | 200 | Chain not supported in this interface | | 81151 | 200 | Token address incorrect | | 81152 | 200 | Token does not exist | | 81153 | 200 | This token is a platform token, no need to add | | 81157 | 200 | Blockchain and address do not match | | 81158 | 200 | Token protocol not supported | | 81159 | 200 | Data caching, please try again later | | 81201 | 200 | Transaction not found | | 81202 | 200 | Transaction still pending | | 81203 | 200 | Transaction extjson parameters not found | | 81302 | 200 | FromAddress does not belong to the account ID| | 81351 | 200 | Insufficient balance to pay | | 81353 | 200 | Address is illegal | | 81451 | 200 | Node return failed | - [Introduction](https://web3.okx.com/onchainos/docs/waas/dex-introduction.md) # Introduction Welcome to OKX DEX’s developer documentation. OKX DEX is an all-in-one trading aggregator for multi-chain and cross-chain transactions. You can use it to build the Web3 trading services and applications you need, suitable for various scenarios such as Web3 wallets, DApp projects, and DeFi projects. ### Multi-chain support We support 20 networks, including EVM networks, Solana, TRON, and other networks. ### Aggregating multiple cross-chain bridges and DEXs We aggregate 18 cross-chain bridges, including third-party bridges and official bridges, to guarantee optimal received token amounts. We aggregate over 400 decentralized exchanges, providing the best quotes. ### Stability and high availability Our API response time is within 100 milliseconds, while fetching optimal quote routes completely free of charge. - [Swap API](https://web3.okx.com/onchainos/docs/waas/dex-aggregation-process.md) # Swap API OKX DEX is an aggregator of various decentralized exchanges (also known as DEXs, such as Uniswap, Curve, Balancer, etc.) on different blockchains, allowing multi-chain and cross-chain trading. Our goal is to provide users with the best possible prices through intelligent routing. |OKX DEX inquiry and transaction process| |:-| |![image](../images/Swap_API_EN.jpg)| - Comprehensively calculate price, slippage, and transaction costs - Select the best quote for users based on a comprehensive comparison of quotes from various DEXs and PMMs through the smart order splitting algorithm | OKX DEX Swap trading process | |:--------------------------------------------| | ![image](../images/single-swap-english.png) | 1. Get information of the supported networks through /supported/chain. 2. Get information of the supported tokens through /aggregator/all-tokens. 3. Build the request for /quote data based on information of the supported networks and tokens. 4. Following the quote request, obtain the user’s authorization to allow the OKX DEX router to perform asset operations on their wallet. 5. Build the request for /approve-transaction to get the user’s wallet authorization. 6. Build /swap information based on the returned quote router data and obtain the transaction data required for the swap. 7. Broadcast the returned swap transaction information to the blockchain. - [Cross-chain API](https://web3.okx.com/onchainos/docs/waas/dex-crosschain-swap-process.md) # Cross-chain API OKX DEX is an aggregator of various high-quality bridges currently on the market (such as Stargate, Across, Celer cBridge, SWFT, etc.) that provides users with multiple cross-chain path choices. It allows users to conduct swaps on the source chain, subsequent cross-chain transactions, and swaps on the destination chain for the desired tokens. OKX’s X Routing algorithm finds the best price across every DEX. We compare prices from Liquidity Providers (LPs) with the best liquidity pools, split orders, and take into consideration prices, slippage, and network gas fees. We then compare the prices of multiple bridges, and obtain the optimal cross-chain quote after comprehensively calculating the amount of cross-chain transactions, cross-chain bridge fees, slippage, and transaction costs. - Allow more projects to easily and quickly access the DEX cross-chain aggregator. - Convenient, easy to understand, and safe during access and use. |OKX DEX cross-chain quote process| |:-| |![image](../images/dex-crosschain-introduct.png)| - The core components mainly include swaps and bridges. - Swaps and bridges are combined into different trading modes based on different token pairs, These modes include swapping in the source DEX pool and then using a bridge to complete the transaction, using a bridge to complete the transaction in a single step, and swapping on the source chain first before using a bridge and then swapping on the destination chain to complete the cross-chain swap. - Swaps and bridges need on-chain data analysis to complete the whole transaction process. - The DEX XBridge contract is the core of the transaction. It supports cross-chain transactions between mainstream EVM chains and between heterogeneous chains. |OKX DEX cross-chain trading process| |:-| |![image](../images/dex-crosschain-flow-new-introduct.png)| 1. Get information of the supported networks through /supported/chain. 2. Get information of the supported tokens through /aggregator/all-tokens. 3. Build the request for /quote data based on information of the supported networks and tokens. 4. Following the quote request, obtain the user’s authorization to allow the OKX DEX router to perform asset operations on their wallet. 5. Build the request for /approve-transaction to get the user’s wallet authorization. 6. Build /build-tx information based on the returned quote router data and obtain the transaction data required for the cross-chain swap . 7. Broadcast the returned transaction information to the blockchain. 8. Use /status to check the details of this cross-chain transaction based on the transaction hash received from the broadcast. - [Limit order API](https://web3.okx.com/onchainos/docs/waas/dex-limit-order-process.md) # Limit order API A DEX limit order (limit order) is a business process in which a user specifies a target price to buy or sell tokens on a decentralized exchange (DEX). If the current market price can meet the user's specified target price, the DEX aggregator will automatically execute the order. Through the DEX Limit Order API, users can create and query limit orders and aggregate liquidity into the DEX aggregator, enjoying the best price on OKX DEX. Key features of the DEX limit order API functionality include: - Limit orders are executed upon matching with users on the DEX aggregator. - Limit order creators experience no slippage. - Partial order execution is supported, allowing orders to be partially filled. |OKX DEX limit order API transaction process |:-| |![image](../images/Limit_Order_EN.jpg)| - [Quick start](https://web3.okx.com/onchainos/docs/waas/dex-aggregation-root-quick-start.md) # Quick start Before using the DEX API, you need to [create a project](./introduction-to-developer-portal-interface#create-project) and [generate an API key](./introduction-to-developer-portal-interface#generate-api-keys) in the developer portal. The detailed steps and related resources are as follows: - [Build swap applications](https://web3.okx.com/onchainos/docs/waas/dex-api-quick-start-reference.md) # Build swap applications - [Build swap applications on the EVM network](https://web3.okx.com/onchainos/docs/waas/dex-use-swap-quick-start.md) # Build swap applications on the EVM network ## Build single-chain applications In this guide, we’ll provide an example token swap through OKX DEX, using ETH from the Ethereum network to purchase USDC. The process is as follows: 1. Set up your environment 2. Check allowance 3. Check approval parameters and initiate the approval 4. Request the /quote endpoint and get the quote data 5. Request the /swap endpoint send the swap transaction ## 1. Set up your environment ```js // --------------------- npm package --------------------- const { Web3} = require('web3'); const cryptoJS = require('crypto-js'); // The URL for the Ethereum node you want to connect to const web3 = new Web3('https://......com'); const apiBaseUrl = 'https://web3.okx.com/api/v5/dex/aggregator'; // --------------------- environment variable --------------------- const chainId = '1'; // usdc contract address const fromTokenAddress = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'; // Native token contract address const toTokenAddress = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'; // gasPrice or GasLimit ratio const ratio = BigInt(3) / BigInt(2); // your wallet address const user = '0x6f9fxxxxxxxxxxxxxxxxxxxx61059dcfd9' const fromAmount = '1000000' // user wallet private key const privateKey = 'xxxxx'; // open api Secret key const secretkey = 'xxxxx' // Get the current time const date = new Date(); // --------------------- util function --------------------- function getAggregatorRequestUrl(methodName, queryParams) { return apiBaseUrl + methodName + '?' + (new URLSearchParams(queryParams)).toString(); } // Check https://web3.okx.com/zh-hans/web3/build/docs/waas/rest-authentication for api-key const headersParams = { 'Content-Type': 'application/json', // The api Key obtained from the previous application 'OK-ACCESS-KEY': 'xxxxx', 'OK-ACCESS-SIGN': cryptoJS.enc.Base64.stringify( // The field order of headersParams should be consistent with the order of quoteParams. // example : quote ==> cryptoJS.HmacSHA256(timestamp + 'GET' + '/api/v5/dex/aggregator/quote?amount=1000000&chainId=1&toTokenAddress=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE&fromTokenAddress=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', secretKey) cryptoJS.HmacSHA256(date.toISOString() + 'GET' + '/api/v5/dex/aggregator/xxx/xxx/xxx', secretKey) ), // Convert the current time to the desired format 'OK-ACCESS-TIMESTAMP': date.toISOString(), // The password created when applying for the key 'OK-ACCESS-PASSPHRASE': 'xxxxxxx', }; ``` ## 2.Check allowance #### Taking ETH chain as an example - This demo is in JavaScript 1. Connect to an Ethereum node: You need to ensure that you’ve connected to an available Ethereum node. You can use web3.js or other Ethereum development libraries to connect to the node. In the code, you need to specify the node’s HTTP or WebSocket endpoint. 2. Obtain a token contract instance: To use the contract address and ABI of the token, you need to create an instance of the token contract. You can use web3.eth.Contract in web3.js to achieve this, and pass the contract address and ABI as arguments to the contract instance. a. Query the authorized amount: Query the authorized allowance by calling the allowance function of the contract instance. This function requires two parameters: the owner’s address and the authorized party’s address (spenderAddress). You can query the authorized allowance by providing these two addresses during the call. 3. For spenderAddress, refer to dexContractAddress from here in the Response interface. ```js const tokenAddress = fromTokenAddress; // user address const ownerAddress = user; // ETH dex token approval address const spenderAddress = '0x40aa958dd87fc8305b97f2ba922cddca374bcd7f'; const tokenABI = [ { "constant": true, "inputs": [ { "name": "_owner", "type": "address" }, { "name": "_spender", "type": "address" } ], "name": "allowance", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" } ]; // Create token contract instance const tokenContract = new web3.eth.Contract(tokenABI, tokenAddress); // Query token approve allowance function async function getAllowance(ownerAddress, spenderAddress) { try { const allowance = await tokenContract.methods.allowance(ownerAddress, spenderAddress).call(); return parseFloat(allowance); } catch (error) { console.error('Failed to query allowance:', error); } } ``` - The variable allowanceAmount in the following text represents the actual allowance amount on the blockchain. ## 3. Check the approval parameters and initiate the approval As allowanceAmount is lower than fromTokenAmount, you need to approve this token. ### 3.1 Define your transaction approval parameters - Next, define the parameters for the transaction approval you want to perform. ```js const getApproveTransactionParams = { chainId: chainId, tokenContractAddress: fromTokenAddress, approveAmount: fromAmount, }; ``` ### 3.2 Define helper functions - Define helper functions that will be used to interact with the DEX transaction approval API. ```js const approveTransaction = async () => { const apiRequestUrl = getAggregatorRequestUrl( '/approve-transaction', getApproveTransactionParams ); console.log('apiRequestUrl:', apiRequestUrl) return fetch(apiRequestUrl, { method: 'get', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` ### 3.3 Get transaction information and send approveTransaction ```js async function sendApproveTx() { const allowanceAmount = await getAllowance(ownerAddress, spenderAddress); if (allowanceAmount < parseFloat(fromAmount)) { let gasPrice = await web3.eth.getGasPrice(); let nonce = await web3.eth.getTransactionCount(user) const {data} = await approveTransaction(); const txObject = { nonce: nonce, to: getApproveTransactionParams.tokenContractAddress, // approve token address gasLimit: data[0].gasLimit * 2, // avoid GasLimit too low gasPrice: gasPrice * BigInt(3) / BigInt(2), // avoid GasPrice too low data: data[0].data, // approve callData value: 0 // approve value fix 0 }; const {rawTransaction} = await web3.eth.accounts.signTransaction( txObject, privateKey ); await web3.eth.sendSignedTransaction(rawTransaction); } } ``` ## 4. Request the /quote endpoint and get the quote data ### 4.1 Define quote parameters - Next, define the parameters to get basic information of the quote and the router list. ```js const quoteParams = { amount: fromAmount, chainId: chainId, toTokenAddress: toTokenAddress, fromTokenAddress: fromTokenAddress, }; ``` ### 4.2 Define helper functions - Define helper functions to interact with the DEX API. ```js const getQuote = async () => { const apiRequestUrl = getAggregatorRequestUrl('/quote', quoteParams); return fetch(apiRequestUrl, { method: 'get', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` ## 5. Request the /swap endpoint and sent transaction ### 5.1 Define swap parameters - Next, define the parameters of the swap, and get the tx information. ```js const swapParams = { chainId: chainid, fromTokenAddress: fromTokenAddress, toTokenAddress: toTokenAddress, amount: fromAmount, slippage: '0.03', userWalletAddress: user }; ``` ### 5.2 Define helper functions - Define helper functions to interact with the DEX API. ```js const getSwapData = async () => { const apiRequestUrl = getAggregatorRequestUrl('/swap', swapParams); return fetch(apiRequestUrl, { method: 'get', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` ### 5.3 Request the /swap endpoint and send the transaction ```js async function sendSwapTx() { const {data: swapData} = await getSwapData(); console.log('swapData:', swapData) const swapDataTxInfo = swapData[0].tx; const nonce = await web3.eth.getTransactionCount(user, 'latest'); let signTransactionParams = { data: swapDataTxInfo.data, gasPrice: BigInt(swapDataTxInfo.gasPrice) * BigInt(ratio), // avoid GasPrice too low, to: swapDataTxInfo.to, value: swapDataTxInfo.value, gas: BigInt(swapDataTxInfo.gas) * BigInt(ratio), // avoid GasLimit too low nonce, }; const {rawTransaction} = await web3.eth.accounts.signTransaction( signTransactionParams, privateKey ); const chainTxInfo = await web3.eth.sendSignedTransaction(rawTransaction); console.log('chainTxInfo:', chainTxInfo); } ``` - [Build swap applications on Solana](https://web3.okx.com/onchainos/docs/waas/dex-use-swap-solana-quick-start.md) # Build swap applications on Solana In this guide, we will provide a use case for Solana token exchange through the OKX DEX. - Set up your environment - Obtain the token account address for toTokenAddress - Obtain the exchange path - Deserialize and sign - Execute the transaction ## 1. Set up your environment Import the necessary Node.js libraries and set up your environment variables. Define helper functions and assembly parameters [Node.js Environment Settings](https://web3.okx.com/web3/build/docs/waas/nodejs-environment). Additionally, you need to import the following libraries after completing the above steps. ```js const bs58 = require('bs58'); const solanaWeb3 = require('@solana/web3.js'); const {Connection} = require("@solana/web3.js"); npm i bs58 npm i @solana/web3.js ``` ## 2. Obtain the exchange path and callData Solana's NativeTokenAddress is 11111111111111111111111111111111. - Use the `/swap` endpoint to retrieve detailed swap paths and `callData`. Here is an example of swapping **SOL** to **wSOL** on the Solana chain: ```js curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/swap?amount=1000&chainId=501&fromTokenAddress=11111111111111111111111111111111&toTokenAddress=So11111111111111111111111111111111111111112&userWalletAddress=3cUbuUEJkcgtzGxvsukksNzmgqaUK9jwFS5pqxxxxxxx&slippage=0.05' \ ``` ## 3. Deserialize and sign The callData here is obtained from the `/swap` endpoint. ```js // rpc const connection = new Connection("xxxxxxxxxxx") async function signTransaction(callData, privateKey) { // decode const transaction = bs58.decode(callData) let tx // There are two types of callData, one is the old version and the other is the new version. try { tx = solanaWeb3.Transaction.from(transaction) } catch (error) { tx = solanaWeb3.VersionedTransaction.deserialize(transaction) } // Replace the latest block hash const recentBlockHash = await connection.getLatestBlockhash(); if (tx instanceof solanaWeb3.VersionedTransaction) { tx.message.recentBlockhash = recentBlockHash.blockhash; } else { tx.recentBlockhash = recentBlockHash.blockhash } let feePayer = solanaWeb3.Keypair.fromSecretKey(bs58.decode(privateKey)) // sign if (tx instanceof solanaWeb3.VersionedTransaction) { // v0 callData tx.sign([feePayer]) } else { // legacy callData tx.partialSign(feePayer) } console.log(tx) } // 'xxxxxxx' means your privateKey signTransaction(callData,'xxxxxxx') ``` ## 4. Execute the transaction ```js const txId = await connection.sendRawTransaction(tx.serialize()); console.log('txId:', txId) // Verify whether it has been broadcast on the chain. await connection.confirmTransaction(txId); console.log(`https://solscan.io/tx/${txId}`); ``` ## 5. Complete Implementation using typescript For a complete implementation of token swaps on Solana, we provide a TypeScript library that integrates with the OKX DEX API. This implementation is part of our [OKX DEX API Library](https://github.com/okx/dex-api-library/tree/main). **Important RPC Configuration Note:** Before proceeding, you'll need to select an RPC endpoint. While this example uses Helius (`https://mainnet.helius-rpc.com`), you can use any Solana RPC provider of your choice. It is recommended that you use a 3rd party provider as the public solana RPC endpoint may introduce resource constraints. > ⚠️ **Disclaimer**: The choice of RPC endpoint is entirely up to you. OKX is not responsible for any third-party RPC services. Always ensure you're using a reliable and secure RPC provider for your production environment. ### Environment Setup Create a `.env` file with the following configuration: ```env OKX_API_KEY=your_api_key OKX_SECRET_KEY=your_secret_key OKX_API_PASSPHRASE=your_passphrase OKX_PROJECT_ID=your_project_id WALLET_ADDRESS=your_wallet_address PRIVATE_KEY=your_private_key SOLANA_RPC_URL=your_rpc_url WS Endpoint is optional WS_ENDPONT= ``` ### Complete Swap Implementation [The following implementation](https://github.com/okx/dex-api-library/blob/main/lib/solana/swap/solana-swap.ts) provides a full-featured swap solution: ```typescript // swap.ts import base58 from "bs58"; import BN from "bn.js"; import * as solanaWeb3 from "@solana/web3.js"; import { Connection } from "@solana/web3.js"; import cryptoJS from "crypto-js"; import dotenv from 'dotenv'; dotenv.config(); // Environment variables const apiKey = process.env.OKX_API_KEY; const secretKey = process.env.OKX_SECRET_KEY; const apiPassphrase = process.env.OKX_API_PASSPHRASE; const projectId = process.env.OKX_PROJECT_ID; const userAddress = process.env.WALLET_ADDRESS; const userPrivateKey = process.env.PRIVATE_KEY; const solanaRpcUrl = process.env.SOLANA_RPC_URL; // Constants const SOLANA_CHAIN_ID = "501"; const COMPUTE_UNITS = 300000; const MAX_RETRIES = 3; const connection = new Connection(`${solanaRpcUrl}`, { confirmTransactionInitialTimeout: 5000 // wsEndpoint: solanaWsUrl, }); function getHeaders(timestamp: string, method: string, requestPath: string, queryString = "") { if (!apiKey || !secretKey || !apiPassphrase || !projectId) { throw new Error("Missing required environment variables"); } const stringToSign = timestamp + method + requestPath + queryString; return { "Content-Type": "application/json", "OK-ACCESS-KEY": apiKey, "OK-ACCESS-SIGN": cryptoJS.enc.Base64.stringify( cryptoJS.HmacSHA256(stringToSign, secretKey) ), "OK-ACCESS-TIMESTAMP": timestamp, "OK-ACCESS-PASSPHRASE": apiPassphrase, "OK-ACCESS-PROJECT": projectId, }; } async function getTokenInfo(fromTokenAddress: string, toTokenAddress: string) { const timestamp = new Date().toISOString(); const requestPath = "/api/v5/dex/aggregator/quote"; const params = { chainId: SOLANA_CHAIN_ID, fromTokenAddress, toTokenAddress, amount: "1000000", // small amount just to get token info slippage: "0.5", }; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); const response = await fetch( `https://web3.okx.com${requestPath}${queryString}`, { method: "GET", headers } ); if (!response.ok) { throw new Error(`Failed to get quote: ${await response.text()}`); } const data = await response.json(); if (data.code !== "0" || !data.data?.[0]) { throw new Error("Failed to get token information"); } const quoteData = data.data[0]; return { fromToken: { symbol: quoteData.fromToken.tokenSymbol, decimals: parseInt(quoteData.fromToken.decimal), price: quoteData.fromToken.tokenUnitPrice }, toToken: { symbol: quoteData.toToken.tokenSymbol, decimals: parseInt(quoteData.toToken.decimal), price: quoteData.toToken.tokenUnitPrice } }; } function convertAmount(amount: string, decimals: number) { try { if (!amount || isNaN(parseFloat(amount))) { throw new Error("Invalid amount"); } const value = parseFloat(amount); if (value <= 0) { throw new Error("Amount must be greater than 0"); } return new BN(value * Math.pow(10, decimals)).toString(); } catch (err) { console.error("Amount conversion error:", err); throw new Error("Invalid amount format"); } } async function main() { try { const args = process.argv.slice(2); if (args.length < 3) { console.log("Usage: ts-node swap.ts "); console.log("Example: ts-node swap.ts 1.5 11111111111111111111111111111111 EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"); process.exit(1); } const [amount, fromTokenAddress, toTokenAddress] = args; if (!userPrivateKey || !userAddress) { throw new Error("Private key or user address not found"); } // Get token information console.log("Getting token information..."); const tokenInfo = await getTokenInfo(fromTokenAddress, toTokenAddress); console.log(`From: ${tokenInfo.fromToken.symbol} (${tokenInfo.fromToken.decimals} decimals)`); console.log(`To: ${tokenInfo.toToken.symbol} (${tokenInfo.toToken.decimals} decimals)`); // Convert amount using fetched decimals const rawAmount = convertAmount(amount, tokenInfo.fromToken.decimals); console.log(`Amount in ${tokenInfo.fromToken.symbol} base units:`, rawAmount); // Get swap quote const quoteParams = { chainId: SOLANA_CHAIN_ID, amount: rawAmount, fromTokenAddress, toTokenAddress, slippage: "0.5", userWalletAddress: userAddress, } as Record; // Get swap data const timestamp = new Date().toISOString(); const requestPath = "/api/v5/dex/aggregator/swap"; const queryString = "?" + new URLSearchParams(quoteParams).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); console.log("Requesting swap quote..."); const response = await fetch( `https://web3.okx.com${requestPath}${queryString}`, { method: "GET", headers } ); const data = await response.json(); if (data.code !== "0") { throw new Error(`API Error: ${data.msg}`); } const swapData = data.data[0]; // Show estimated output and price impact const outputAmount = parseFloat(swapData.routerResult.toTokenAmount) / Math.pow(10, tokenInfo.toToken.decimals); console.log("\nSwap Quote:"); console.log(`Input: ${amount} ${tokenInfo.fromToken.symbol} ($${(parseFloat(amount) * parseFloat(tokenInfo.fromToken.price)).toFixed(2)})`); console.log(`Output: ${outputAmount.toFixed(tokenInfo.toToken.decimals)} ${tokenInfo.toToken.symbol} ($${(outputAmount * parseFloat(tokenInfo.toToken.price)).toFixed(2)})`); if (swapData.priceImpactPercentage) { console.log(`Price Impact: ${swapData.priceImpactPercentage}%`); } console.log("\nExecuting swap transaction..."); let retryCount = 0; while (retryCount < MAX_RETRIES) { try { if (!swapData || (!swapData.tx && !swapData.data)) { throw new Error("Invalid swap data structure"); } const transactionData = swapData.tx?.data || swapData.data; if (!transactionData || typeof transactionData !== 'string') { throw new Error("Invalid transaction data"); } const recentBlockHash = await connection.getLatestBlockhash(); console.log("Got blockhash:", recentBlockHash.blockhash); const decodedTransaction = base58.decode(transactionData); let tx; try { tx = solanaWeb3.VersionedTransaction.deserialize(decodedTransaction); console.log("Successfully created versioned transaction"); tx.message.recentBlockhash = recentBlockHash.blockhash; } catch (e) { console.log("Versioned transaction failed, trying legacy:", e); tx = solanaWeb3.Transaction.from(decodedTransaction); console.log("Successfully created legacy transaction"); tx.recentBlockhash = recentBlockHash.blockhash; } const computeBudgetIx = solanaWeb3.ComputeBudgetProgram.setComputeUnitLimit({ units: COMPUTE_UNITS }); const feePayer = solanaWeb3.Keypair.fromSecretKey( base58.decode(userPrivateKey) ); if (tx instanceof solanaWeb3.VersionedTransaction) { tx.sign([feePayer]); } else { tx.partialSign(feePayer); } const txId = await connection.sendRawTransaction(tx.serialize(), { skipPreflight: false, maxRetries: 5 }); const confirmation = await connection.confirmTransaction({ signature: txId, blockhash: recentBlockHash.blockhash, lastValidBlockHeight: recentBlockHash.lastValidBlockHeight }, 'confirmed'); if (confirmation?.value?.err) { throw new Error(`Transaction failed: ${JSON.stringify(confirmation.value.err)}`); } console.log("\nSwap completed successfully!"); console.log("Transaction ID:", txId); console.log("Explorer URL:", `https://solscan.io/tx/${txId}`); process.exit(0); } catch (error) { console.error(`Attempt ${retryCount + 1} failed:`, error); retryCount++; if (retryCount === MAX_RETRIES) { throw error; } await new Promise(resolve => setTimeout(resolve, 2000 * retryCount)); } } } catch (error) { console.error("Error:", error instanceof Error ? error.message : "Unknown error"); process.exit(1); } } if (require.main === module) { main(); } ``` ### Usage Example To execute a swap, run the script with the following parameters: ```bash npx ts-node swap.ts ``` For Example: ```bash # Example: Swap .01 SOL to USDC npx ts-node swap.ts .01 11111111111111111111111111111111 EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v ``` Will return a response similar to the following: ```bash From: SOL (9 decimals) To: USDC (6 decimals) Amount in SOL base units: 10000000 Requesting swap quote... Swap Quote: Input: .01 SOL ($1.82) Output: 1.820087 USDC ($1.82) Executing swap transaction... Got blockhash: J7cWaf9UQJyN6SqatDHhmdAtP3skN7YKFCJnbaLeKf3r Successfully created versioned transaction Swap completed successfully! Transaction ID: 5LncQyzK7YmcodcsQMYwnjYBAYBkKJAaS1XR2RLiCVyPyA5nwHjUNuSQos4VGk4CJm5spRPngdnv8cQYjYYwCAVu Explorer URL: https://solscan.io/tx/5LncQyzK7YmcodcsQMYwnjYBAYBkKJAaS1XR2RLiCVyPyA5nwHjUNuSQos4VGk4CJm5spRPngdnv8cQYjYYwCAVu ``` ## 6. MEV Protection Trading on any network comes with MEV(Maximal Extractable Value) risks, but here are some methods to potentially protect your users' trades on Solana. This implementation includes several approaches that developers can implement to minimize their users' MEV exposure. ### Smart Protection Approaches The first line of defense uses dynamic priority fees - think of it as your bid in an auction against MEV bots: ```typescript static async getPriorityFee(): Promise { const recentFees = await connection.getRecentPrioritizationFees(); const maxFee = Math.max(...recentFees.map(fee => fee.prioritizationFee)); return Math.min(maxFee * 1.5, MEV_PROTECTION.MAX_PRIORITY_FEE); } ``` For larger trades, you can enable TWAP(Time-Weighted Average Price). Instead of making one big splash that MEV bots love to target, your trade gets split into smaller pieces: ```typescript if (MEV_PROTECTION.TWAP_ENABLED) { const chunks = await TWAPExecution.splitTrade( rawAmount, fromTokenAddress, toTokenAddress ); } ``` ### Protection in Action When you execute a trade with [this implementation](https://github.com/okx/dex-api-library/blob/main/lib/solana/swap/solana-swap-mev.ts), several things happen: (1)**Pre-Trade Checks:** - The token you're buying gets checked for honeypot characteristics - Network fees are analyzed to set competitive priority - Your trade size determines if it should be split up (2)**During the Trade:** - Large trades can be split into parts with randomized timing - Each piece gets its own priority fee based on market conditions - Specific block targeting helps reduce exposure (3)**Transaction Safety:** - Each transaction runs through simulation first - Built-in confirmation tracking - Automatic retry logic if something goes wrong To be transaprent - MEV on Solana is like rain. You can't stop it completely, but these protections are like carrying an umbrella. They make life harder for MEV bots, but more robust solutions require . ### Making It Work For You Some practical tips when using these protections: (1)For trades where TWAP is applicabe, consider enabling it in the code example: ```typescript MEV_PROTECTION.TWAP_ENABLED = true; ``` (2)During crazy market conditions, you might want to bump up priority fees: ```typescript MEV_PROTECTION.PRIORITY_MULTIPLIER = 3; // More competitive ``` (3)Set slippage based on the token you're trading: ```typescript CONFIG.SLIPPAGE = "0.5" // Standard setting ``` It's worth noting that better MEV protection usually means slower execution. If you need speed above all else, you might need to accept more MEV risk. It's about finding what works for your users' needs. ### Real World Example Here's how you'd use it: ```bash npx ts-node solana-swap-mev.ts .02 11111111111111111111111111111111 EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v ``` Which Returns: ```bash Swap completed successfully! Transaction IDs: 669uQvX6wRRGo3mUMvyPG5s9kFN9pCZsKER5kbByfWUKptWHTCUMpfycwMXC2RFMJpzYBKaPAMfCbxr3886fzkQY, 51nvyyGWQU3Nw8jo7g1Suq2sAZSUkgA7bSJ8upbFtR8bSsibs896R6Bifi6ucFmhuTP63cmsM8bKJiFz6AA14LxA, 5ov1cVk64adFVnnXZpizrdRFd4BvpASMwkkVTohRWtig5Fu519iQSahVbddvjRAtfcimNGg6XhN8cTaneVddc63j, 2ySKQq5gmfYZ1sJuCrz72aNFMknu943PBAw9ebRFtFeLpW4Q9PXjNTHwY1uiREVmvDiYGJZu9piKvBNDLorx5zi5 Explorer URLs: https://solscan.io/tx/669uQvX6wRRGo3mUMvyPG5s9kFN9pCZsKER5kbByfWUKptWHTCUMpfycwMXC2RFMJpzYBKaPAMfCbxr3886fzkQY https://solscan.io/tx/51nvyyGWQU3Nw8jo7g1Suq2sAZSUkgA7bSJ8upbFtR8bSsibs896R6Bifi6ucFmhuTP63cmsM8bKJiFz6AA14LxA https://solscan.io/tx/5ov1cVk64adFVnnXZpizrdRFd4BvpASMwkkVTohRWtig5Fu519iQSahVbddvjRAtfcimNGg6XhN8cTaneVddc63j https://solscan.io/tx/2ySKQq5gmfYZ1sJuCrz72aNFMknu943PBAw9ebRFtFeLpW4Q9PXjNTHwY1uiREVmvDiYGJZu9piKvBNDLorx5zi5 ``` ### Looking Beyond Implementation Protection While the protections in this implementation offer solid defense mechanisms, it's worth noting that the most advanced MEV protection on Solana happens at the validator level. Validator-level solutions can intercept and protect trades before they even hit the mempool, providing protection at a much deeper layer than application-level safeguards. However, these solutions typically require specialized infrastructure setup and aren't accessible through standard RPC endpoints. The reality is: the most effective MEV protection combines multiple approaches - from smart contract level safeguards, to application-level protections like those in this implementation, all the way up to validator-level solutions. Each layer adds its own unique benefits and tradeoffs in the battle against MEV. ## 7.Add Swap Instructions The swap-instruction endpoint is your go-to when you need more control over the swap process than the `/swap` endpoint provides. While `/swap` gives you a pre-built transaction ready to sign, swap-instruction lets you: - Build custom transaction signing flows - Handle instruction processing your own way - Add your own instructions to the transaction if needed - Work with lookup tables directly for optimizing transaction size This guide walks through a complete implementation using swap instructions. You'll see how to fetch them from the API, process them, and build them into a working transaction. ### Set up your environment Import the necessary libraries and configure your environment: ```typescript // Required Solana dependencies for DEX interaction import { Connection, // Handles RPC connections to Solana network Keypair, // Manages wallet keypairs for signing PublicKey, // Handles Solana public key conversion and validation TransactionInstruction, // Core transaction instruction type TransactionMessage, // Builds transaction messages (v0 format) VersionedTransaction, // Supports newer transaction format with lookup tables RpcResponseAndContext, // RPC response wrapper type SimulatedTransactionResponse, // Simulation result type AddressLookupTableAccount, // For transaction size optimization PublicKeyInitData // Public key input type } from "@solana/web3.js"; import base58 from "bs58"; // Required for private key decoding import dotenv from "dotenv"; // Environment variable management dotenv.config(); ``` ### Initialize Connection and Wallet Set up your connection and wallet instance: ```typescript // Note: Consider using a reliable RPC endpoint with high rate limits for production const connection = new Connection( process.env.SOLANA_RPC_URL || "https://api.mainnet-beta.solana.com" ); // Initialize wallet for signing // This wallet will be the fee payer and transaction signer // Ensure it has sufficient SOL for transaction fees const wallet = Keypair.fromSecretKey( Uint8Array.from(base58.decode(process.env.PRIVATE_KEY?.toString() || "")) ); ``` ### Configure Swap Parameters Set up the parameters for your swap: ```typescript // Configure swap parameters const baseUrl = "https://beta.okex.org/api/v5/dex/aggregator/swap-instruction"; const params = { chainId: "501", // Solana mainnet chain ID feePercent: "1", // Platform fee percentage amount: "1000000", // Amount in smallest denomination (e.g., lamports for SOL) fromTokenAddress: "11111111111111111111111111111111", // SOL mint address toTokenAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC mint address slippage: "0.1", // Slippage tolerance in percentage userWalletAddress: process.env.WALLET_ADDRESS || "", // Wallet performing the swap priceTolerance: "0", // Maximum allowed price impact autoSlippage: "false", // Use fixed slippage instead of auto fromTokenReferrerWalletAddress: process.env.WALLET_ADDRESS || "", // For referral fees pathNum: "3" // Maximum routes to consider } ``` ### Process Swap Instructions Fetch and process the swap instructions: ```typescript // Helper function to convert DEX API instructions to Solana format // The DEX returns instructions in a custom format that needs conversion function createTransactionInstruction(instruction: any): TransactionInstruction { return new TransactionInstruction({ programId: new PublicKey(instruction.programId), // DEX program ID keys: instruction.accounts.map((key: any) => ({ pubkey: new PublicKey(key.pubkey), // Account address isSigner: key.isSigner, // True if account must sign tx isWritable: key.isWritable // True if instruction modifies account })), data: Buffer.from(instruction.data, 'base64') // Instruction parameters }); } // Fetch optimal swap route and instructions from DEX // This call finds the best price across different DEX liquidity pools const url = `${baseUrl}?${new URLSearchParams(params).toString()}`; const { data: { instructionLists, addressLookupTableAccount } } = await fetch(url, { method: 'GET', headers: { 'Content-Type': 'application/json' } }).then(res => res.json()); // Process DEX instructions into Solana-compatible format const instructions: TransactionInstruction[] = []; // Remove duplicate lookup table addresses returned by DEX const addressLookupTableAccount2 = Array.from(new Set(addressLookupTableAccount)); console.log("Lookup tables to load:", addressLookupTableAccount2); // Convert each DEX instruction to Solana format if (instructionLists?.length) { instructions.push(...instructionLists.map(createTransactionInstruction)); } ``` ### Handle Address Lookup Tables Process the address lookup tables for transaction optimization: ```typescript // Process lookup tables for transaction optimization // Lookup tables are crucial for complex swaps that interact with many accounts // They significantly reduce transaction size and cost const addressLookupTableAccounts: AddressLookupTableAccount[] = []; if (addressLookupTableAccount2?.length > 0) { console.log("Loading address lookup tables..."); // Fetch all lookup tables in parallel for better performance const lookupTableAccounts = await Promise.all( addressLookupTableAccount2.map(async (address: unknown) => { const pubkey = new PublicKey(address as PublicKeyInitData); // Get lookup table account data from Solana const account = await connection .getAddressLookupTable(pubkey) .then((res) => res.value); if (!account) { throw new Error(`Could not fetch lookup table account ${address}`); } return account; }) ); addressLookupTableAccounts.push(...lookupTableAccounts); } ``` ### Create and Sign Transaction Create the transaction message and sign it: ```typescript // Get recent blockhash for transaction timing and uniqueness // Transactions are only valid for a limited time after this blockhash const latestBlockhash = await connection.getLatestBlockhash('finalized'); // Create versioned transaction message // V0 message format required for lookup table support const messageV0 = new TransactionMessage({ payerKey: wallet.publicKey, // Fee payer address recentBlockhash: latestBlockhash.blockhash, // Transaction timing instructions // Swap instructions from DEX }).compileToV0Message(addressLookupTableAccounts); // Include lookup tables // Create new versioned transaction with optimizations const transaction = new VersionedTransaction(messageV0); // Simulate transaction to check for errors // This helps catch issues before paying fees const result: RpcResponseAndContext = await connection.simulateTransaction(transaction); // Sign transaction with fee payer wallet const feePayer = Keypair.fromSecretKey( base58.decode(process.env.PRIVATE_KEY?.toString() || "") ); transaction.sign([feePayer]) ``` ### Execute Transaction Finally, simulate and send the transaction: ```typescript // Send transaction to Solana // skipPreflight=false ensures additional validation // maxRetries helps handle network issues const txId = await connection.sendRawTransaction(transaction.serialize(), { skipPreflight: false, // Run preflight validation maxRetries: 5 // Retry on failure }); // Log transaction details console.log("Raw transaction:", transaction.serialize()); console.log("Base58 transaction:", base58.encode(transaction.serialize())); // Log simulation results for debugging console.log("=========simulate result========="); result.value.logs?.forEach((log) => { console.log(log); }); // Log transaction results console.log("Transaction ID:", txId); console.log("Explorer URL:", `https://solscan.io/tx/${txId}`); ``` ### Best Practices and Considerations When implementing swap instructions, keep these key points in mind: 1. You can view an example of the full Typescript implementation here 2. **Error Handling**: Always implement proper error handling for API responses and transaction simulation results. 3. **Slippage Protection**: Choose appropriate slippage parameters based on your use case and market conditions. 4. **Gas Optimization**: Use address lookup tables when available to reduce transaction size and costs. 5. **Transaction Simulation**: Always simulate transactions before sending them to catch potential issues early. You can also use this for testing without executing the transaction. 6. **Retry Logic**: Implement proper retry mechanisms for failed transactions with appropriate backoff strategies. By following these practices and understanding the swap instruction process, you can build reliable and efficient token exchange functionality into your Solana applications. - [Build swap applications on Sui](https://web3.okx.com/onchainos/docs/waas/dex-use-swap-sui-quick-start.md) # Build swap applications on Sui In this guide, we will provide a use case for Sui token exchange through the OKX DEX. - Set up your environment - Obtain the token account address for toTokenAddress - Obtain the exchange path - Process and sign transaction - Execute the transaction ## 1. Set up your environment For convenience, you can clone the OKX DEX API Library and install the necessary dependencies: ```bash git clone https://github.com/okx/dex-api-library.git cd dex-api-library npm install ``` Additionally, you need to create a `.env` file with the following configuration: You can obtain your OKX API credentials from: https://web3.okx.com/web3/build/dev-portal ```js OKX_API_KEY=your_api_key OKX_SECRET_KEY=your_secret_key OKX_API_PASSPHRASE=your_passphrase OKX_PROJECT_ID=your_project_id WALLET_ADDRESS=your_sui_wallet_address PRIVATE_KEY=your_sui_wallet_private_key ``` This demo uses the `hexWithoutFlag` format of your SUI privatekey You can follow the steps below to obtain it: 1. Export and save your SUI wallet's private key 2. Download and install the [SUI CLI](https://docs.sui.io/guides/developer/getting-started/sui-install) 3. Use the following command to convert your SUI wallet's private key to the `hexWithoutFlag` format ```typescript sui keytool convert ``` 4. Use the output value as `PRIVATE_KEY` in your `.env` file ## 2. Obtain token information and swap quote Use the `/dex/aggregator/quote` endpoint to retrieve token information and the `/dex/aggregator/swap` endpoint for swap data. Here's an example of swapping **SUI** to **USDC**: ```bash function getHeaders(timestamp: string, method: string, requestPath: string, queryString = "") { if (!apiKey || !secretKey || !apiPassphrase || !projectId) { throw new Error("Missing required environment variables"); } const timestamp = new Date().toISOString(); const stringToSign = timestamp + method + requestPath + queryString; return { "Content-Type": "application/json", "OK-ACCESS-KEY": apiKey, "OK-ACCESS-SIGN": cryptoJS.enc.Base64.stringify( cryptoJS.HmacSHA256(stringToSign, secretKey) ), "OK-ACCESS-TIMESTAMP": timestamp, "OK-ACCESS-PASSPHRASE": apiPassphrase, "OK-ACCESS-PROJECT": projectId, }; } async function getTokenInfo(fromTokenAddress: string, toTokenAddress: string) { const timestamp = new Date().toISOString(); const requestPath = "/api/v5/dex/aggregator/swap"; const params = { chainId: SUI_CHAIN_ID, fromTokenAddress, toTokenAddress, amount: "1000000", slippage: "0.5", userWalletAddress: normalizedWalletAddress, }; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); const response = await fetch( `https://web3.okx.com${requestPath}${queryString}`, { method: "GET", headers } ); if (!response.ok) { throw new Error(`Failed to get quote: ${await response.text()}`); } const data = await response.json(); if (data.code !== "0" || !data.data?.[0]) { throw new Error("Failed to get token information"); } const Data = data.data[0] return Data } ``` ## 3. Process and sign transaction The transaction data here is obtained from the `/swap` endpoint. ```typescript async function executeSwap(txData: string, privateKey: string) { // Create transaction block const txBlock = Transaction.from(txData); txBlock.setSender(normalizedWalletAddress); // Set gas parameters const referenceGasPrice = await client.getReferenceGasPrice(); txBlock.setGasPrice(BigInt(referenceGasPrice)); txBlock.setGasBudget(BigInt(CONFIG.DEFAULT_GAS_BUDGET)); // Build and sign transaction const builtTx = await txBlock.build({ client }); const txBytes = Buffer.from(builtTx).toString('base64'); const signedTx = await wallet.signTransaction({ privateKey, data: { type: 'raw', data: txBytes } }); return signedTx; } ``` ## 4. Execute the transaction ```typescript const result = await client.executeTransactionBlock({ transactionBlock: builtTx, signature: [signedTx.signature], options: { showEffects: true, showEvents: true, } }); // Verify the transaction const confirmation = await client.waitForTransaction({ digest: result.digest, options: { showEffects: true, showEvents: true, } }); console.log("Transaction ID:", result.digest); console.log("Explorer URL:", `https://suiscan.xyz/mainnet/tx/${result.digest}`); ``` ## 5. Complete Implementation using typescript The following implementation provides a full-featured swap solution: ```typescript // swap.ts import { SuiWallet } from "@okxweb3/coin-sui"; import { getFullnodeUrl, SuiClient } from '@mysten/sui/client'; import { Transaction } from '@mysten/sui/transactions'; import cryptoJS from "crypto-js"; import dotenv from 'dotenv'; dotenv.config(); // Environment variables const apiKey = process.env.OKX_API_KEY; const secretKey = process.env.OKX_SECRET_KEY; const apiPassphrase = process.env.OKX_API_PASSPHRASE; const projectId = process.env.OKX_PROJECT_ID; const userAddress = process.env.WALLET_ADDRESS; const userPrivateKey = process.env.PRIVATE_KEY; // Constants const SUI_CHAIN_ID = "784"; const DEFAULT_GAS_BUDGET = 50000000; const MAX_RETRIES = 3; // Initialize clients const wallet = new SuiWallet(); const client = new SuiClient({ url: getFullnodeUrl('mainnet') }); // Normalize wallet address const normalizedWalletAddress = normalizeSuiAddress(userAddress); function getHeaders(timestamp: string, method: string, requestPath: string, queryString = "") { if (!apiKey || !secretKey || !apiPassphrase || !projectId) { throw new Error("Missing required environment variables"); } const stringToSign = timestamp + method + requestPath + queryString; return { "Content-Type": "application/json", "OK-ACCESS-KEY": apiKey, "OK-ACCESS-SIGN": cryptoJS.enc.Base64.stringify( cryptoJS.HmacSHA256(stringToSign, secretKey) ), "OK-ACCESS-TIMESTAMP": timestamp, "OK-ACCESS-PASSPHRASE": apiPassphrase, "OK-ACCESS-PROJECT": projectId, }; } async function getTokenInfo(fromTokenAddress: string, toTokenAddress: string) { const timestamp = new Date().toISOString(); const requestPath = "/api/v5/dex/aggregator/quote"; const params = { chainId: SUI_CHAIN_ID, fromTokenAddress, toTokenAddress, amount: "1000000", slippage: "0.5", }; const queryString = "?" + new URLSearchParams(params).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); const response = await fetch( `https://web3.okx.com${requestPath}${queryString}`, { method: "GET", headers } ); if (!response.ok) { throw new Error(`Failed to get quote: ${await response.text()}`); } const data = await response.json(); if (data.code !== "0" || !data.data?.[0]) { throw new Error("Failed to get token information"); } const quoteData = data.data[0]; return { fromToken: { symbol: quoteData.fromToken.tokenSymbol, decimals: parseInt(quoteData.fromToken.decimal), price: quoteData.fromToken.tokenUnitPrice }, toToken: { symbol: quoteData.toToken.tokenSymbol, decimals: parseInt(quoteData.toToken.decimal), price: quoteData.toToken.tokenUnitPrice } }; } function convertAmount(amount: string, decimals: number) { try { if (!amount || isNaN(parseFloat(amount))) { throw new Error("Invalid amount"); } const value = parseFloat(amount); if (value <= 0) { throw new Error("Amount must be greater than 0"); } return (BigInt(Math.floor(value * Math.pow(10, decimals)))).toString(); } catch (err) { console.error("Amount conversion error:", err); throw new Error("Invalid amount format"); } } async function main() { try { const args = process.argv.slice(2); if (args.length < 3) { console.log("Usage: ts-node swap.ts "); console.log("Example: ts-node swap.ts 1.5 0x2::sui::SUI 0xdba...::usdc::USDC"); process.exit(1); } const [amount, fromTokenAddress, toTokenAddress] = args; if (!userPrivateKey || !userAddress) { throw new Error("Private key or user address not found"); } // Get token information console.log("Getting token information..."); const tokenInfo = await getTokenInfo(fromTokenAddress, toTokenAddress); console.log(`From: ${tokenInfo.fromToken.symbol} (${tokenInfo.fromToken.decimals} decimals)`); console.log(`To: ${tokenInfo.toToken.symbol} (${tokenInfo.toToken.decimals} decimals)`); // Convert amount using fetched decimals const rawAmount = convertAmount(amount, tokenInfo.fromToken.decimals); console.log(`Amount in ${tokenInfo.fromToken.symbol} base units:`, rawAmount); // Get swap quote const quoteParams = { chainId: SUI_CHAIN_ID, amount: rawAmount, fromTokenAddress, toTokenAddress, slippage: "0.5", userWalletAddress: normalizedWalletAddress, }; // Get swap data const timestamp = new Date().toISOString(); const requestPath = "/api/v5/dex/aggregator/swap"; const queryString = "?" + new URLSearchParams(quoteParams).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); console.log("Requesting swap quote..."); const response = await fetch( `https://web3.okx.com${requestPath}${queryString}`, { method: "GET", headers } ); const data = await response.json(); if (data.code !== "0") { throw new Error(`API Error: ${data.msg}`); } const swapData = data.data[0]; // Show estimated output and price impact const outputAmount = parseFloat(swapData.routerResult.toTokenAmount) / Math.pow(10, tokenInfo.toToken.decimals); console.log("\nSwap Quote:"); console.log(`Input: ${amount} ${tokenInfo.fromToken.symbol} ($${(parseFloat(amount) * parseFloat(tokenInfo.fromToken.price)).toFixed(2)})`); console.log(`Output: ${outputAmount.toFixed(tokenInfo.toToken.decimals)} ${tokenInfo.toToken.symbol} ($${(outputAmount * parseFloat(tokenInfo.toToken.price)).toFixed(2)})`); if (swapData.priceImpactPercentage) { console.log(`Price Impact: ${swapData.priceImpactPercentage}%`); } console.log("\nExecuting swap transaction..."); let retryCount = 0; while (retryCount < MAX_RETRIES) { try { // Create transaction block const txBlock = Transaction.from(swapData.tx.data); txBlock.setSender(normalizedWalletAddress); // Set gas parameters const referenceGasPrice = await client.getReferenceGasPrice(); txBlock.setGasPrice(BigInt(referenceGasPrice)); txBlock.setGasBudget(BigInt(DEFAULT_GAS_BUDGET)); // Build and sign transaction const builtTx = await txBlock.build({ client }); const txBytes = Buffer.from(builtTx).toString('base64'); const signedTx = await wallet.signTransaction({ privateKey: userPrivateKey, data: { type: 'raw', data: txBytes } }); if (!signedTx?.signature) { throw new Error("Failed to sign transaction"); } // Execute transaction const result = await client.executeTransactionBlock({ transactionBlock: builtTx, signature: [signedTx.signature], options: { showEffects: true, showEvents: true, } }); // Wait for confirmation const confirmation = await client.waitForTransaction({ digest: result.digest, options: { showEffects: true, showEvents: true, } }); console.log("\nSwap completed successfully!"); console.log("Transaction ID:", result.digest); console.log("Explorer URL:", `https://suiscan.xyz/mainnet/tx/${result.digest}`); process.exit(0); } catch (error) { console.error(`Attempt ${retryCount + 1} failed:`, error); retryCount++; if (retryCount === MAX_RETRIES) { throw error; } await new Promise(resolve => setTimeout(resolve, 2000 * retryCount)); } } } catch (error) { console.error("Error:", error instanceof Error ? error.message : "Unknown error"); process.exit(1); } } if (require.main === module) { main(); } ``` ### Usage Example To execute a swap, run the script with the following parameters: ```bash npx ts-node swap.ts ``` For Example: ```bash # Example: Swap 1.5 SUI to USDC npx ts-node swap.ts 1.5 0x2::sui::SUI 0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC ``` This will return a response similar to the following: ```bash Getting token information... From: SUI (9 decimals) To: USDC (6 decimals) Amount in SUI base units: 1500000000 Swap Quote: Input: 1.5 SUI ($2.73) Output: 2.73 USDC ($2.73) Executing swap transaction... Signing transaction... Executing transaction... Swap completed successfully! Transaction ID: 5LncQyzK7YmcodcsQMYwnjYBAYBkKJAaS1XR2RLiCVyPyA5nwHjUNuSQos4VGk4CJm5spRPngdnv8cQYjYYwCAVu Explorer URL: https://suiscan.xyz/mainnet/tx/5LncQyzK7Ym ``` - [Build swap applications on the Ton network](https://web3.okx.com/onchainos/docs/waas/dex-use-swap-ton-quick-start.md) # Build swap applications on the Ton network ## Build single-chain applications In this guide, we’ll provide an example token swap through OKX DEX, using Ton from the Ton network to purchase JETTON. The process is as follows: 1. Set up your environment 2. Request the /quote endpoint and get the quote data 3. Request the /swap endpoint send the swap transaction ## 1. Set up your environment ```bash # --------------------- npm package --------------------- npm install @ton/ton @ton/crypto @ton/core buffer @orbs-network/ton-access ``` ```js const cryptoJS = require('crypto-js'); // Import encryption modules for subsequent encryption calculations const { TonClient, WalletContractV4, internal } = require("@ton/ton"); const { toNano, Cell } = require("@ton/core"); const { mnemonicToPrivateKey } = require("@ton/crypto"); const { getHttpEndpoint } = require("@orbs-network/ton-access"); // --------------------- environment variable --------------------- const apiBaseUrl = 'https://web3.okx.com/api/v5/dex/aggregator'; const chainId = '607'; // Native token contract address const fromTokenAddress = 'EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c'; // JETTON token contract address const toTokenAddress = 'EQAQXlWJvGbbFfE8F3oS8s87lIgdovS455IsWFaRdmJetTon'; // your wallet address const user = 'UQDoI2kiSNQZxxxxxxxxxxxx6lM2ZSxKkEw3k1' const fromAmount = '1000000' // user wallet private key const privateKey = 'xxxxx'; // open api Secret key const secretkey = 'xxxxx' // Get the current time const date = new Date(); // --------------------- util function --------------------- function getAggregatorRequestUrl(methodName, queryParams) { return apiBaseUrl + methodName + '?' + (new URLSearchParams(queryParams)).toString(); } // Check https://web3.okx.com/zh-hans/web3/build/docs/waas/rest-authentication for api-key const headersParams = { 'Content-Type': 'application/json', // The api Key obtained from the previous application 'OK-ACCESS-KEY': 'xxxxx', 'OK-ACCESS-SIGN': cryptoJS.enc.Base64.stringify( // The field order of headersParams should be consistent with the order of quoteParams. // example : quote ==> cryptoJS.HmacSHA256(date.toISOString() + 'GET' + '/api/v5/dex/aggregator/quote?amount=1000000&chainId=607&toTokenAddress=EQAQXlWJvGbbFfE8F3oS8s87lIgdovS455IsWFaRdmJetTon&fromTokenAddress=EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c', secretKey) cryptoJS.HmacSHA256(date.toISOString() + 'GET' + '/api/v5/dex/aggregator/xxx/xxx/xxx', secretKey) ), // Convert the current time to the desired format 'OK-ACCESS-TIMESTAMP': date.toISOString(), // The password created when applying for the key 'OK-ACCESS-PASSPHRASE': 'xxxxxxx', }; ``` **Additional receiving addresses aren’t supported.** ## 2. Request the /quote endpoint and get the quote data ### 2.1 Define quote parameters - Next, define the parameters to get basic information of the quote and the router list. ```js const quoteParams = { amount: fromAmount, chainId: chainId, toTokenAddress: toTokenAddress, fromTokenAddress: fromTokenAddress, }; ``` ### 2.2 Define helper functions - Define helper functions to interact with the DEX API. ```js const getQuote = async () => { const apiRequestUrl = getAggregatorRequestUrl('/quote', quoteParams); return fetch(apiRequestUrl, { method: 'get', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` ## 3. Request the /swap endpoint and sent transaction ### 3.1 Define swap parameters - Next, define the parameters of the swap, and get the tx information. ```js const swapParams = { chainId: 1, fromTokenAddress: 'fromTokenAddress', toTokenAddress: 'toTokenAddress', amount: '1000000', slippage: '0.03', userWalletAddress: user }; ``` ### 3.2 Define helper functions Define helper functions to interact with the DEX API ```js const getSwapData = async () => { const apiRequestUrl = getAggregatorRequestUrl('/swap', swapParams); return fetch(apiRequestUrl, { method: 'get', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` ### 3.3 Request the /swap endpoint and send the transaction ```js let tx = { "data": "te6cckEBBAEAwAABsA+KfqUAALgW1FkYQkBfXhAIAK3+NxydEq8Qc4csyQ7botOnBqxp3L54Fn7Zof9EjDx5ADoI2kiSNQZdnOIVsRSLrVMtiBySHg0Lt6lM2ZSxKkEwyC592wEBAZ8RMwAAAvrwgIALyzu3/eo7h8wFCa+0XsOg6z0IG/43fUuMnumWS8xS91AD0F/w35CTWUxTWRjefoV+400KRA2jX51X4ezIgmUUY/0AX5sDCAIBAQwDABgAAAABAAAAAAAAA+cKUcDO", "from": "UQDoI2kiSNQZdnOIVsRSLrVMtiBySHg0Lt6lM2ZSxKkEw3k1", "gas": "80234000", "gasPrice": "5000", "maxPriorityFeePerGas": "", "minReceiveAmount": "25062412", "to": "UQBXp1W7_UJWvsBrbaO8s-9i8O53s7hNNeZ0XqEEz12i0oDS", "value": "440000000" } // This is the response of the /swap endpoint async function sendTx() { const endpoint = await getHttpEndpoint(); const client = new TonClient({ endpoint }); const mnemonic = ['range', 'xxxxxx']; // Your mnemonic words Decimal conversion const keyPair = await mnemonicToPrivateKey(mnemonic); const wallet = WalletContractV4.create({workchain: 0, publicKey: keyPair.publicKey}); const contract = client.open(wallet) let seqno = await contract.getSeqno(); const body = Cell.fromBase64(tx.data); const value = tx.value / Math.pow(10, 9); // Decimal conversion const to = tx.to; await contract.sendTransfer({ seqno, secretKey: keyPair.secretKey, messages: [internal({ value: toNano(value), to, body: body, })] }); } ``` - [Build bridge applications](https://web3.okx.com/onchainos/docs/waas/dex-crosschain-api-quick-start-reference.md) # Build bridge applications - [Build bridge applications](https://web3.okx.com/onchainos/docs/waas/dex-use-crosschain-quick-start.md) # Build bridge applications In this guide, we’ll show you how to do a cross-chain swap using USDT on the Ethereum chain for USDC on the Arbitrum chain as an example provided by OKX DEX. This process includes: - Set up your environment - Check allowance - Check approval parameters and send the approved transaction - Get the toChainId list that can be traded through fromChainId, and select one of the chains as the destination chain - Get the token list through toChainId and select one of the tokens as the destination token - Request the /quote endpoint and get the quote data, also retrieving the bridge ID - Request the /build-tx endpoint and send the cross-chain swap transaction - Get the transaction status ## 1. Set up your environment Import the necessary Node.js libraries and set your environment variables as well as define helper functions and assembly parameters [Node.js Environment Settings](https://web3.okx.com/web3/build/docs/waas/nodejs-environment). ## 2. Check allowance ### Taking ETH chain as an example - `This demo is in JavaScript` 1. `Connect to an Ethereum node`: You need to ensure that you have connected to an available Ethereum node. You can use web3.js or other Ethereum development libraries to connect to the node. In the code, you need to specify the node's HTTP or WebSocket endpoint. 2. `Obtain a token contract instance`: Using the contract address and ABI of the token, you need to create an instance of the token contract. You can use the web3.eth.Contract in web3.js to achieve this. Pass the contract address and ABI as arguments to the contract instance. 3. `Query the authorized amount`: Query the authorized allowance by calling the allowance function of the contract instance. This function requires two parameters: the owner's address and the authorized party's address (spenderAddress). You can query the authorized allowance by providing these two addresses during the call. 4. The spenderAddress can refer to the dexTokenApproveAddress from [Here](https://web3.okx.com/web3/build/docs/waas/dex-get-supported-chains) in the Response interface.。 ```js const { Web3 } = require('web3'); // Connect to an Ethereum node const web3 = new Web3('https://xxxxx'); // token address and ABI const tokenAddress = '0xxxxxxxxx'; // user address const ownerAddress = '0xxxxxxxx'; // ETH dex token approval address const spenderAddress = '0x40aa958dd87fc8305b97f2ba922cddca374bcd7f'; const tokenABI = [ { "constant": true, "inputs": [ { "name": "_owner", "type": "address" }, { "name": "_spender", "type": "address" } ], "name": "allowance", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" } ]; // Create token contract instance const tokenContract = new web3.eth.Contract(tokenABI, tokenAddress); // Query token approve allowance function async function getAllowance(ownerAddress, spenderAddress) { try { const allowance = await tokenContract.methods.allowance(ownerAddress, spenderAddress).call(); console.log(`Allowance for ${ownerAddress} to ${spenderAddress}: ${allowance}`); } catch (error) { console.error('Failed to query allowance:', error); } } getAllowance(ownerAddress, spenderAddress).then(r => console.log(r)); ``` ### 2.2 Get allowance amount Get allowance amount. If allowanceAmount < fromTokenAmount, check out step 3. If allowanceAmount > fromTokenAmount, check out step 3 to increase the allowance amount, or go directly to step 4. ```js const { data: allowanceData } = await getAllowanceData(); const allowanceAmount = allowanceData?.[0]?.allowanceAmount; ``` ## 3. Check approval parameters and send the approved transaction Since allowanceAmount < fromTokenAmount, we need to approve this token. ### 3.1 Define approval parameters Next, define the parameters for the transaction approval you want to perform. ```js const getApproveTransactionParams = { chainId: fromChainId, tokenContractAddress: fromTokenAddress, userWalletAddress, approveAmount: fromTokenAmount, }; ``` ### 3.2 Define helper functions Define helper functions to interact with the DEX API. ```js const approveTransaction = async () => { const { apiRequestUrl, path } = getAggregatorRequestUrl( '/approve-transaction', getApproveTransactionParams ); return fetch(apiRequestUrl, { method: 'get', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` ### 3.3 Get the transaction approval tx and send the approved transaction ```js if (parseFloat(allowanceAmount) < parseFloat(fromTokenAmount)) { const { data } = await approveTransaction(allowanceAmount); let allowanceParams = { ...{ data: data[0].data }, // You can modify the data content you want in accordance with the Web3 official website }; const { rawTransaction } = await web3.eth.accounts.signTransaction( allowanceParams, privateKey ); await web3.eth.sendSignedTransaction(rawTransaction); } ``` ## 4. Get the toChainId list that can be traded through fromChainId, and select one of the chains as the destination chain ### 4.1 Define the parameters to get a tradable destination chain Next, define the parameters to get the tradable toChainId list through fromChainId. ```js const toChainListParams = { chainId: fromChainId, }; ``` ### 4.2 Define helper functions Define helper functions to interact with the DEX API. ```js const getSupportedChain = async () => { const { apiRequestUrl, path } = getCrossChainBaseUrl( '/supported/chain', toChainListParams ); return fetch(apiRequestUrl, { method: 'get', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` ### 4.3 Get the supported destination chains and select the Arbitrum chain. You can also select one of the other chains as the destination chain based on the list. ```js const { data: supportedChainList } = await getSupportedChain(); const selectChainItem = supportedChainList.find((item) => { return item.chainName === 'Arbitrum'; }); toChainId = selectChainItem?.chainId; ``` ## 5. Get the token list through toChainId, and select one of the tokens as the destination token ### 5.1 Define the parameters for getting a list of tradable destination tokens Next, define the parameters to get a list of tradable tokens through toChainId. ```js const toChainTokenListParams = { chainId: toChainId, }; ``` ### 5.2 Define helper functions Define helper functions to interact with the DEX API. ```js const getToChainTokenList = async () => { const { apiRequestUrl, path } = getAggregatorRequestUrl( '/all-tokens', toChainTokenListParams ); return fetch(apiRequestUrl, { method: 'get', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` ### 5.3 Get the tradable token list and select USDC. You can also select another token as the destination token. ```js const { data: toChainTokenList } = await getToChainTokenList(); const selectToChainToken = toChainTokenList.find((item) => { return item.tokenSymbol === 'USDC'; }); toTokenAddress = selectToChainToken?.tokenContractAddress; ``` ## 6. Request the /quote endpoint and get the quote data, also retrieving the bridge ID ### 6.1 Define quote parameters Next, define the parameters to get basic information of the quote and the router list. ```js const quoteParams = { fromChainId, toChainId, fromTokenAddress, toTokenAddress, amount: fromTokenAmount, slippage, }; ``` ### 6.2 Define helper functions Define helper functions to interact with the DEX API. ```js const getQuote = async () => { const { apiRequestUrl, path } = getCrossChainBaseUrl('/quote', quoteParams); return fetch(apiRequestUrl, { method: 'get', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` ### 6.3 Get the quote information and select a router as the transaction router ```js const { data: quoteData } = await getQuote(); bridgeId = quoteData[0]?.routerList[0]?.router?.bridgeId; ``` ## 7. Request the /build-tx endpoint and send the cross-chain swap transaction ### 7.1 Define cross-chain swap parameters Next, define the parameters to get the tx information of the cross-chain swap. ```js const swapParams = { fromChainId: fromChainId, toChainId: toChainId, fromTokenAddress, toTokenAddress, amount: fromTokenAmount, slippage, userWalletAddress, bridgeId, }; ``` ### 7.2 Define helper functions Define helper functions to interact with the DEX API. ```js const getSwapData = async () => { const { apiRequestUrl, path } = getCrossChainBaseUrl('/build-tx', swapParams); return fetch(apiRequestUrl, { method: 'get', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` ### 7.3 Request the /build-tx endpoint to get the tx information and send the cross-chain swap transaction ```js const { data: swapData } = await getSwapData(); const swapDataTxInfo = swapData[0].tx; const nonce = await web3.eth.getTransactionCount(userWalletAddress, 'latest'); // You can obtain the latest nonce and process the hexadecimal numbers starting with 0x according to your needs let signTransactionParams = { data: swapDataTxInfo.data, gasPrice: swapDataTxInfo.gasPrice, to: swapDataTxInfo.to, value: swapDataTxInfo.value, nonce, }; const { rawTransaction } = await web3.eth.accounts.signTransaction( signTransactionParams, privateKey ); const chainTxInfo = await web3.eth.sendSignedTransaction(rawTransaction); transactionTx = chainTxInfo; ``` ## 8. Get the transaction status ### 8.1 Define query parameters Next, define the parameters, mainly the source chain hash address. ```js const getCheckStatusParams = { hash: transactionTx, }; ``` ### 8.2 Define helper functions Define helper functions to interact with the DEX API. ```js const checkTransactionStatus = async () => { const { apiRequestUrl, path } = getCrossChainBaseUrl( '/status', getCheckStatusParams ); return fetch(apiRequestUrl, { method: 'get', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` ### 8.3 Get the transaction status You can also add a polling method to get order status in real time. Here is an example of a single query. ```js const { data: statusInfo } = await checkTransactionStatus(); console.log(statusInfo?.data[0]?.detailStatus); ``` - [Send multi-signature transactions on the Solana chain](https://web3.okx.com/onchainos/docs/waas/dex-use-crosschain-solana-quick-start.md) # Send multi-signature transactions on the Solana chain ```js import * as anchor from '@coral-xyz/anchor' import { base64, bs58 } from '@coral-xyz/anchor/dist/cjs/utils/bytes'; async function sendtx() { const connection = new anchor.web3.Connection( anchor.web3.clusterApiUrl("mainnet-beta") // "https://solana-mainnet.g.alchemy.com/v2/EiyeW_PJ3a0Yig7E61nZHpfbMapVbV4m" ) const keypair = anchor.web3.Keypair.fromSecretKey( bs58.decode("YOUR_USER_KEYPAIR") ) // user’s wallet private key const wallet = new anchor.Wallet(keypair) const provider = new anchor.AnchorProvider( connection, wallet ); console.log(wallet.publicKey.toString()) let json = { "data": "hEFh3sGCFQKmLrMKDhDzr623WrtzawSrzHmtCqquGT2rX63Eh1bxU6UQJRT8WK1DqNJDA2hVvNvm3hpPCbkStRBs9qooQzUP5BSZJMqKGUxFPv5PT1p1kMNCvCc68jL1JQdsPNdhAFHaZa5UcEobMW62DeXorNgf74rCCYcYmH8Jd5TDQjE5Njp94iAqj12fv6WrWUSfHBZvRyrp4HxCUM55UfESi8d1tvFeVBGHXXn1kUdJPaUm4nia2WFxeaKS3RnrTwQeTfHSGK7j1sHvg1k5JStZQxZWaBi58tE7g4RWcEiuYedBKCGT4fjeNxCi8rBfsSk34QNSoRxxQpmayEzCMBFtMgwbpjXR3a1RuQHTBaEtpoUYaRoHtwHbLJ1C6eKBWULEyAxu1gQ8VmCQwh8qZHtuKBeamFGJxH2GK5mQ7rRftHXFhiTpPBfQHcYsFvZP73STDMGA6EMXFb5VKenocr6dG1tcxm4m4VbEiovqTuma6goegYMPA1RJV3fuVRqU4ZyD1AhiGGZyWCHpMpyjsRgFx65k51QBLZzNtmydPfTWnzPCPjYR5EYWsnNy2jGrj1RRTdKNryEE7S1DPB9hh5eHT6qchGyHEpi9WnzV2EntQqzuWz6u9DMVEt1n27ZeK7AcLRjyherRr5v4UvceZZf8ESqPo7Z2CZaMHYqfw463RLBjB5tLsWDR6hMv8RfSnEAy6dMEKkw4zm8h5Gp2JZTHX4ddo7Ag8TNhZkAzkGYk9GAbVKDooNTmVHD8kzQudj4dSCUAebJM7sgapVvbp2ucg7v6TUZvWUUwfvzUiCfxqTxP2z3cxrKmpwkffNZpsE5NnzVxvieGxQLFJqCUfk2eAct3XY6bFr6EkP5n6w8EDo399d3G2J7ohRDt9psCY9YZrgDY2JAYhLp2vGwApkhrfAPwK5voamxXuoghwkQcTmcK3MdU1A8gTH3jhxbFqEom4pmMKbgYaESEnSJpB2wsd1KdDwZjjoHB4HLFMH7fod6FZuH2VMfyjhoHLYEBWuq4DXid9RmWwsazH9qHyNpY4napPvxFcn2hGGtWzav3CMHCFHsz58wtg7ZzmF3yMS6KvGJq2UtqHfBCSd7xMJJPEmKHnftyUtGx23cL4f4J1NyHzwARqo9SFqrZHBVFwaKGAZn3666D9SUt3f6ukGEGDmBnkoK4N9bBpVrdb4zdbRoAPf59wWVCMZ4PHQtGrYYBbZ7omtG5s3BmZy41AxNaAaBEcnhxrzcthK2CqadxZtRooUkUnviWsrhyNH4Cu4xT8TTCJm7VuHsG3rkZSds3pGeMPkna2Ny8RsFtu4vhqQyhyvBzNbNo5ycoeaerFKaS87ny3kAXKzUDSyNFRqfFaoqwcu7fTtxvJgnyv5fLg1a3Ak9avNxKjfrZEc17n1Tq44Vtsbv9YsGjCLqTUEiAQMsvXC1WG6nbQ1DexwsyiUtxy7DcViG4bLQChhMvEM1AYP", "from": "Jk9fBdZBe83dsy5t8FWuk26LZhytWJCa7MXTqkiDEtF", "gasLimit": "622500", "gasPrice": "5000", "key": [ "5B7Q21z2B5o2D1WVpp3LXNFq4NbY2HsVRnWbLTtj3mAdbXnPQe2QvJtrizW8expLE91HbXypzrw8vJsAxm3nHTrW" ], "maxPriorityFeePerGas": "", "to": "AqwtzPZxUmM6KoDCm5ceC7kje4DB2bLPRjKVJ8njCjKx", "value": "28000000" } const keypair2 = anchor.web3.Keypair.fromSecretKey(bs58.decode(json.key[0])) // randomKeyAccount parameters const wallet2 = new anchor.Wallet(keypair2) let transaction = anchor.web3.VersionedTransaction.deserialize(Buffer.from(bs58.decode(json.data))) const { blockhash } = await connection.getLatestBlockhash(); transaction.message.recentBlockhash = blockhash transaction.sign([keypair, keypair2]) // Using randomKeyAccount and user’s wallet private key for multi-signature operations const txId = await connection.sendTransaction(transaction, {skipPreflight: false, maxRetries: 20}) console.log("txId: ", txId) } sendtx() ``` - [Build limit order applications](https://web3.okx.com/onchainos/docs/waas/dex-limit-order-quick-start.md) # Build limit order applications In this guide, we will provide an example token limit order through OKX DEX. This process includes: - Set up your environment - Check allowance - Create order - Cancel order ## 1. Set up your environment Import the necessary Node.js libraries and set your environment variables as well as define helper functions and assembly parameters [Node.js Environment Settings](https://web3.okx.com/web3/build/docs/waas/nodejs-environment). ## 2. Check allowance ### 2.1 Please refer to the tutorial [Get allowance](https://web3.okx.com/web3/build/docs/waas/dex-limit-order-get-allowance) - The variable allowanceAmount in the following text represents the actual allowance amount on the blockchain. ### 2.2 Get allowance amount Obtain the specific quantity. If `allowanceAmount !== '0'`, please check step 4. If `allowanceAmount === '0'`, please check step 5. ```js const { data: allowanceData } = await getAllowanceData(); const allowanceAmount = allowanceData?.[0]?.allowanceAmount; ``` ## 3. Create order If allowanceAmount is greater than zero, it indicates that the approval operation has been performed and the transaction can be directly sent. ### 3.1 Offline signature Structured signature using EIP712, the wallet will show the order structured content when signing. ```js const ethers = require('ethers'); // Build domain data const domainData = { name: 'OKX LIMIT ORDER', version: '2.0', chainId: 1, // The chainId of the ETH mainnet verifyingContract: '0x2ae8947FB81f0AAd5955Baeff9Dcc7779A3e49F2' // LimitOrder contract address }; // Define the limit order type const Order = [ { name: "salt", type: "uint256" }, { name: "makerToken", type: "address" }, { name: "takerToken", type: "address" }, { name: "maker", type: "address" }, { name: "receiver", type: "address" }, { name: "allowedSender", type: "address" }, { name: "makingAmount", type: "uint256" }, { name: "takingAmount", type: "uint256" }, { name: "minReturn", type: "uint256" }, { name: "deadLine", type: "uint256" }, { name: "partiallyAble", type: "bool" } ]; const orderData = { salt: 1702979522, makerToken: "0xdAC17F958D2ee523a2206206994597C13D831ec7", takerToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", maker: "0x5F73e69237eB5bA3544273D165907447bF6a0AA7", receiver: "0x5F73e69237eB5bA3544273D165907447bF6a0AA7", allowedSender: "0x0000000000000000000000000000000000000000", makingAmount: 1000000, takingAmount: 1000000, minReturn: 1000000, deadLine: 1703254942, partiallyAble: true } // Build EIP-712 messages const message = { domain: domainData, types: { Order }, value: orderData, }; // Create an Ethereum signature wallet const privateKey = ''; const wallet = new ethers.Wallet(privateKey); (async () => { // Calculate the EIP-712 orderHash const orderHash = ethers.utils._TypedDataEncoder.hash(message.domain, message.types, message.value); console.log("Order data:", orderData); console.log("Order Hash:", orderHash); // Sign the message with the privatekey const signature = await wallet._signTypedData( message.domain, message.types, message.value ); console.log("Order signature:", signature); })(); ``` ### 3.2 Define parameters ```js const limitOrderRequestParams = { orderHash, orderData, chainId, signature }; ``` ### 3.3 Create order ```js const resp = await fetch(apiBaseUrl +"/limit-order/save-order", { method: "POST", body: JSON.stringify(limitOrderRequestParams), headers: headersParams, }); ``` ## 4. Cancel order ```js const ethers = require('ethers'); // Example Limit Order Data const orderData = { salt: 1700110500, // random number salt as idempotent identifier , Current timestamp (millisecond value) makerToken: "0xMakerTokenAddress", //Address of makerToken takerToken: "0xTakerTokenAddress", //Address of takerToken maker: "0xMakerAddress", //Address of order signer receiver: "0xTakerAddress", //Default is zero address, and the recipient’s assets will be sent to the address of the limit order creator. If you set a value, the asset will be sent to the current address. allowedSender: "0xAllowedSender", //User-specified counterparty address makingAmount: 2000, //The number of a token to be sold takingAmount: 1000, //The number of a token to be bought minReturn: 950, //Minimum number of currencies to be cashed out for slippage control deadLine: 1700120500, //Order Timeout Timestamp partiallyAble: false //Whether to support partial transaction }; // Connecting to an Ethernet node const provider = new ethers.providers.JsonRpcProvider("https://mainnet.infura.io/v3/your_infura_project_id"); // Contract address and ABI const contractAddress = "0x2ae8947FB81f0AAd5955Baeff9Dcc7779A3e49F2"; // LimitOrder contract address const contractABI = [ { "inputs": [ { "components": [ { "internalType": "uint256", "name": "salt", "type": "uint256" }, { "internalType": "address", "name": "makerToken", "type": "address" }, { "internalType": "address", "name": "takerToken", "type": "address" }, { "internalType": "address", "name": "maker", "type": "address" }, { "internalType": "address", "name": "receiver", "type": "address" }, { "internalType": "address", "name": "allowedSender", "type": "address" }, { "internalType": "uint256", "name": "makingAmount", "type": "uint256" }, { "internalType": "uint256", "name": "takingAmount", "type": "uint256" }, { "internalType": "uint256", "name": "minReturn", "type": "uint256" }, { "internalType": "uint256", "name": "deadLine", "type": "uint256" }, { "internalType": "bool", "name": "partiallyAble", "type": "bool" } ], "internalType": "struct OrderLibV2.Order", "name": "_order", "type": "tuple" } ], "name": "cancelOrder", "outputs": [ { "internalType": "uint256", "name": "orderRemaining", "type": "uint256" }, { "internalType": "bytes32", "name": "orderHash", "type": "bytes32" } ], "stateMutability": "nonpayable", "type": "function" } ]; // Creating Contract Instances with Contract ABIs and Addresses const contract = new ethers.Contract(contractAddress, contractABI, provider); // Creating a wallet with a private key const privateKey = "your_private_key"; const wallet = new ethers.Wallet(privateKey, provider); // Cancel order async function cancelOrder(orderData) { const tx = await contract.connect(wallet).cancelOrder(orderData); await tx.wait; console.log("txhash:", tx.hash); } // Example of interaction (async () => { await cancelOrder(orderData); })(); ``` - [Swap API](https://web3.okx.com/onchainos/docs/waas/dex-aggregation.md) # Swap API - [API reference](https://web3.okx.com/onchainos/docs/waas/dex-api-reference.md) # API reference - [Get Supported Chains](https://web3.okx.com/onchainos/docs/waas/dex-get-aggregator-supported-chains.md) {/* api-page */} # Get Supported Chains Retrieve information on chains supported for single-chain exchanges. The request returns supported target chains for cross-chain transactions. ### Request URL GET `https://web3.okx.com/api/v5/dex/aggregator/supported/chain` ### Request Parameters | Parameter | Type | Required | Description | |---------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------| | chainId | String | No | Unique identifier for the chain.
If left empty ````, the response will return all supported chain information.
If a specific chain ID is provided, information for that chain will be returned, e.g., `1`: Ethereum. See more [here](./walletapi-resources-supported-networks). |
### Response Parameters | Parameter | Type | Description | |-----------------------|---------|----------------------------------------------------------------------------------------------------------------------------| | chainId | String | Unique identifier for the chain (e.g., `1`: Ethereum; see more [here](./walletapi-resources-supported-networks)). | | chainName | String | Chain name (e.g., `Optimism`). | | dexTokenApproveAddress | String | DEX authorization contract address; if no authorization has been made, this field will be empty. |
### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/supported/chain?chainId=1' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code":"0", "data":[ { "chainId":"1", "chainName":"Ethereum", "dexTokenApproveAddress": "0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f" }, ], "msg":"" } ```
- [Get tokens](https://web3.okx.com/onchainos/docs/waas/dex-get-tokens.md) {/* api-page */} # Get tokens It fetches a list of tokens. This interface returns a list of tokens that belong to major platforms or are deemed significant enough by OKX. However, you can still quote and swap other tokens outside of this list on OKX DEX. ### Request address GET `https://web3.okx.com/api/v5/dex/aggregator/all-tokens` ### Request param | Parameter | Type | Required | Description | |-----------|--------|----------|--------------------------------------------------------------------------------------------------------------------------| | chainId | String | Yes | Chain ID (e.g., `1` for Ethereum. See [Chain IDs](./walletapi-resources-supported-networks)) | ### Response param | Parameter | Type | The precision of tokens | |----------------------|--------|--------------------------| | decimals | String | The precision of tokens (e.g., `18`) | | tokenContractAddress | String | Token contract address (e.g., `0x382bb369d343125bfb2117af9c149795c6c65c50`) | | tokenLogoUrl | String | Token logo (e.g., `https://static.okx.com/cdn/wallet/logo/USDT-991ffed9-e495-4d1b-80c2-a4c5f96ce22d.png`) | | tokenName | String | Token full name (e.g., `Tether`) | | tokenSymbol | String | Token symbol (e.g., `USDT`) | ### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/all-tokens?chainId=1' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code": "0", "data": [ { "decimals": "18", "tokenContractAddress": "0x382bb369d343125bfb2117af9c149795c6c65c50", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/USDT-991ffed9-e495-4d1b-80c2-a4c5f96ce22d.png", "tokenName": "Tether", "tokenSymbol": "USDT" }, { "decimals": "18", "tokenContractAddress": "0xc946daf81b08146b1c7a8da2a851ddf2b3eaaf85", "tokenLogoUrl": "https://static.okx.com/cdn/explorer/okexchain/exchain_usdc.png", "tokenName": "USD Coin", "tokenSymbol": "USDC" }, { "decimals": "18", "tokenContractAddress": "0xdf54b6c6195ea4d948d03bfd818d365cf175cfc2", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/okb.png", "tokenName": "OKB", "tokenSymbol": "OKB" }, { "decimals": "18", "tokenContractAddress": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/okt.png", "tokenName": "OKTC", "tokenSymbol": "OKT" }, { "decimals": "18", "tokenContractAddress": "0x218c3c3d49d0e7b37aff0d8bb079de36ae61a4c0", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/BNB-20220308.png", "tokenName": "Binance Coin", "tokenSymbol": "BNB" }, { "decimals": "18", "tokenContractAddress": "0x332730a4f6e03d9c55829435f10360e13cfa41ff", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/BUSD-20220308.png", "tokenName": "Binance USD", "tokenSymbol": "BUSD" }, { "decimals": "18", "tokenContractAddress": "0xdcac52e001f5bd413aa6ea83956438f29098166b", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/eth_usdk.png", "tokenName": "USDK", "tokenSymbol": "USDK" } ], "msg": "" } ``` [//]: # () [//]: # (//移动端页面布局(注释迁移时忽略)) [//]: # () [//]: # (//下一行填写 API名称) [//]: # (# 获取币种列表) [//]: # () [//]: # (获取欧易DEX聚合器协议支持兑换的币种列表) [//]: # () [//]: # () [//]: # () [//]: # () [//]: # (### 请求地址) [//]: # (「GET」https://web3.okx.com/api/v5/dex/aggregator/all-tokens) [//]: # () [//]: # (### 请求参数) [//]: # (// 下方填写请求参数表格(如果存在path 和 query 则分别分点描述)) [//]: # () [//]: # (| 参数名 | 类型 | 是否必须 | 描述 |) [//]: # (|---------|--------|------|---------------------------------|) [//]: # (| chainId | String | 是 | 链 ID (如`1`: Ethereum,更多可查看数据字典) |) [//]: # () [//]: # () [//]: # () [//]: # (### 请求示例) [//]: # () [//]: # () [//]: # (//下方填写shell 代码) [//]: # () [//]: # (```shell) [//]: # (curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/all-tokens?chainId=1') [//]: # (```) [//]: # () [//]: # () [//]: # (//下方填写java 代码) [//]: # () [//]: # () [//]: # () [//]: # (//此区域可写其他补充性内容) [//]: # () [//]: # () [//]: # (### 响应参数) [//]: # (// 下方填写响应参数表格) [//]: # () [//]: # () [//]: # (### 响应示例) [//]: # () [//]: # () [//]: # () [//]: # () [//]: # (```json) [//]: # ({) [//]: # ( "code": "0",) [//]: # ( "data": [) [//]: # ( {) [//]: # ( "decimals": 18,) [//]: # ( "tokenContractAddress": "0xdf54b6c6195ea4d948d03bfd818d365cf175cfc2",) [//]: # ( "tokenLogoUrl": "https://static.coinall.ltd/cdn/wallet/logo/okb.png",) [//]: # ( "tokenName": "OKB",) [//]: # ( "tokenSymbol": "OKB") [//]: # ( },) [//]: # ( {) [//]: # ( "decimals": 6,) [//]: # ( "tokenContractAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7",) [//]: # ( "tokenLogoUrl": "https://static.coinall.ltd/cdn/wallet/logo/usdt.png",) [//]: # ( "tokenName": "Tether",) [//]: # ( "tokenSymbol": "USDT") [//]: # ( },) [//]: # ( {) [//]: # ( "decimals": 6,) [//]: # ( "tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",) [//]: # ( "tokenLogoUrl": "https://static.oklink.com/cdn/explorer/okexchain/exchain_usdc.png",) [//]: # ( "tokenName": "USD Coin",) [//]: # ( "tokenSymbol": "USDC") [//]: # ( },) [//]: # ( {) [//]: # ( "decimals": 18,) [//]: # ( "tokenContractAddress": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",) [//]: # ( "tokenLogoUrl": "https://static.coinall.ltd/cdn/wallet/logo/eth01.png",) [//]: # ( "tokenName": "Ethereum",) [//]: # ( "tokenSymbol": "ETH") [//]: # ( }) [//]: # ( ],) [//]: # ( "msg": "") [//]: # (}) [//]: # (```) [//]: # () [//]: # () [//]: # () [//]: # (//此区域可写其他补充性内容) [//]: # () [//]: # () [//]: # () [//]: # () - [Get liquidity sources](https://web3.okx.com/onchainos/docs/waas/dex-get-liquidity.md) {/* api-page */} # Get liquidity sources Get a list of liquidity that are available for swap in the OKX aggregation protocol. ### Request address GET `https://web3.okx.com/api/v5/dex/aggregator/get-liquidity` ### Request param | Parameter | Type | Required | Description | |-----------|--------|----------|--------------------------------------------------------------------------------------------------------------------------| | chainId | String | Yes | Chain ID (e.g., `1` for Ethereum. See [Chain IDs](./walletapi-resources-supported-networks)) | ### Response param | Parameter | Type | The precision of tokens | |----------------------|--------|--------------------------| | id | String | The id of liquidity (e.g., `34`) | | name | String | The name of liquidity (e.g., `Uniswap V2`) | | logo | String | Liquidity Logo URL (e.g., `https://static.okx.com/cdn/wallet/logo/UNI.png`) | ### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/get-liquidity?chainId=1' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code": "0", "data": [ { "id": "34", "logo": "https://static.okx.com/cdn/wallet/logo/UNI.png", "name": "Uniswap V2" }, { "id": "29", "logo": "https://static.okx.com/cdn/wallet/logo/SUSHI.png", "name": "SushiSwap" }, { "id": "47", "logo": "https://static.okx.com/cdn/explorer/dex/logo/Dex_DefiSwap.png", "name": "DeFi Swap" }, { "id": "49", "logo": "https://static.okx.com/cdn/wallet/logo/convxswap.png", "name": "Convergence" }, { "id": "48", "logo": "https://static.okx.com/cdn/wallet/logo/luaswap.png", "name": "LuaSwap" }, { "id": "40", "logo": "https://static.okx.com/cdn/wallet/logo/SHIB.png", "name": "ShibaSwap" }, { "id": "30", "logo": "https://static.okx.com/cdn/wallet/logo/pancake.png", "name": "PancakeSwap" }, { "id": "53", "logo": "https://static.okx.com/cdn/wallet/logo/UNI.png", "name": "Uniswap V3" }, { "id": "54", "logo": "https://static.okx.com/cdn/wallet/logo/balancer.png", "name": "Balancer V1" }, { "id": "51", "logo": "https://static.okx.com/cdn/wallet/logo/balancer.png", "name": "Balancer V2" }, { "id": "55", "logo": "https://static.okx.com/cdn/wallet/logo/Curve.png", "name": "Curve V1" }, { "id": "259", "logo": "https://static.okx.com/cdn/wallet/logo/Curve.png", "name": "Curve" }, { "id": "58", "logo": "https://static.okx.com/cdn/wallet/logo/Curve.png", "name": "Curve V2" }, { "id": "52", "logo": "https://static.okx.com/cdn/wallet/logo/bancor.png", "name": "Bancor" }, { "id": "59", "logo": "https://static.okx.com/cdn/wallet/logo/Kyber.png", "name": "Kyber" }, { "id": "81", "logo": "https://static.okx.com/cdn/wallet/logo/Synapse.png", "name": "Synapse" }, { "id": "83", "logo": "https://static.okx.com/cdn/wallet/logo/Wombat.png", "name": "Wombat" }, { "id": "80", "logo": "https://static.okx.com/cdn/wallet/logo/DODO.png", "name": "DODO" }, { "id": "82", "logo": "https://static.okx.com/cdn/wallet/logo/Shell.png", "name": "Shell" }, { "id": "88", "logo": "https://static.okx.com/cdn/wallet/logo/DODO.png", "name": "DODO V2" }, { "id": "264", "logo": "https://static.okx.com/cdn/wallet/logo/DODO.png", "name": "DODO V3" }, { "id": "91", "logo": "https://static.okx.com/cdn/wallet/logo/Smoothy.png", "name": "Smoothy" }, { "id": "92", "logo": "https://static.okx.com/cdn/wallet/logo/RadioShack.png", "name": "RadioShack" }, { "id": "90", "logo": "https://static.okx.com/cdn/wallet/logo/ORION.png", "name": "Orion" }, { "id": "89", "logo": "https://static.okx.com/cdn/wallet/logo/FraxFinance.png", "name": "FraxSwap" }, { "id": "99", "logo": "https://static.okx.com/cdn/wallet/logo/okb.png", "name": "OKX DEX" }, { "id": "28", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Hashflow.png", "name": "HashFlow" }, { "id": "101", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Swapr.png", "name": "Swapr" }, { "id": "351", "logo": "https://static.okx.com/cdn/wallet/logo/dex_DFX.png", "name": "DFX Finance V3" }, { "id": "104", "logo": "https://static.okx.com/cdn/wallet/logo/dex_bancor.png", "name": "Bancor V3" }, { "id": "105", "logo": "https://static.okx.com/cdn/wallet/logo/dex_PSM.png", "name": "PSM" }, { "id": "106", "logo": "https://static.okx.com/cdn/wallet/logo/balancer.png", "name": "Balancer" }, { "id": "108", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Verse.png", "name": "Verse" }, { "id": "110", "logo": "https://static.okx.com/cdn/wallet/logo/dex_1inch_limit_order.png", "name": "1inch Limit Order" }, { "id": "248", "logo": "https://static.okx.com/cdn/wallet/logo/okb.png", "name": "OKX Limit Order" }, { "id": "132", "logo": "https://static.okx.com/cdn/wallet/logo/dex_defiplaza.png", "name": "DefiPlaza" }, { "id": "114", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Swerve.png", "name": "Swerve" }, { "id": "113", "logo": "https://static.okx.com/cdn/wallet/logo/Kyber.png", "name": "Kyber Elastic" }, { "id": "131", "logo": "https://static.okx.com/cdn/wallet/logo/dex_defiplaza.png", "name": "StablePlaza" }, { "id": "130", "logo": "https://static.okx.com/cdn/wallet/logo/dex_0x_limit_order.png", "name": "0x Limit Order" }, { "id": "133", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Clipper.png", "name": "Clipper" }, { "id": "134", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Lido.png", "name": "Lido" }, { "id": "135", "logo": "https://static.okx.com/cdn/wallet/logo/dex_NOMISWAP.png", "name": "Nomiswap Stable" }, { "id": "136", "logo": "https://static.okx.com/cdn/explorer/dex/logo/solidly.png", "name": "Solidly" }, { "id": "215", "logo": "https://static.okx.com/cdn/wallet/logo/traderjoexyz.png", "name": "Trader Joe V2.1" }, { "id": "153", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Cafe_Swap.png", "name": "Cafe Swap" }, { "id": "141", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_ELK.png", "name": "ELK" }, { "id": "102", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Unifi.png", "name": "Unifi" }, { "id": "159", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_LINKSWAP.png", "name": "LINKSWAP" }, { "id": "160", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Sake_Swap.png", "name": "Sake Swap" }, { "id": "27", "logo": "https://static.okx.com/cdn/wallet/logo/Curve.png", "name": "Curve 3CRV" }, { "id": "202", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Aave.png", "name": "Aave V2" }, { "id": "230", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Aave.png", "name": "Aave V3" }, { "id": "199", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Compound.png", "name": "Compound" }, { "id": "266", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Compound.png", "name": "Compound V3" }, { "id": "184", "logo": "https://static.okx.com/cdn/wallet/logo/dex_logo_Frax.png", "name": "sfrxETH" }, { "id": "356", "logo": "https://static.okx.com/cdn/wallet/logo/dex_logo_Frax.png", "name": "sFRAX" }, { "id": "186", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Lido.png", "name": "stMatic" }, { "id": "200", "logo": "https://static.okx.com/cdn/wallet/logo/pancake.png", "name": "PancakeSwap V3" }, { "id": "203", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Rocketpool.png", "name": "RocketPool" }, { "id": "207", "logo": "https://static.okx.com/cdn/wallet/logo/dex_kronos.png", "name": "Kronos" }, { "id": "204", "logo": "https://static.okx.com/cdn/wallet/logo/dex_1inch_limit_order.png", "name": "1inch LP v1.1" }, { "id": "210", "logo": "https://static.okx.com/cdn/wallet/logo/Curve.png", "name": "Curve TNG" }, { "id": "330", "logo": "https://static.okx.com/cdn/wallet/logo/Curve.png", "name": "CurveNG" }, { "id": "214", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Mooniswap.png", "name": "Mooniswap" }, { "id": "213", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Integral.png", "name": "Integral" }, { "id": "218", "logo": "https://static.okx.com/cdn/wallet/logo/dex_Maverick.png", "name": "Maverick V1" }, { "id": "226", "logo": "https://static.okx.com/cdn/wallet/logo/Curve.png", "name": "Curve LLAMMA" }, { "id": "234", "logo": "https://static.okx.com/cdn/explorer/dex/logo/Dex_xSigma.png", "name": "xSigma" }, { "id": "239", "logo": "https://static.okx.com/cdn/explorer/dex/logo/Dex_Sushiswap_V3.png", "name": "Sushiswap V3" }, { "id": "257", "logo": "https://static.okx.com/cdn/explorer/dex/logo/Synthetix.png", "name": "Wrapped Synthetix" }, { "id": "262", "logo": "https://static.okx.com/cdn/explorer/dex/logo/solidly.png", "name": "Solidly V3" }, { "id": "265", "logo": "https://static.okx.com/cdn/explorer/dex/logo/SmarDex.png", "name": "SmarDex" }, { "id": "328", "logo": "https://static.okx.com/cdn/web3/dex/logo/sDai.png", "name": "sDai" }, { "id": "365", "logo": "https://static.okx.com/cdn/web3/dex/logo/Angle.png", "name": "Angle" }, { "id": "352", "logo": "https://static.okx.com/cdn/web3/dex/logo/Angle.png", "name": "Angle Stake" }, { "id": "258", "logo": "https://static.okx.com/cdn/wallet/logo/okb.png", "name": "OKX Pre Limit Order" }, { "id": "354", "logo": "https://static.okx.com/cdn/web3/dex/logo/Origin.png", "name": "Origin Wrapper" }, { "id": "355", "logo": "https://static.okx.com/cdn/web3/dex/logo/Origin.png", "name": "Origin" }, { "id": "368", "logo": "https://static.okx.com/cdn/wallet/logo/Dex_Aave.png", "name": "Bgd Aave Static" }, { "id": "379", "logo": "https://static.okx.com/cdn/web3/dex/logo/Unicly.png", "name": "Unicly" }, { "id": "394", "logo": "https://static.okx.com/cdn/web3/dex/logo/novabits.png", "name": "Novabits V3" } ], "msg": "" } ``` - [Approve transactions](https://web3.okx.com/onchainos/docs/waas/dex-approve-transaction.md) {/* api-page */} # Approve transactions According to the [ERC-20 standard ](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/), we need to make sure that the OKX router has permission to spend funds with the user's wallet before making a transaction. This API will generate the relevant data for calling the contract. ### Request address GET `https://web3.okx.com/api/v5/dex/aggregator/approve-transaction` ### Request param | Parameter | Type | Required | Description | |----------------------|--------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------| | chainId | String | Yes | Chain ID (e.g., `1` for Ethereum. See [Chain IDs](./walletapi-resources-supported-networks)) | | tokenContractAddress | String | Yes | Token contract address (e.g., `0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`) | | approveAmount | String | Yes | The amount of token that needs to be permitted (set in minimal divisible units, e.g., `1.00` USDT set as `1000000`, `1.00` DAI set as `1000000000000000000`) | ### Response param | Parameter | Type | Description | |--------------------|--------|----------------------------------------| | data | String | Call data | | dexContractAddress | String | The contract address of OKX DEX approve (e.g., `0x6f9ffea7370310cd0f890dfde5e0e061059dcfd9`) | | gasLimit | String | Gas limit (e.g., `50000`) | | gasPrice | String | Gas price in wei (e.g., `110000000`) | ### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/approve-transaction?chainId=1&tokenContractAddress=0x6f9ffea7370310cd0f890dfde5e0e061059dcfd9&approveAmount=1000000' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code": "0", "data": [ { "data": "0x095ea7b3000000000000000000000000c67879f4065d3b9fe1c09ee990b891aa8e3a4c2f00000000000000000000000000000000000000000000000000000000000f4240", "dexContractAddress": "0xc67879F4065d3B9fe1C09EE990B891Aa8E3a4c2f", "gasLimit": "50000", "gasPrice": "110000000" } ], "msg": "" } ``` - [Get quotes](https://web3.okx.com/onchainos/docs/waas/dex-get-quote.md) {/* api-page */} # Get quotes Get the best quote for a swap through OKX DEX. ### Request address GET `https://web3.okx.com/api/v5/dex/aggregator/quote` ### Request param | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chainId | String | Yes | Chain ID (e.g., `1` for Ethereum. See [Chain IDs](https://web3.okx.com/web3/build/docs/waas/wallet-supported-networks)) | | amount | String | Yes | The input amount of a token to be sold (set in minimal divisible units, e.g., 1.00 USDT set as 1000000, 1.00 DAI set as 1000000000000000000), you could get the minimal divisible units from [Tokenlist](https://web3.okx.com/web3/build/docs/waas/dex-get-tokens). | | fromTokenAddress | String | Yes | The contract address of a token to be sold (e.g., `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`) | | toTokenAddress | String | Yes | The contract address of a token to be bought (e.g., `0xa892e1fef8b31acc44ce78e7db0a2dc610f92d00`) | | dexIds | String | No | DexId of the liquidity pool for limited quotes, multiple combinations separated by `,` (e.g.,`1,50,180`, see liquidity list for more) | | directRoute | Boolean | No | The default setting is false. When enabled, Direct Routes restrict our routing to a single liquidity pool only. Currently, this feature is only active for Solana swaps. | | priceImpactProtectionPercentage | String | No | (Optional. The default is 90%.) The percentage (between 0 - 1.0) of the price impact allowed.

When the priceImpactProtectionPercentage is set, if the estimated price impact is above the percentage indicated, an error will be returned. For example, if PriceImpactProtectionPercentage = .25 (25%), any quote with a price impact higher than 25% will return an error.
This is an optional feature, and the default value is 0.9. When it’s set to 1.0 (100%), the feature will be disabled, which means that every transaction will be allowed to pass.
Note: If we’re unable to calculate the price impact, we’ll return null, and the price impact protection will be disabled. | | feePercent | String | No | The percentage of fromTokenAmount will be sent to the referrer's address, the rest will be set as the input amount to be sold. min percentage:0
max percentage:3
By configuring this parameter, you can obtain the final amount of `totoken` provided to the user after deducting the commission from `fromtoken`.
A maximum of two decimal places is allowed. If more decimals are entered, the system will automatically round up.|
### Response param | Parameter | Type | Description | |-----------------|--------|-------------------------------------------------------------------------------------------------------------------------------| | chainId | String |Chain ID (e.g., 1 for Ethereum. See [Chain IDs](./walletapi-resources-supported-networks)) | | ***dexRouterList*** | ***Array*** | ***Quote path data set*** | | fromTokenAmount | String | The input amount of a token to be sold (e.g., `500000000000000000000000`) | | toTokenAmount | String | The resulting amount of a token to be bought (e.g., `168611907733361`) | | tradeFee | String | Estimated network fee (USD) of the quote route | | estimateGasFee | String | Estimated gas consumption is returned in the smallest units of each chain, such as wei. | | router | String | One of the main paths for the token swap | | routerPercent | String | The percentage of assets handled by the main path (e.g., `5`) | | ***subRouterList*** | ***Array*** | ***DEX Router information*** | | ***dexProtocol*** | ***Array*** | ***Liquidity protocols used on the main path*** (e.g., `Verse`) | | percent | String | The percentage of assets handled by the protocol (e.g., `100`)| | dexName | String | The name of the liquidity protocol | | ***fromToken*** | ***Object*** | ***The information of a token to be sold*** | | tokenContractAddress | String | Token contract address (e.g., `0xa892e1fef8b31acc44ce78e7db0a2dc610f92d00`) | | tokenSymbol | String | Token symbol (e.g., `0xa892e1fef8b31acc44ce78e7db0a2dc610f92d00`) | | tokenUnitPrice | String | The token unit price returned by this interface is a general USD real time price based on data from on-chain sources. Note: This price is only a recommended price. For some special cases, the token unit price may be 'null' | | decimal | String | The decimal number defines the smallest unit into which a single currency token can be divided. For example, if the decimal number of a token is 8, it means that a single such token can be divided into 100,000,000 of its smallest units. ***Note: This parameter is for reference only. It may change due to reasons such as settings adjustments by the contract owner.*** | | isHoneyPot | Boolean | If the token is a honeypot token. `yes:true` `no:false ` | | taxRate | String | Token tax rate for selling: Applicable to tokens with configurable tax mechanisms (e.g., SafeMoon, SPL2022 tokens). Returns 0 for regular tokens without tax. The value ranges from 0 to 1, where 0.01 represents 1%. | | ***toToken*** | ***Object*** | ***The information of a token to be bought*** | | tokenContractAddress | String | Token contract address (e.g., `0xa892e1fef8b31acc44ce78e7db0a2dc610f92d00`) | | tokenSymbol | String | Token symbol (e.g., `0xa892e1fef8b31acc44ce78e7db0a2dc610f92d00`) | | tokenUnitPrice | String | The token unit price returned by this interface is a general USD price based on data from on-chain, exchange, and other third-party sources. Note: This price is only a recommended price. For some special cases, the token unit price may be 'null' | | decimal | String | The decimal number defines the smallest unit into which a single currency token can be divided. For example, if the decimal number of a token is 8, it means that a single such token can be divided into 100,000,000 of its smallest units. ***Note: This parameter is for reference only. It may change due to reasons such as settings adjustments by the contract owner.*** | | isHoneyPot | Boolean | If the token is a honeypot token. `yes:true` `no:false ` | | taxRate | String | Token tax rate for buying: Applicable to tokens with configurable tax mechanisms (e.g., SafeMoon, SPL2022 tokens). Returns 0 for regular tokens without tax. The value ranges from 0 to 1, where 0.01 represents 1%. | | ***quoteCompareList*** | ***Array*** | ***Comparison of quote routes*** | | dexName | String | DEX name of the quote route | | dexLogo | String | DEX logo of the quote route | | tradeFee | String | Estimated network fee (USD) of the quote route | | amountOut | String | Received amount of the quote route | | priceImpactPercentage | String | Percentage = (Received value – Paid value) / Paid value. The swap amount will affect the depth of the liquidity pool, causing a value difference. This percentage can be positive if the received value exceeds the paid value. |
### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/quote?amount=10000000000000000000&chainId=1&toTokenAddress=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48&fromTokenAddress=0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code": "0", "data": [ { "chainId": "1", "dexRouterList": [ { "router": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee--0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "routerPercent": "100", "subRouterList": [ { "dexProtocol": [ { "dexName": "Uniswap V3", "percent": "100" } ], "fromToken": { "decimal": "18", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "tokenSymbol": "WETH", "tokenUnitPrice": "3606.94" }, "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "tokenSymbol": "USDC", "tokenUnitPrice": "0.9999" } } ] } ], "estimateGasFee": "135000", "fromToken": { "decimal": "18", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", "tokenSymbol": "ETH", "tokenUnitPrice": "3606.94" }, "fromTokenAmount": "1000000000000000", "originToTokenAmount": "3608628", "priceImpactPercentage": "0.04", "quoteCompareList": [ { "amountOut": "35984", "dexLogo": "https://static.okx.com/cdn/wallet/logo/DODO.png", "dexName": "DODO", "tradeFee": "13.609993622490384" }, { "amountOut": "3586381", "dexLogo": "https://static.okx.com/cdn/wallet/logo/balancer.png", "dexName": "Balancer V1", "tradeFee": "16.319948104844664" }, { "amountOut": "3580447", "dexLogo": "https://static.okx.com/cdn/wallet/logo/UNI.png", "dexName": "Uniswap V1", "tradeFee": "8.018574649654157568" }, { "amountOut": "3585311", "dexLogo": "https://static.okx.com/cdn/web3/dex/logo/Fluid.png", "dexName": "Fluid", "tradeFee": "7.957841558644062204" }, { "amountOut": "3591031", "dexLogo": "https://static.okx.com/cdn/wallet/logo/balancer.png", "dexName": "Balancer V2", "tradeFee": "7.286766496997064" } ], "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "tokenSymbol": "USDC", "tokenUnitPrice": "0.9999" }, "toTokenAmount": "3608628", "tradeFee": "4.1057406791269083" } ], "msg": "" } ```
- [Get Solana swap instructions](https://web3.okx.com/onchainos/docs/waas/dex-solana-swap-instruction.md) {/* api-page */} # Get Solana swap instructions Obtain transaction instruction data for redemption or custom assembly in Solana. ### Request address GET `https://web3.okx.com/api/v5/dex/aggregator/swap-instruction` ### Request parameters | Parameter | Type | Required | Description | |----------------------------------|---------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | chainId | String | Yes | Chain ID (e.g., `1` for Ethereum. See [Chain ID List](./walletapi-resources-supported-networks) for more details.) | | amount | String | Yes | Token amount for the quote.
(The amount must include its precision. For example, exchanging 1.00 USDT requires inputting `1000000`, while exchanging 1.00 DAI requires `1000000000000000000`. Token precision can be obtained from the token list.) | | fromTokenAddress | String | Yes | Address of the token contract being swapped from (e.g., `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`). | | toTokenAddress | String | Yes | Address of the token contract being swapped to (e.g., `0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`). | | slippage | String | Yes | Slippage limit.
**Note:**
On Solana, the minimum is `0`, and the maximum must be less than `1`.
(e.g., `0.005` means a max slippage of `0.5%`, `1` means `100%`). | | userWalletAddress | String | Yes | User’s wallet address (e.g., `0x3f6a3f57569358a512ccc0e513f171516b0fd42a`). | | swapReceiverAddress | String | No | Recipient address for the purchased asset. If not set, the asset will be sent to the `userWalletAddress`. (e.g., `0x3f6a3f57569358a512ccc0e513f171516b0fd42a`). | | feePercent | String | No | Percentage of the `fromToken` or `toToken` amount sent to the referral address. Minimum: `0%`, Maximum: `3%`, supports up to two decimal places (e.g., input `1.326%`, but only `1.32%` will be used). | | fromTokenReferrerWalletAddress | String | No | Wallet address receiving the referral fee in `fromToken`.
**Must be used with `feePercent`**, and a single transaction can only apply **either `fromToken` or `toToken` referral fees**.

**Note:**
**Solana:** The referral address must hold some SOL for activation. | | toTokenReferrerWalletAddress | String | No | Wallet address receiving the referral fee in `toToken`.
**Must be used with `feePercent`**, and a single transaction can only apply **either `fromToken` or `toToken` referral fees**.

**Note:**
**Solana:** The referral address must hold some SOL for activation. | | dexIds | String | No | Restrict the quote to specific liquidity pools by `dexId`. Multiple IDs should be comma-separated (e.g., `1,50,180`. See liquidity list for more details). | | priceImpactProtectionPercentage | String | No | (Optional, default: `90%`) Allowed price impact percentage (between `0` and `1.0`).
If the estimated price impact exceeds the specified percentage, an error will be returned.
Example: If `priceImpactProtectionPercentage = 0.25 (25%)`, any quote exceeding `25%` price impact will return an error.

**This is an optional feature**, defaulting to `0.9`. Setting it to `1.0 (100%)` disables this protection, allowing all trades to proceed.

**Note:** If price impact cannot be calculated, it will return `null`, and this feature will be disabled. | | computeUnitPrice | String | No | Used for transactions on the Solana network and similar to gasPrice on Ethereum. This price determines the priority level of the transaction. The higher the price, the more likely that the transaction can be processed faster. | | computeUnitLimit | String | No | Used for transactions on the Solana network and analogous to gasLimit on Ethereum, which ensures that the transaction won’t take too much computing resource. |
### Response parameter | Parameter | Type | Description | |------------------------------------|-----------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | addressLookupTableAccount | Array | Address Lookup Table Account. A data structure in the Solana blockchain used to optimize the management and referencing of addresses in transactions. It allows developers to store a group of related addresses in a table and reference them in transactions via index values (instead of the full 32-byte address), significantly improving transaction efficiency and scalability. | | instructionLists | Array | Detailed transaction instruction information | | data | String | Instruction data | | accounts | Array | Instruction account information | | isSigner | Boolean | Whether the account is a signer | | isWritable | Boolean | Whether the account is writable | | pubkey | Boolean | Public key address of the account | | programId | String | Program ID for instruction execution |
### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/swap-instruction?chainId=501&amount=350000000&fromTokenAddress=11111111111111111111111111111111&toTokenAddress=Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB&slippage=0.4&userWalletAddress=FvUDkjR1STZ3c6g3DjXwLsiQ477t2HGH4LQ81xMKWJZk \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code": "0", "data": { "addressLookupTableAddresses": [ "EDDSpjZHrsFKYTMJDcBqXAjkLcu9EKdvrQR4XnqsXErH", "9YcB7FUV4cLxTtDWEf399ooy3idpfepeEhMqGihKDDwX", "4tbRdGdVvuSzWjFeJJYVMv2vvTpEhCdWbFmNZAnuxmtk" ], "instructionLists": [ { "data": "ApC+BgA=", "accounts": [], "programId": "ComputeBudget111111111111111111111111111111" }, { "data": "A08vKAAAAAAA", "accounts": [], "programId": "ComputeBudget111111111111111111111111111111" }, { "data": "AwAAAN22LW+lIkpOjB6e81eI68Mgzu7zEfkmh9QEBkCPOLG3DQAAAAAAAAAxNzM5MjU1OTc3NzU58B0fAAAAAAClAAAAAAAAAAbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCp", "accounts": [ { "isSigner": true, "isWritable": false, "pubkey": "FvUDkjR1STZ3c6g3DjXwLsiQ477t2HGH4LQ81xMKWJZk" }, { "isSigner": false, "isWritable": false, "pubkey": "9haFKThJYWEVA66mtxv7nTBWMHieQdnZpmLjvXAiS2zm" } ], "programId": "11111111111111111111111111111111" }, { "data": "AQ==", "accounts": [ { "isSigner": false, "isWritable": true, "pubkey": "9haFKThJYWEVA66mtxv7nTBWMHieQdnZpmLjvXAiS2zm" }, { "isSigner": false, "isWritable": false, "pubkey": "So11111111111111111111111111111111111111112" }, { "isSigner": false, "isWritable": false, "pubkey": "FvUDkjR1STZ3c6g3DjXwLsiQ477t2HGH4LQ81xMKWJZk" }, { "isSigner": false, "isWritable": false, "pubkey": "SysvarRent111111111111111111111111111111111" } ], "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" }, { "data": "AgAAAICT3BQAAAAA", "accounts": [ { "isSigner": true, "isWritable": true, "pubkey": "FvUDkjR1STZ3c6g3DjXwLsiQ477t2HGH4LQ81xMKWJZk" }, { "isSigner": false, "isWritable": true, "pubkey": "9haFKThJYWEVA66mtxv7nTBWMHieQdnZpmLjvXAiS2zm" } ], "programId": "11111111111111111111111111111111" }, { "data": "EQ==", "accounts": [ { "isSigner": false, "isWritable": true, "pubkey": "9haFKThJYWEVA66mtxv7nTBWMHieQdnZpmLjvXAiS2zm" } ], "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" }, { "data": "AQ==", "accounts": [ { "isSigner": true, "isWritable": true, "pubkey": "FvUDkjR1STZ3c6g3DjXwLsiQ477t2HGH4LQ81xMKWJZk" }, { "isSigner": false, "isWritable": true, "pubkey": "HwEh3U3E7aPRwXUhzes6wxX1kbSmKm85ugK6DXP5vgzf" }, { "isSigner": false, "isWritable": false, "pubkey": "FvUDkjR1STZ3c6g3DjXwLsiQ477t2HGH4LQ81xMKWJZk" }, { "isSigner": false, "isWritable": false, "pubkey": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" }, { "isSigner": false, "isWritable": false, "pubkey": "11111111111111111111111111111111" }, { "isSigner": false, "isWritable": false, "pubkey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" } ], "programId": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" }, { "data": "QUs/TOtbW4iAk9wUAAAAAIXrRQQAAAAAHVqQAgAAAAABAAAAgJPcFAAAAAABAAAAAgAAAAEAAAANAQAAAGQBAAAABQEAAABkTpgBAAAAAAA=", "accounts": [ { "isSigner": true, "isWritable": true, "pubkey": "FvUDkjR1STZ3c6g3DjXwLsiQ477t2HGH4LQ81xMKWJZk" }, { "isSigner": false, "isWritable": true, "pubkey": "9haFKThJYWEVA66mtxv7nTBWMHieQdnZpmLjvXAiS2zm" }, { "isSigner": false, "isWritable": true, "pubkey": "HwEh3U3E7aPRwXUhzes6wxX1kbSmKm85ugK6DXP5vgzf" }, { "isSigner": false, "isWritable": false, "pubkey": "So11111111111111111111111111111111111111112" }, { "isSigner": false, "isWritable": false, "pubkey": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" }, { "isSigner": false, "isWritable": false, "pubkey": "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo" }, { "isSigner": true, "isWritable": true, "pubkey": "FvUDkjR1STZ3c6g3DjXwLsiQ477t2HGH4LQ81xMKWJZk" }, { "isSigner": false, "isWritable": true, "pubkey": "9haFKThJYWEVA66mtxv7nTBWMHieQdnZpmLjvXAiS2zm" }, { "isSigner": false, "isWritable": true, "pubkey": "HjkGLCPnsMr4yP2Tmi1Uj7gV7Y2xDj2Npn9kYfVBYr2s" }, { "isSigner": false, "isWritable": true, "pubkey": "8gJ7UWboMeQ6z6AQwFP3cAZwSYG8udVS2UesyCbH79r7" }, { "isSigner": false, "isWritable": false, "pubkey": "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo" }, { "isSigner": false, "isWritable": true, "pubkey": "chM5ZB1uPZxvJJAK4D1Z4KHAYjWKvwuQTy6fFAeWQ1T" }, { "isSigner": false, "isWritable": true, "pubkey": "FGFaiYjXTVuLsKvzn6ueckraNTeqUGHeYqrQPQCpd7kH" }, { "isSigner": false, "isWritable": false, "pubkey": "So11111111111111111111111111111111111111112" }, { "isSigner": false, "isWritable": false, "pubkey": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" }, { "isSigner": false, "isWritable": true, "pubkey": "DoBNfRox1ZjEsZq6QPY4jpN8hN4Fu9JVkAxJQro164VR" }, { "isSigner": false, "isWritable": true, "pubkey": "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo" }, { "isSigner": false, "isWritable": false, "pubkey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" }, { "isSigner": false, "isWritable": false, "pubkey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" }, { "isSigner": false, "isWritable": false, "pubkey": "D1ZN9Wj1fRSUQfCjhvnu1hqDMT7hzjzBBpi12nVniYD6" }, { "isSigner": false, "isWritable": true, "pubkey": "6TWKYuLYtuJVtvfqnPEs1ZxFMRDGTKkQJgTa4Dv7CzQS" }, { "isSigner": false, "isWritable": true, "pubkey": "EMfT8Jw2M5fs691J6ycgTuggXRJ4uLfbCrqZYJXMXpdL" }, { "isSigner": false, "isWritable": true, "pubkey": "7VVeicGxT7XmwG4Sg25QVFRcAZDaBtGxT9d1CpByzGYN" }, { "isSigner": false, "isWritable": false, "pubkey": "5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h" }, { "isSigner": false, "isWritable": true, "pubkey": "HV1KXxWFaSeriyFvXyx48FqG9BoFbfinB8njCJonqP7K" }, { "isSigner": false, "isWritable": true, "pubkey": "HjkGLCPnsMr4yP2Tmi1Uj7gV7Y2xDj2Npn9kYfVBYr2s" }, { "isSigner": false, "isWritable": true, "pubkey": "HwEh3U3E7aPRwXUhzes6wxX1kbSmKm85ugK6DXP5vgzf" }, { "isSigner": false, "isWritable": false, "pubkey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" }, { "isSigner": false, "isWritable": true, "pubkey": "2EXiumdi14E9b8Fy62QcA5Uh6WdHS2b38wtSxp72Mibj" }, { "isSigner": false, "isWritable": false, "pubkey": "3uaZBfHPfmpAHW7dsimC1SnyR61X4bJqQZKWmRSCXJxv" }, { "isSigner": false, "isWritable": true, "pubkey": "4zbGjjRx8bmZjynJg2KnkJ54VAk1crcrYsGMy79EXK1P" }, { "isSigner": false, "isWritable": true, "pubkey": "5XkWQL9FJL4qEvL8c3zCzzWnMGzerM3jbGuuyRprsEgG" }, { "isSigner": false, "isWritable": true, "pubkey": "jfrmNrBtxnX1FH36ATeiaXnpA4ppQcKtv7EfrgMsgLJ" }, { "isSigner": false, "isWritable": true, "pubkey": "CDSr3ssLcRB6XYPJwAfFt18MZvEZp4LjHcvzBVZ45duo" }, { "isSigner": false, "isWritable": false, "pubkey": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin" }, { "isSigner": false, "isWritable": true, "pubkey": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS" }, { "isSigner": false, "isWritable": true, "pubkey": "37m9QdvxmKRdjm3KKV2AjTiGcXMfWHQpVFnmhtb289yo" }, { "isSigner": false, "isWritable": true, "pubkey": "AQKXXC29ybqL8DLeAVNt3ebpwMv8Sb4csberrP6Hz6o5" }, { "isSigner": false, "isWritable": true, "pubkey": "9MgPMkdEHFX7DZaitSh6Crya3kCCr1As6JC75bm3mjuC" }, { "isSigner": false, "isWritable": true, "pubkey": "H61Y7xVnbWVXrQQx3EojTEqf3ogKVY5GfGjEn5ewyX7B" }, { "isSigner": false, "isWritable": true, "pubkey": "9FLih4qwFMjdqRAGmHeCxa64CgjP1GtcgKJgHHgz44ar" }, { "isSigner": false, "isWritable": false, "pubkey": "FGBvMAu88q9d1Csz7ZECB5a2gbWwp6qicNxN2Mo7QhWG" } ], "programId": "6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma" }, { "data": "CQ==", "accounts": [ { "isSigner": false, "isWritable": true, "pubkey": "9haFKThJYWEVA66mtxv7nTBWMHieQdnZpmLjvXAiS2zm" }, { "isSigner": false, "isWritable": true, "pubkey": "FvUDkjR1STZ3c6g3DjXwLsiQ477t2HGH4LQ81xMKWJZk" }, { "isSigner": true, "isWritable": true, "pubkey": "FvUDkjR1STZ3c6g3DjXwLsiQ477t2HGH4LQ81xMKWJZk" } ], "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" } ] }, "msg": "" } ```
- [Swap](https://web3.okx.com/onchainos/docs/waas/dex-swap.md) {/* api-page */} # Swap Generate the data to call the OKX DEX router to execute a swap. In Uni v3 pools, the following scenario may occur:
If the liquidity for the desired token pair in the pool is depleted, the pool will only consume part of the payment token, leaving a remainder.
As a fully decentralized smart contract, the OKX DEX Router will automatically refund the remainder.
During your integration, please ensure compatibility with this scenario by configuring your contract to support token refunds, thereby ensuring a smooth user experience.
### Request address GET `https://web3.okx.com/api/v5/dex/aggregator/swap` ### Request param | Parameter | Type | Required | Description | |-------------------|--------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------| | chainId | String | Yes | Chain ID (e.g., `1` for Ethereum. See [Chain IDs](./walletapi-resources-supported-networks)) | | amount | String | Yes | The input amount of a token to be sold
(set in minimal divisible units, e.g., 1.00 USDT set as 1000000, 1.00 DAI set as 1000000000000000000), you could get the minimal divisible units from [Tokenlist](https://web3.okx.com/web3/build/docs/waas/dex-get-tokens). | | fromTokenAddress | String | Yes | The contract address of a token you want to send (e.g.,`0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`) | | toTokenAddress | String | Yes | The contract address of a token you want to receive (e.g.,`0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`) | | slippage | String | Yes | Slippage limit.

Note:
1. For EVM networks, the slippage setting has a minimum value of `0` and a maximum value of `1`.
2. For Solana, the slippage setting has a minimum value of `0` and a maximum value of less than `1`.
(For example: `0.005` means that the maximum slippage for this transaction is `0.5%`, while `1` means that the maximum slippage of this transaction is `100%`.) | | userWalletAddress | String | Yes | User's wallet address (e.g.,`0x3f6a3f57569358a512ccc0e513f171516b0fd42a`) | | swapReceiverAddress | String | No | Recipient address of a purchased token if not set, `userWalletAddress` will receive a purchased token (e.g.,`0x3f6a3f57569358a512ccc0e513f171516b0fd42a`) | | feePercent | String | No | The percentage of fromTokenAmount or toTokenAmount will be sent to the referrer’s address, the rest will be set as the input amount to be sold. `Min percentage: 0`. `Max percentage: 3`.
Maximum 2 decimal points. Longer sections will be automatically omitted. (E.g. 1.326% is the actual input, but the final calculation will only adopt 1.32%.)| | fromTokenReferrerWalletAddress | String | No | The wallet address to receive the commission fee from the `fromToken`.
When using the API, you need to configure the commission ratio using `feePercent`.
Each transaction can only choose commission from either the `fromToken` or the `toToken`.

Note:
1. For **EVM chains**: Transactions involving wrapped pairs, such as ETH and WETH, are not supported here.
2. For **Solana chain**: The commission address must have some SOL deposited in advance for activation. | | toTokenReferrerWalletAddress | String | No | The wallet address to receive the commission fee from the `toToken`.
When using the API, you need to configure the commission ratio using `feePercent`.
Each transaction can only choose commission from either the `fromToken` or the `toToken`.

Note:
1. For **EVM chains**: Transactions involving wrapped pairs, such as ETH and WETH, are not supported here.
2. For **Solana chain**: The commission address must have some SOL deposited in advance for activation. | enablePositiveSlippage | Boolean | No | The default setting is false. The positive slippage revenue will be sent to userWalletAddress in default. When enabled, the positive slippage revenue will be sent to the referrer’s address | | gaslimit | String | No | (Optional, The gas (in wei) for the swap transaction. If the value is too low to achieve the quote, an error will be returned | | gasLevel | String | No | (Optional, defaults to `average`) The target gas price level for the swap transaction,set to `average` or `fast` or `slow` | | dexIds | String | No | DexId of the liquidity pool for limited quotes, multiple combinations separated by `,` (e.g., `1,50,180`, see liquidity list for more) | | directRoute | Boolean | No | The default setting is false. When enabled, Direct Routes restrict our routing to a single liquidity pool only. Currently, this feature is only active for Solana swaps. | | priceImpactProtectionPercentage | String | No | (Optional. The default is 90%.) The percentage (between 0 - 1.0) of the price impact allowed.

When the priceImpactProtectionPercentage is set, if the estimated price impact is above the percentage indicated, an error will be returned. For example, if PriceImpactProtectionPercentage = .25 (25%), any quote with a price impact higher than 25% will return an error.
This is an optional feature, and the default value is 0.9. When it’s set to 1.0 (100%), the feature will be disabled, which means that every transaction will be allowed to pass.
Note: If we’re unable to calculate the price impact, we’ll return null, and the price impact protection will be disabled. | | callDataMemo | String | No | You can customize the parameters to be sent on the blockchain in callData by encoding the data into a 128-character 64-bytes hexadecimal string. For example, the string “0x...111” needs to keep the “0x” at its start. | | computeUnitPrice | String | No | Used for transactions on the Solana network and similar to gasPrice on Ethereum. This price determines the priority level of the transaction. The higher the price, the more likely that the transaction can be processed faster. | | computeUnitLimit | String | No | Used for transactions on the Solana network and analogous to gasLimit on Ethereum, which ensures that the transaction won’t take too much computing resource. | | autoSlippage | Boolean | No | Default is false. When set to true, the original slippage (if set) will be covered by the autoSlippage and the API will calculate and return auto slippage recommendations based on current market data. | | maxAutoSlippage | String | No | When autoSlippage is set to true, this value is the maximum auto slippage returned by the API. We recommend that users adopt this value to ensure risk control. |
### Response param | Parameter | Type | Description | |------------------|--------|---------------------------------------------------------------------------------------------------------------------------------------| | ***routerResult*** | ***Object*** | ***Quote path data*** | | chainId | String | Chain ID (e.g., `1` for Ethereum. See [Chain IDs](./walletapi-resources-supported-networks)) | | fromTokenAmount | String | The input amount of a token to be sold ( e.g.,`500000000000000000000000`) | | toTokenAmount | String | The resulting amount of a token to be bought ( e.g.,`168611907733361`) | | tradeFee | String | Estimated network fee (USD) of the quote route | | estimateGasFee | String | Estimated gas consumption is returned in the smallest units of each chain, such as wei. | | ***dexRouterList*** | ***Array*** | ***Quote path data set*** | | router | String | One of the main paths for the token swap | | routerPercent | String | The percentage of assets handled by the main path (e.g.,`5`) | | ***subRouterList*** | ***Array*** | ***Quote path sub data set*** | | ***dexProtocol*** | ***Array*** | ***Liquidity protocols used on the main path*** | | dexName | String | The name of the liquidity protocol (e.g.,`Verse`) | | percent | String | The percentage of assets handled by the protocol (e.g.,`100`) | | ***fromToken*** | ***Object*** | ***The information of a token to be sold*** | | tokenContractAddress | String | Token contract address (e.g.,`0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`) | | tokenSymbol | String | Token symbol (e.g.,`USDC`) | | tokenUnitPrice | String | The token unit price returned by this interface is a general USDis a general USD real time price based on data from on-chain sources. Note: This price is only a recommended price. For some special cases, the token unit price may be 'null' | | decimal | String | The decimal number defines the smallest unit into which a single currency token can be divided. For example, if the decimal number of a token is 8, it means that a single such token can be divided into 100,000,000 of its smallest units. ***Note: This parameter is for reference only. It may change due to reasons such as settings adjustments by the contract owner.*** | | isHoneyPot | Boolean | If the token is a honeypot token. `yes:true` `no:false ` | | taxRate | String | Token tax rate for selling: Applicable to tokens with configurable tax mechanisms (e.g., SafeMoon, SPL2022 tokens). Returns 0 for regular tokens without tax. The value ranges from 0 to 1, where 0.01 represents 1%. | | ***toToken*** | ***Object*** | ***The information of a token to be bought*** | | tokenContractAddress | String | Token contract address (e.g.,`0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`) | | tokenSymbol | String | Token symbol (e.g.,`USDC`) | | tokenUnitPrice | String | The token unit price returned by this interface is a general USD price based on data from on-chain, exchange, and other third-party sources. Note: This price is only a recommended price. For some special cases, the token unit price may be 'null' | | decimal | String | The decimal number defines the smallest unit into which a single currency token can be divided. For example, if the decimal number of a token is 8, it means that a single such token can be divided into 100,000,000 of its smallest units. ***Note: This parameter is for reference only. It may change due to reasons such as settings adjustments by the contract owner.*** | | isHoneyPot | Boolean | If the token is a honeypot token. `yes:true` `no:false ` | | taxRate | String | Token tax rate for buying: Applicable to tokens with configurable tax mechanisms (e.g., SafeMoon, SPL2022 tokens). Returns 0 for regular tokens without tax. The value ranges from 0 to 1, where 0.01 represents 1%. | | ***quoteCompareList*** | ***Array*** | ***Comparison of quote routes*** | | dexName | String | DEX name of the quote route | | dexLogo | String | DEX logo of the quote route | | tradeFee | String | Estimated network fee (USD) of the quote route | | amountOut | String | Received amount of the quote route | | priceImpactPercentage | String | Percentage = (Received value – Paid value) / Paid value. The swap amount will affect the depth of the liquidity pool, causing a value difference. This percentage can be positive if the received value exceeds the paid value. | | ***tx*** | ***Object*** | ***contract data model*** | | signatureData | ***Array*** | If this parameter is returned, it indicates that the transaction requires additional signing data. Developers should use this parameter as one of the inputs for the transaction signature and ensure it is correctly applied during the signing process. | | from | String | User's wallet address (e.g.,`0x3f6a3f57569358a512ccc0e513f171516b0fd42a`) | | gas | String | estimated amount of the gas limit, increase this value by 50% (e.g.,`1173250`) | | gasPrice | String | Gas price in wei (e.g.,`58270000000`) | | maxPriorityFeePerGas | String | EIP-1559: Recommended priority cost of gas per unit (e.g.,`500000000`) | | to | String | The contract address of OKX DEX router (e.g.,`0x3b3ae790Df4F312e745D270119c6052904FB6790`) | | value | String | The amount of native tokens (in wei) that will be sent to the contract address (e.g.,`0`) | | minReceiveAmount | String | The minimum amount of a token to buy when the price reaches the upper limit of slippage (e.g.,`900645839798`) | | data | String | Call data | | slippage | String | The value of current transaction slippage |
### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/swap?chainId=1&amount=10000000000000&toTokenAddress=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48&fromTokenAddress=0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee&slippage=0.05&userWalletAddress=0x6f9ffea7370310cd0f890dfde5e0e061059dcfb8' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code": "0", "data": [ { "routerResult": { "chainId": "1", "dexRouterList": [ { "router": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee--0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "routerPercent": "100", "subRouterList": [ { "dexProtocol": [ { "dexName": "Uniswap V3", "percent": "100" } ], "fromToken": { "decimal": "18", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "tokenSymbol": "WETH", "tokenUnitPrice": "3342.87" }, "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "tokenSymbol": "USDC", "tokenUnitPrice": "0.9995" } } ] } ], "estimateGasFee": "135000", "fromToken": { "decimal": "18", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", "tokenSymbol": "ETH", "tokenUnitPrice": "3342.87" }, "fromTokenAmount": "10000000000000", "priceImpactPercentage": "0.001", "quoteCompareList": [ { "amountOut": "32990", "dexLogo": "https://static.okx.com/cdn/wallet/logo/balancer.png", "dexName": "Balancer V1", "tradeFee": "44.32919149271585462" }, { "amountOut": "334", "dexLogo": "https://static.okx.com/cdn/wallet/logo/DODO.png", "dexName": "DODO", "tradeFee": "36.96825563599181972" }, { "amountOut": "33023", "dexLogo": "https://static.okx.com/cdn/wallet/logo/balancer.png", "dexName": "Balancer V2", "tradeFee": "19.79273863696907162" }, { "amountOut": "32980", "dexLogo": "https://static.okx.com/cdn/explorer/dex/logo/Dex_Sushiswap_V3.png", "dexName": "Sushiswap V3", "tradeFee": "15.70332982767794112" }, { "amountOut": "32964", "dexLogo": "https://static.okx.com/cdn/wallet/logo/SHIB.png", "dexName": "ShibaSwap", "tradeFee": "15.70332982767794112" } ], "toToken": { "decimal": "6", "isHoneyPot": false, "taxRate": "0", "tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "tokenSymbol": "USDC", "tokenUnitPrice": "0.9995" }, "toTokenAmount": "33474", "tradeFee": "4.3491690602723664" }, "tx": { "data": "0x0d5f0e3b00000000000000000001881f6f9ffea7370310cd0f890dfde5e0e061059dcfb8000000000000000000000000000000000000000000000000000009184e72a0000000000000000000000000000000000000000000000000000000000000007c3800000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001800000000000000000000000e0554a476a092703abdb3ef35c80e0d76d32939f", "from": "0x6f9ffea7370310cd0f890dfde5e0e061059dcfb8", "gas": "202500", "gasPrice": "32657616776", "maxPriorityFeePerGas": "2086453233", "minReceiveAmount": "31800", "signatureData": [ "" ], "to": "0x7D0CcAa3Fac1e5A943c5168b6CEd828691b46B36", "value": "10000000000000" } } ], "msg": "" } ```
- [Query Transaction Status](https://web3.okx.com/onchainos/docs/waas/dex-swap-history.md) {/* api-page */} # Query Transaction Status Query the final transaction status of a single-chain swap using `txhash`. ### Request URL GET `https://web3.okx.com/api/v5/dex/aggregator/history` ### Request Parameters | Parameter | Type | Required | Description | |--------------------|--------|----------|----------------------------------------------------------------------------------------------| | chainId | String | Yes | Chain ID (e.g., `1`: Ethereum, see [Chain ID List](./walletapi-resources-supported-networks)) | | txHash | String | Yes | Transaction hash for a swap initiated via OKX DEX API | | isFromMyProject | Boolean| No | Set `true` to check if the transaction is under the current API Key. Set `false` or omit to query any OKX DEX API transaction. | ### Response Parameters | Parameter | Type | Description | |---------------------|---------|-----------------------------------------------------------------------------| | chainId | String | Unique identifier of the chain (e.g., 1: Ethereum, see Chain ID List). | | txHash | String | Transaction hash. | | height | String | Block height where the transaction occurred. | | txTime | String | Transaction time in Unix timestamp (milliseconds). | | status | String | Transaction status: `pending` (In Progress), `success` (Success), `failure` (Failure). | | txType | String | Transaction action: `Approve`, `Wrap`, `Unwrap`, `Swap`. | | fromAddress | String | Sender's address. | | dexRouter | String | Interaction address. | | toAddress | String | Receiver's address. | | fromTokenDetails | Array | Details of the token being swapped. | | >symbol | String | Symbol of the token being swapped. | | >amount | String | Swap amount in the smallest unit (e.g., wei for Ethereum). | | >tokenAddress | String | Contract address of the token being swapped (e.g., `0xEeeeeEeeeEeEee...`). | | toTokenDetails | Array | Details of the token received in the swap. | | >symbol | String | Symbol of the token received. | | >amount | String | Amount received in the smallest unit. | | >tokenAddress | String | Contract address of the received token (e.g., `0xa0b86991c6218b36...`). | | referalAmount | String | Referral fee amount. | | errorMsg | String | Error message. | | gasLimit | String | Gas limit for the transaction. | | gasUsed | String | Gas used in the transaction, in the smallest unit (e.g., wei). | | gasPrice | String | Gas price in the smallest unit (e.g., wei). | | txFee | String | Transaction fee, in the main chain currency. | ### Request Example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/history?chainId=784&txHash=5GePcvqEakoUtArW8PHULDSQds95vcgeiTznvbnb8hCV' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code": "0", "data": { "chainId": "784", "dexRouter": "0x51159f25f262ae01e87532b673de3b38df8f0ecc2dc0581f1033df6b84b84955", "errorMsg": "", "fromAddress": "0x4b9df646075d8621e2578f14818427e4c708709744ea3b827136056f85f88da7", "fromTokenDetails": { "amount": "892919000000.000", "symbol": "HIPPO", "tokenAddress": "0x8993129d72e733985f7f1a00396cbd055bad6f817fee36576ce483c8bbb8b87b::sudeng::SUDENG" }, "gasLimit": "", "gasPrice": "", "gasUsed": "", "height": "99502953", "referralAmount": "892919000", "status": "success", "toAddress": "0x4b9df646075d8621e2578f14818427e4c708709744ea3b827136056f85f88da7", "toTokenDetails": { "amount": "1532443840.00000000", "symbol": "SUI", "tokenAddress": "0x2::sui::SUI" }, "txFee": "7976416", "txHash": "5GePcvqEakoUtArW8PHULDSQds95vcgeiTznvbnb8hCV", "txTime": "1736390263909", "txType": "swap" }, "msg": "" } ``` - [Adding Fees ](https://web3.okx.com/onchainos/docs/waas/dex-api-addfee.md) # Adding Fees The OKX DEX API supports configuring referral fees and fee-receiving addresses for token swaps You can extend the implementation to include fee parameters in your swap quotes and charge up to 3% per swap from your users. The OKX DEX API plans to take a certain percentage of the referral fee charged by you to your users. Currently the OKX DEX API charges no fees. Ton chain currently does not support commission splitting. ```json // Extended quoteParams with fee support const quoteParams = { chainId: SOLANA_CHAIN_ID, amount: rawAmount, fromTokenAddress, toTokenAddress, slippage: "0.5", userWalletAddress: userAddress, // Fee-related parameters fromTokenReferrerWalletAddress: "Your_REFERRER_WALLET_ADDRESS", // Optional: Referrer address for commissions based on fromToken toTokenReferrerWalletAddress: "REFERRER_WALLET", // Optional: Referrer address for commissions based on toToken feePercent: "1.5", // Optional: Commission percentage (0-3%, max 2 decimal points) } as Record; ``` Important Fee Configuration Notes: - The feePercent parameter must be between 0 and 3% - Maximum 2 decimal points are supported for feePercent E.g. 1.326% is the actual input, but the final calculation will only adopt 1.32% - For Solana , the commission address must have some SOL deposited for activation - Each transaction can only choose commission from either the fromToken or the toToken Example Usage with Fees: ```json // .. Previous code implementation // Get swap quote const quoteParams = { chainId: SOLANA_CHAIN_ID, amount: rawAmount, fromTokenAddress, toTokenAddress, slippage: "0.5", userWalletAddress: userAddress, // Additional Fee params fromTokenReferrerWalletAddress: "fee-recipient-wallet-address", feePercent: "1", // The wallet addresses to receive the commission fee (Each transaction can only choose commission from either the fromToken or the toToken) // toTokenReferrerWalletAddress: "fee-recipient-wallet-address", // fromTokenReferrerWalletAddress: "fee-recipient-wallet-address", } as Record; const timestamp = new Date().toISOString(); const requestPath = "/api/v5/dex/aggregator/swap"; const queryString = "?" + new URLSearchParams(quoteParams).toString(); const headers = getHeaders(timestamp, "GET", requestPath, queryString); const response = await fetch( `https://web3.okx.com${requestPath}${queryString}`, { method: "GET", headers } ); const data = await response.json(); // .. Continue code implementation ``` Command Line Usage with Fees: ```json # Example: Swap .01 SOL to USDC with 1.5% fee to referrer npx ts-node swap.ts .01 11111111111111111111111111111111 EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v --referrer YOUR_REFERRER_ADDRESS --fee 1.5 ``` Fee Calculation Example: For a trade of 100 USDC with a 1.5% fee: - Fee amount: 1.5 USDC (1.5% of 100 USDC) - Actual swap amount: 98.5 USDC - The fee (1.5 USDC) will be sent to the referrer address - [DEX-integration](https://web3.okx.com/onchainos/docs/waas/dex-integration.md) # DEX-integration To successfully integrate your DEX into the OKX Routing Engine, please follow the steps below: 1. Provide a DEX SDK compatible with the OKX DEX AMM Interface: We require a DEX SDK that is fully compatible with our AMM (Automated Market Maker) interface. This SDK will allow us to communicate with your DEX and integrate its functionalities, enabling liquidity provision and trade execution seamlessly on our platform. The SDK should be able to handle key functions like pricing, order matching, liquidity pool interaction, and trade execution. 2. Allow us to fork your SDK: In order to ensure long-term maintenance and support for our users, it’s important that we can fork your SDK. This means we need the ability to create our own version of the SDK for integration purposes. By doing so, we can: - Guarantee the stability of the SDK for our users. - Maintain and update the SDK independently, fixing potential bugs and addressing issues related to your DEX’s integration within our ecosystem. - Customize the SDK to meet our specific requirements and adapt it for performance optimization. 3. Follow the guide and example we provide: We will provide a detailed integration guide and example code to ensure smooth integration. This will help you understand the technical requirements and structure, making the process easier and faster. By adhering to this documentation, you ensure that your DEX SDK aligns with our platform’s needs and integration standards. By meeting these guidelines, we will be able to provide your DEX with reliable support and ensure that your liquidity is accessible through the OKX DEX Routing Engine. Currently, the interface only works for Solana-based DEXs. ## AMM Interface ```typescript use async_trait::async_trait; use solana_client::rpc_client::RpcClient; use solana_sdk::pubkey::Pubkey; use std::collections::HashMap; use std::error::Error; use tokio::sync::mpsc::Sender; pub mod raydium_clmm; // Other dex template // pub mod raydium_amm; // pub mod orca_amm; // ... #[async_trait] pub trait Dex: Send + Sync { // Return DEX Name fn dex_name(&self) -> String; // Return DEX Program ID fn dex_program_id(&self) -> Pubkey; // Quote function fn quote(&self, amount_in: f64, metadata: &PoolMetadata) -> f64; // fetch all the pool address fn fetch_pool_addresses(&self, client: &RpcClient) -> Vec; // monitor new pools and event changes async fn listen_new_pool_addresses( &self, client: &RpcClient, address_tx: Sender, ) -> Result<(), Box>; // To export quote parameters from the pool address fn fetch_pool_metadata(&self, client: &RpcClient, pool_address: &str) -> Option; } // abstract design for pool metadata #[derive(Clone)] pub struct PoolMetadata { pub pool_address: String, pub base_mint: String, pub quote_mint: String, pub base_reserve: Option, pub quote_reserve: Option, pub trade_fee: Option, pub extra: HashMap, } // Extended value types for pool #[derive(Clone)] pub enum PoolMetadataValue { String(String), Number(f64), Bool(bool), Array(Vec), Map(HashMap), } // Generic simplify HashMap access macro_rules! get_extra { ($metadata:expr, $key:expr, $variant:path) => { $metadata.extra.get($key).and_then(|v| match v { $variant(val) => Some(val.clone()), _ => None, }) }; } pub(crate) use get_extra; ``` ## An example of implementation based on Raydium CLMM ```typescript use async_trait::async_trait; use solana_client::rpc_client::RpcClient; use solana_sdk::{ pubkey::Pubkey, signature::Signature, commitment_config::CommitmentConfig, }; use std::collections::HashMap; use std::error::Error; use std::sync::{Arc, Mutex}; use tokio::sync::mpsc::Sender; use base58::{FromBase58, ToBase58}; use log::{info, error}; use tokio_tungstenite::{connect_async, tungstenite::protocol::Message}; use super::{Dex, PoolMetadata, get_extra}; // Raydium CLMM Program ID const PROGRAM_ID: &str = "CLMM9tUush29+wnRVN2QqohW5Ns5mYAPbXTRmbn6kYH"; // Global Mapping Table lazy_static::lazy_static! { static ref POOL_ADDRESS_MAP: Arc>> = Arc::new(Mutex::new(HashMap::new())); } // Raydium CLMM Pool Derived Account #[derive(Clone)] struct PoolDerivedAccounts { pool_address: String, base_mint: String, quote_mint: String, base_vault: String, quote_vault: String, fee_state: String, tick_array_current: String, tick_array_prev: String, tick_array_next: String, observation_state: String, } pub struct RaydiumCLMM; #[async_trait] impl Dex for RaydiumCLMM { fn dex_name(&self) -> String { "RaydiumCLMM".to_string() } fn dex_program_id(&self) -> Pubkey { Pubkey::from_str(PROGRAM_ID).unwrap() } fn quote(&self, amount_in: f64, metadata: &PoolMetadata) -> f64 { if amount_in <= 0.0 { return 0.0; } let fee_rate = metadata.trade_fee.unwrap_or(0.0); let amount_in_with_fee = amount_in * (1.0 - fee_rate); let mut remaining_in = amount_in_with_fee; let mut total_out = 0.0; let sqrt_price_x64 = get_extra!(metadata, "sqrt_price_x64", PoolMetadataValue::Number).unwrap_or(0.0); let tick_current_index = get_extra!(metadata, "tick_current_index", PoolMetadataValue::Number).unwrap_or(0.0) as i32; let tick_array = get_extra!(metadata, "tick_array", PoolMetadataValue::Array).unwrap_or(vec![]); if tick_array.is_empty() { return 0.0; } let current_price = sqrt_price_x64 / 2_f64.powi(64); let mut current_tick = tick_current_index; let mut ticks: Vec<(i32, f64)> = tick_array.iter() .filter_map(|v| match v { PoolMetadataValue::Map(m) => { let tick_index = get_extra!(m, "tick_index", PoolMetadataValue::Number)? as i32; let liquidity = get_extra!(m, "liquidity", PoolMetadataValue::Number)?; Some((tick_index, liquidity)) }, _ => None, }) .collect(); ticks.sort_by(|a, b| a.0.cmp(&b.0)); for (tick_index, liquidity) in ticks { if tick_index <= current_tick { continue; } let sqrt_price_lower = (1.0001_f64.powf(current_tick as f64)).sqrt(); let sqrt_price_upper = (1.0001_f64.powf(tick_index as f64)).sqrt(); let delta_sqrt_price = sqrt_price_upper - sqrt_price_lower; let max_amount_out = liquidity * delta_sqrt_price; let cost = max_amount_out * (sqrt_price_upper + sqrt_price_lower) / 2.0; if remaining_in >= cost { total_out += max_amount_out; remaining_in -= cost; current_tick = tick_index; } else { let fraction = remaining_in / cost; total_out += max_amount_out * fraction; remaining_in = 0.0; break; } if remaining_in <= 0.0 { break; } } total_out } fn fetch_pool_addresses(&self, client: &RpcClient) -> Vec { let program_id = self.dex_program_id(); let accounts = match client.get_program_accounts(&program_id) { Ok(accs) => accs, Err(e) => { error!("Failed to fetch {} pool addresses: {}", self.dex_name(), e); return Vec::new(); } }; let mut pool_addresses = Vec::new(); for (pubkey, account) in accounts { if account.owner != program_id { continue; } let data = account.data; if data.len() < 200 { continue; } let base_mint = data[0..32].to_base58(); let quote_mint = data[32..64].to_base58(); if base_mint.is_empty() || quote_mint.is_empty() { continue; } let discriminator = u64::from_le_bytes(data[0..8].try_into().unwrap()); if discriminator == 0 { continue; } let pool_address = pubkey.to_string(); pool_addresses.push(pool_address.clone()); if let Some(accounts) = self.derive_accounts_from_pool_address(client, &pool_address) { POOL_ADDRESS_MAP.lock().unwrap().insert(pool_address, accounts); } } pool_addresses } async fn listen_new_pool_addresses( &self, client: &RpcClient, address_tx: Sender, ) -> Result<(), Box> { let program_id = self.dex_program_id(); let ws_url = "wss://api.mainnet-beta.solana.com"; let (mut ws_stream, _) = connect_async(ws_url).await?; let subscribe_msg = format!( r#"{"jsonrpc":"2.0","id":1,"method":"logsSubscribe","params":["mentions","{}"]}"#, program_id ); ws_stream.send(Message::Text(subscribe_msg)).await?; while let Some(msg) = ws_stream.next().await { let msg = msg?; if let Message::Text(text) = msg { let log: serde_json::Value = serde_json::from_str(&text)?; if log.get("result").is_some() { continue; } let params = log.get("params").and_then(|p| p.get("result")).ok_or("No params")?; let tx_sig = params.get("signature").and_then(|s| s.as_str()).ok_or("No signature")?; let logs = params.get("logs").and_then(|l| l.as_array()).ok_or("No logs")?; let tx = client.get_transaction( &Signature::from_str(tx_sig)?, CommitmentConfig::confirmed(), )?; if tx.meta.is_some() && tx.meta.unwrap().err.is_some() { continue; } let log_str = logs.iter().filter_map(|l| l.as_str()).collect::>().join(" "); let account_keys = tx.transaction.message.account_keys; for (i, key) in account_keys.iter().enumerate() { if tx.transaction.message.is_writable(i) { let pool_address = self.find_pool_address_from_account(&key.to_string()); if pool_address.is_empty() && self.is_valid_pool_address(client, &key.to_string()) { if let Some(accounts) = self.derive_accounts_from_pool_address(client, &key.to_string()) { POOL_ADDRESS_MAP.lock().unwrap().insert(key.to_string(), accounts); info!("Detected new {} pool address: {}", self.dex_name(), key); address_tx.send(key.to_string()).await?; } } else if !pool_address.is_empty() { info!("Detected writable account affecting pool: {}, Pool: {}", tx_sig, pool_address); address_tx.send(pool_address).await?; } } } if log_str.contains("initialize") { if let Some(pool_address) = self.extract_new_pool_address(client, tx_sig) { if self.is_valid_pool_address(client, &pool_address) { if let Some(accounts) = self.derive_accounts_from_pool_address(client, &pool_address) { POOL_ADDRESS_MAP.lock().unwrap().insert(pool_address.clone(), accounts); info!("Detected new {} pool address: {}", self.dex_name(), pool_address); address_tx.send(pool_address).await?; } } } } } } Ok(()) } fn fetch_pool_metadata(&self, client: &RpcClient, pool_address: &str) -> Option { let derived_accounts = self.derive_accounts_from_pool_address(client, pool_address)?; let out = client.get_account_data(&Pubkey::from_str(pool_address).ok()?).ok()?; if out.len() < 200 { error!("Pool data too short for {}", pool_address); return None; } let base_reserve = self.get_vault_balance(client, &derived_accounts.base_vault); let quote_reserve = self.get_vault_balance(client, &derived_accounts.quote_vault); let fee_data = client.get_account_data(&Pubkey::from_str(&derived_accounts.fee_state).ok()?).ok()?; let fee_numerator = u64::from_le_bytes(fee_data[0..8].try_into().unwrap()); let fee_denominator = u64::from_le_bytes(fee_data[8..16].try_into().unwrap()); let trade_fee = if fee_denominator > 0 { Some(fee_numerator as f64 / fee_denominator as f64) } else { None }; let sqrt_price_x64 = u64::from_le_bytes(out[64..72].try_into().unwrap()); let tick_current_index = i32::from_le_bytes(out[72..76].try_into().unwrap()); let tick_array_data = client.get_account_data(&Pubkey::from_str(&derived_accounts.tick_array_current).ok()?).unwrap_or_default(); let mut tick_array = Vec::new(); if !tick_array_data.is_empty() { for i in (8..tick_array_data.len() - 12).step_by(12) { let tick_index = i32::from_le_bytes(tick_array_data[i..i+4].try_into().unwrap()); let liquidity = f64::from_le_bytes(tick_array_data[i+4..i+12].try_into().unwrap()) / 1_000_000.0; let mut tick_map = HashMap::new(); tick_map.insert("tick_index".to_string(), PoolMetadataValue::Number(tick_index as f64)); tick_map.insert("liquidity".to_string(), PoolMetadataValue::Number(liquidity)); tick_array.push(PoolMetadataValue::Map(tick_map)); } } let mut extra = HashMap::new(); extra.insert("sqrt_price_x64".to_string(), PoolMetadataValue::Number(sqrt_price_x64 as f64)); extra.insert("tick_current_index".to_string(), PoolMetadataValue::Number(tick_current_index as f64)); extra.insert("tick_array".to_string(), PoolMetadataValue::Array(tick_array)); Some(PoolMetadata { pool_address: pool_address.to_string(), base_mint: derived_accounts.base_mint, quote_mint: derived_accounts.quote_mint, base_reserve: Some(base_reserve), quote_reserve: Some(quote_reserve), trade_fee, extra, }) } } impl RaydiumCLMM { fn derive_accounts_from_pool_address(&self, client: &RpcClient, pool_address: &str) -> Option { let out = client.get_account_data(&Pubkey::from_str(pool_address).ok()?).ok()?; if out.len() < 200 { error!("Pool data too short for {}", pool_address); return None; } let base_mint = out[0..32].to_base58(); let quote_mint = out[32..64].to_base58(); let base_vault = out[96..128].to_base58(); let quote_vault = out[128..160].to_base58(); let fee_state = out[160..192].to_base58(); let tick_array_current_seed = format!("tick_array{}", pool_address); let tick_array_current = Pubkey::create_program_address( &[&tick_array_current_seed.as_bytes()], &Pubkey::from_str(PROGRAM_ID).unwrap(), ).ok()?.to_string(); let tick_array_prev_seed = format!("tick_array_prev{}", pool_address); let tick_array_prev = Pubkey::create_program_address( &[&tick_array_prev_seed.as_bytes()], &Pubkey::from_str(PROGRAM_ID).unwrap(), ).ok()?.to_string(); let tick_array_next_seed = format!("tick_array_next{}", pool_address); let tick_array_next = Pubkey::create_program_address( &[&tick_array_next_seed.as_bytes()], &Pubkey::from_str(PROGRAM_ID).unwrap(), ).ok()?.to_string(); let observation_state_seed = format!("observation_state{}", pool_address); let observation_state = Pubkey::create_program_address( &[&observation_state_seed.as_bytes()], &Pubkey::from_str(PROGRAM_ID).unwrap(), ).ok()?.to_string(); Some(PoolDerivedAccounts { pool_address: pool_address.to_string(), base_mint, quote_mint, base_vault, quote_vault, fee_state, tick_array_current, tick_array_prev, tick_array_next, observation_state, }) } fn find_pool_address_from_account(&self, account_address: &str) -> String { let map = POOL_ADDRESS_MAP.lock().unwrap(); for (pool_address, accounts) in map.iter() { if account_address == pool_address || account_address == &accounts.base_vault || account_address == &accounts.quote_vault || account_address == &accounts.tick_array_current || account_address == &accounts.tick_array_prev || account_address == &accounts.tick_array_next { return pool_address.clone(); } } String::new() } fn is_valid_pool_address(&self, client: &RpcClient, pool_address: &str) -> bool { let out = match client.get_account_data(&Pubkey::from_str(pool_address).unwrap()) { Ok(data) => data, Err(_) => return false, }; if out.len() < 200 { return false; } if Pubkey::from_str(&out.owner.to_string()).unwrap() != Pubkey::from_str(PROGRAM_ID).unwrap() { return false; } let base_mint = out[0..32].to_base58(); let quote_mint = out[32..64].to_base58(); if base_mint.is_empty() || quote_mint.is_empty() { return false; } let discriminator = u64::from_le_bytes(out[0..8].try_into().unwrap()); if discriminator == 0 { return false; } true } fn get_vault_balance(&self, client: &RpcClient, vault: &str) -> f64 { match client.get_token_account_balance(&Pubkey::from_str(vault).unwrap(), CommitmentConfig::confirmed()) { Ok(resp) => resp.ui_amount.unwrap_or(0.0), Err(_) => 0.0, } } fn extract_new_pool_address(&self, client: &RpcClient, tx_sig: &str) -> Option { let tx = client.get_transaction( &Signature::from_str(tx_sig).ok()?, CommitmentConfig::confirmed(), ).ok()?; for key in tx.transaction.message.account_keys { if key.is_writable() && !key.is_signer() { return Some(key.to_string()); } } None } } ``` - [Smart contract](https://web3.okx.com/onchainos/docs/waas/dex-smart-contract.md) # Smart contract The contract addresses of OKX DEX router and ABI ## Contract address The contract addresses of the DEX router and token approval may be subject to replacement due to contract upgrades. To ensure uninterrupted use of the API, we recommend using the contract addresses returned by the response parameters: `/approve-transaction` API and `/swap` API for approvals and transactions. ### DEX router The contract addresses of OKX DEX router.Ton and Solana chains do not require authorization. | Chain | DEX router address | |----------------|----------------------------------------------| | Ethereum | 0x3b3ae790Df4F312e745D270119c6052904FB6790 | | Solana | 6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma | | SUI | 0xe42ca2f16029c503d69b09467b4fc6d11af15b56453a8427f913fa5f92d375d8| | Tron | TCkwEw4NdkaTJ1atJg5jZ18NgtHfpzZTC5 | | Sonic | 0x4Efa4b8545a3a77D80Da3ECC8F81EdB1a4bda783 | | Ton | EQBjfOGw4Iq6FYZplhwZ5rRNb7Htac7WJh8g_eQcGTswxVqP | | zkSync Era | 0xb9061E38FeE7d30134F56aEf7117E2F6d1580666 | | Optimism | 0xf332761c673b59B21fF6dfa8adA44d78c12dEF09 | | Polygon | 0xA748D6573acA135aF68F2635BE60CB80278bd855 | | BNB Chain | 0x9333C74BDd1E118634fE5664ACA7a9710b108Bab | | OKC | 0xf6Aab105CB9e66e03CAD2c2F3f8558242593385c | | Avalanche C | 0x1daC23e41Fc8ce857E86fD8C1AE5b6121C67D96d | | Fantom | 0xf332761c673b59B21fF6dfa8adA44d78c12dEF09 | | Arbitrum | 0xf332761c673b59B21fF6dfa8adA44d78c12dEF09 | | Linea | 0x6b2C0c7be2048Daa9b5527982C29f48062B34D58 | | Conflux eSpace | 0x0112bc6fDB78345e612B862a6B388FfeB00E2320 | | Base | 0x6b2C0c7be2048Daa9b5527982C29f48062B34D58 | | Mantle | 0x6b2C0c7be2048Daa9b5527982C29f48062B34D58 | | Scroll | 0x6b2C0c7be2048Daa9b5527982C29f48062B34D58 | | Manta | 0x6b2C0c7be2048Daa9b5527982C29f48062B34D58 | | Metis | 0x6b2C0c7be2048Daa9b5527982C29f48062B34D58 | | Blast | 0x2E86f54943faFD2cB62958c3deed36C879e3E944 | | Zeta | 0x0DaB5A5294AfAae76Ce990993fC10b896A01DBd1 | | Polygon zkEvm | 0x6b2C0c7be2048Daa9b5527982C29f48062B34D58 | | Merlin | 0x127a986cE31AA2ea8E1a6a0F0D5b7E5dbaD7b0bE | | X Layer | 0x127a986cE31AA2ea8E1a6a0F0D5b7E5dbaD7b0bE | ### Token approval A list of smart contracts for ERC-20 token approval | Chain | Approval contract address | |----------------|--------------------------------------------| | Ethereum | 0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f | | Sonic | 0xd321ab5589d3e8fa5df985ccfef625022e2dd910 | | Tron | THRAE2VhGNAcvPKtT96AqyXtSQwhiU1XL8 | | zkSync Era | 0xc67879F4065d3B9fe1C09EE990B891Aa8E3a4c2f | | Optimism | 0x68D6B739D2020067D1e2F713b999dA97E4d54812 | | Polygon | 0x3B86917369B83a6892f553609F3c2F439C184e31 | | BNB Chain | 0x2c34A2Fb1d0b4f55de51E1d0bDEfaDDce6b7cDD6 | | OKC | 0x70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58 | | Avalanche C | 0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f | | Fantom | 0x70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58 | | Arbitrum | 0x70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58 | | Linea | 0x57df6092665eb6058DE53939612413ff4B09114E | | Conflux eSpace | 0x68D6B739D2020067D1e2F713b999dA97E4d54812 | | Base | 0x57df6092665eb6058DE53939612413ff4B09114E | | Mantle | 0x57df6092665eb6058DE53939612413ff4B09114E | | Scroll | 0x57df6092665eb6058DE53939612413ff4B09114E | | Manta | 0x57df6092665eb6058DE53939612413ff4B09114E | | Metis | 0x57df6092665eb6058DE53939612413ff4B09114E | | Blast | 0x5fD2Dc91FF1dE7FF4AEB1CACeF8E9911bAAECa68 | | Zeta | 0x03B5ACdA01207824cc7Bc21783Ee5aa2B8d1D2fE | | Polygon zkEvm | 0x57df6092665eb6058DE53939612413ff4B09114E | | Merlin | 0x8b773D83bc66Be128c60e07E17C8901f7a64F000 | | X Layer | 0x8b773D83bc66Be128c60e07E17C8901f7a64F000 | ## The Application Binary Interface of Contract (ABI) Please refer to: https://github.com/okx/OKX-DEX-Aggregator-ABI - [Error codes](https://web3.okx.com/onchainos/docs/waas/dex-error-code.md) # Error codes | Code | HTTP status | Message | | ----- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 0 | 200 | Succeeded | | 50011 | 429 | Rate limit reached. Please refer to API documentation and throttle requests accordingly | | 50014 | 400 | Parameter param0 cannot be empty | | 50026 | 500 | System error. Try again later | | 50103 | 401 | Request header "OK-ACCESS-KEY" cannot be empty | | 50104 | 401 | Request header "OK-ACCESS-PASSPHRASE" cannot be empty | | 50105 | 401 | Request header "OK-ACCESS-PASSPHRASE" incorrect | | 50106 | 401 | Request header "OK-ACCESS-SIGN" cannot be empty | | 50107 | 401 | Request header "OK-ACCESS-TIMESTAMP" cannot be empty | | 50111 | 401 | Invalid OK-ACCESS-KEY | | 50112 | 401 | Invalid OK-ACCESS-TIMESTAMP | | 50113 | 401 | Invalid signature | | 51000 | 400 | Parameter param0 error | | 80000 | 200 | Repeated request | | 80001 | 200 | CallData exceeds the maximum limit. Try again in 5 minutes. | | 80002 | 200 | Requested token Object count has reached the limit. | | 80003 | 200 | Requested native token Object count has reached the limit. | | 80004 | 200 | Timeout when querying SUI Object. | | 80005 | 200 | Not enough Sui objects under the address for swapping | | 82000 | 200 | Insufficient liquidity | | 82001 | 500 | The commission service is not available during the upgrade | | 82102 | 200 | Less than the minimum quantity limit,the minimum amount is 0 | | 82103 | 200 | Exceeds than the maximum quantity limit,the maximum amount is 0 | | 82104 | 200 | This token is not supported | | 82105 | 200 | This chain is not supported | | 82112 | 200 | The value difference from this transaction’s quote route is higher than num, which may cause asset loss,The default value is 90%. It can be adjusted using the string priceImpactProtectionPercentage. | | 82116 | 200 | callData exceeds the maximum limit. Try again in 5 minutes. | | 82120 | 200 | Detected honeypot tokens or high-risk tokens with a 100% buy/sell tax. Transactions have been intercepted. | | 82130 | 200 | The chain does not require authorized transactions and can be exchanged directly. | - [FAQ](https://web3.okx.com/onchainos/docs/waas/dex-aggregation-faq.md) # FAQ ## What is the Native Token Address for Each Chain? We have defined the native tokens for each chain. Please refer to the table below for details: | Chain Name | Native Token Address | | |------------|----------------------------------------------------|------| | EVM | 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee | | | Solana | 11111111111111111111111111111111 | | | Sui | 0x2::sui::SUI | | | Tron | T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb | | | Ton | EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c | | - [Cross-chain API](https://web3.okx.com/onchainos/docs/waas/dex-crosschain-aggregator.md) # Cross-chain API - [API reference](https://web3.okx.com/onchainos/docs/waas/dex-crosschain-api.md) # API reference - [Get supported chains](https://web3.okx.com/onchainos/docs/waas/dex-get-supported-chains.md) {/* api-page */} # Get supported chains Get information from chains that support cross-chain transactions. Use a request to return a supported destination chain. ### Request address GET `https://web3.okx.com/api/v5/dex/cross-chain/supported/chain` ### Request param | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chainId | String | No | Unique identifier for the chain.
If left empty ````, the response will return all supported chain information.
If a specific chain ID is provided, information for that chain will be returned, e.g., `1`: Ethereum. See more [here](./walletapi-resources-supported-networks). |
### Response param | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | chainId | String| Unique identifier for the chain (e.g., `1`: Ethereum; see more [here](./walletapi-resources-supported-networks)). | | chainName | String | Chain name (e.g.,`Optimism`) | | dexTokenApproveAddress | String | dex token Approve Contract Address |
### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/cross-chain/supported/chain' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code": "0", "data": [ { "chainId": "137", "chainName": "Polygon", "dexTokenApproveAddress": "0x3B86917369B83a6892f553609F3c2F439C184e31" }, { "chainId": "195", "chainName": "TRON", "dexTokenApproveAddress": "THRAE2VhGNAcvPKtT96AqyXtSQwhiU1XL8" }, { "chainId": "43114", "chainName": "Avalanche C", "dexTokenApproveAddress": "0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f" }, { "chainId": "1", "chainName": "Ethereum", "dexTokenApproveAddress": "0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f" }, { "chainId": "66", "chainName": "OKTC", "dexTokenApproveAddress": "0x70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58" }, { "chainId": "56", "chainName": "BNB Chain", "dexTokenApproveAddress": "0x2c34A2Fb1d0b4f55de51E1d0bDEfaDDce6b7cDD6" }, { "chainId": "250", "chainName": "Fantom", "dexTokenApproveAddress": "0x70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58" }, { "chainId": "42161", "chainName": "Arbitrum", "dexTokenApproveAddress": "0x70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58" }, { "chainId": "10", "chainName": "Optimism", "dexTokenApproveAddress": "0x68D6B739D2020067D1e2F713b999dA97E4d54812" }, { "chainId": "25", "chainName": "Cronos", "dexTokenApproveAddress": "0x70cbb871e8f30fc8ce23609e9e0ea87b6b222f58" }, { "chainId": "501", "chainName": "Solana", "dexTokenApproveAddress": "" }, { "chainId": "324", "chainName": "zkSync Era", "dexTokenApproveAddress": "0xc67879F4065d3B9fe1C09EE990B891Aa8E3a4c2f" }, { "chainId": "1030", "chainName": "Conflux eSpace", "dexTokenApproveAddress": "0x68D6B739D2020067D1e2F713b999dA97E4d54812" }, { "chainId": "784", "chainName": "SUI", "dexTokenApproveAddress": "" }, { "chainId": "1101", "chainName": "Polygon zkEvm", "dexTokenApproveAddress": "0x57df6092665eb6058DE53939612413ff4B09114E" }, { "chainId": "59144", "chainName": "Linea", "dexTokenApproveAddress": "0x57df6092665eb6058DE53939612413ff4B09114E" }, { "chainId": "5000", "chainName": "Mantle", "dexTokenApproveAddress": "0x57df6092665eb6058DE53939612413ff4B09114E" }, { "chainId": "8453", "chainName": "Base", "dexTokenApproveAddress": "0x57df6092665eb6058DE53939612413ff4B09114E" }, { "chainId": "534352", "chainName": "Scroll", "dexTokenApproveAddress": "0x57df6092665eb6058DE53939612413ff4B09114E" }, { "chainId": "196", "chainName": "X Layer", "dexTokenApproveAddress": "0x8b773D83bc66Be128c60e07E17C8901f7a64F000" }, { "chainId": "169", "chainName": "Manta Pacific", "dexTokenApproveAddress": "0x57df6092665eb6058DE53939612413ff4B09114E" }, { "chainId": "1088", "chainName": "Metis", "dexTokenApproveAddress": "0x57df6092665eb6058DE53939612413ff4B09114E" }, { "chainId": "7000", "chainName": "Zeta", "dexTokenApproveAddress": "0x03B5ACdA01207824cc7Bc21783Ee5aa2B8d1D2fE" }, { "chainId": "4200", "chainName": "Merlin", "dexTokenApproveAddress": "0x8b773D83bc66Be128c60e07E17C8901f7a64F000" }, { "chainId": "81457", "chainName": "Blast", "dexTokenApproveAddress": "0x5fD2Dc91FF1dE7FF4AEB1CACeF8E9911bAAECa68" }, { "chainId": "607", "chainName": "TON", "dexTokenApproveAddress": "" } ], "msg": "" } ```
- [Get tokens](https://web3.okx.com/onchainos/docs/waas/dex-crosschain-get-tokens.md) {/* api-page */} # Get tokens List of source-chain tokens available for cross-chain swaps. ### Request address GET `https://web3.okx.com/api/v5/dex/aggregator/all-tokens` ### Request param | Parameter | Type | Required | Description | |-----------|--------|----------|--------------------------------------------------------------------------------------------------------------------------| | chainId | String | Yes | Chain ID (e.g., `1` for Ethereum. See [Chain IDs](https://web3.okx.com/web3/build/docs/waas/wallet-supported-networks)) | ### Response param | Parameter | Type | The precision of tokens | |----------------------|--------|--------------------------| | decimals | String | The precision of tokens (e.g., `18`) | | tokenContractAddress | String | Token contract address (e.g., `0x382bb369d343125bfb2117af9c149795c6c65c50`) | | tokenLogoUrl | String | Token logo (e.g., `https://static.okx.com/cdn/wallet/logo/USDT-991ffed9-e495-4d1b-80c2-a4c5f96ce22d.png`) | | tokenName | String | Token full name (e.g., `Tether`) | | tokenSymbol | String | Token symbol (e.g., `USDT`) | ### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/all-tokens?chainId=1' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code": "0", "data": [ { "decimals": "18", "tokenContractAddress": "0x382bb369d343125bfb2117af9c149795c6c65c50", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/USDT-991ffed9-e495-4d1b-80c2-a4c5f96ce22d.png", "tokenName": "Tether", "tokenSymbol": "USDT" }, { "decimals": "18", "tokenContractAddress": "0xc946daf81b08146b1c7a8da2a851ddf2b3eaaf85", "tokenLogoUrl": "https://static.okx.com/cdn/explorer/okexchain/exchain_usdc.png", "tokenName": "USD Coin", "tokenSymbol": "USDC" }, { "decimals": "18", "tokenContractAddress": "0xdf54b6c6195ea4d948d03bfd818d365cf175cfc2", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/okb.png", "tokenName": "OKB", "tokenSymbol": "OKB" }, { "decimals": "18", "tokenContractAddress": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/okt.png", "tokenName": "OKTC", "tokenSymbol": "OKT" }, { "decimals": "18", "tokenContractAddress": "0x218c3c3d49d0e7b37aff0d8bb079de36ae61a4c0", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/BNB-20220308.png", "tokenName": "Binance Coin", "tokenSymbol": "BNB" }, { "decimals": "18", "tokenContractAddress": "0x332730a4f6e03d9c55829435f10360e13cfa41ff", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/BUSD-20220308.png", "tokenName": "Binance USD", "tokenSymbol": "BUSD" }, { "decimals": "18", "tokenContractAddress": "0xdcac52e001f5bd413aa6ea83956438f29098166b", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/eth_usdk.png", "tokenName": "USDK", "tokenSymbol": "USDK" } ], "msg": "" } ``` - [Get the list of tokens supported by the cross-chain bridges](https://web3.okx.com/onchainos/docs/waas/dex-get-supported-tokens.md) {/* api-page */} # Get the list of tokens supported by the cross-chain bridges List of tokens available for traded directly across the cross-chain bridge. ### Request address GET `https://web3.okx.com/api/v5/dex/cross-chain/supported/tokens` ### Request param | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chainId | String | No | Chain ID (e.g., `1` for Ethereum. See [Chain IDs](https://web3.okx.com/web3/build/docs/waas/wallet-supported-networks)) | ### Response param | Parameter | Type | Description | | --- | --- | --- | | chainId | String | Chain ID (e.g., `1` for Ethereum. See [Chain IDs](https://web3.okx.com/web3/build/docs/waas/wallet-supported-networks)) | | decimals | Integer | The precision of tokens (e.g., `18`) | | tokenContractAddress | String| Token contract address (e.g., `0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2`) | | tokenName | String |Token name (e.g., `USDC`) | | tokenSymbol | String | Token symbol (e.g., `6`) | ### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/cross-chain/supported/tokens' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code": "0", "data": [ { "chainId": "1", "decimals": 6, "tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "tokenName": "USDC", "tokenSymbol": "USDC" }, { "chainId": "1", "decimals": 18, "tokenContractAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "tokenName": "Wrapped Ether", "tokenSymbol": "WETH" } ], "msg": "" } ``` - [Get the list of tokens pairs supported by the cross-chain bridge](https://web3.okx.com/onchainos/docs/waas/dex-get-supported-bridge-tokens-pairs.md) {/* api-page */} # Get the list of tokens pairs supported by the cross-chain bridge List of tokens pairs available for traded directly across the cross-chain bridge. ### Request address GET `https://web3.okx.com/api/v5/dex/cross-chain/supported/bridge-tokens-pairs` ### Request param | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | fromChainId | String| No | Chain ID (e.g., `1` for Ethereum. See [Chain IDs](https://web3.okx.com/web3/build/docs/waas/wallet-supported-networks)) | ### Response param | Parameter | Type | Required | Description | | --- | --- | --- | --- | | fromChainId | String | YES | Source Chain ID (e.g., `1` for Ethereum. See [Chain IDs](https://web3.okx.com/web3/build/docs/waas/wallet-supported-networks)) | | toChainId | String | YES | Destination Chain ID (e.g., `10` for Ethereum. See [Chain IDs](https://web3.okx.com/web3/build/docs/waas/wallet-supported-networks)) | | fromTokenAddress | String | YES | The contract address of a token to be sold (e.g., `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` ) | | toTokenAddress | String | YES | The contract address of a token to be bought (e.g., `TEkxiTehnzSmSe2XqrBj4w32RUN966rdz8`) | | fromTokenSymbol | String | YES | Source Chain Token symbol (e.g.,`USDT`) | | toTokenSymbol | String | YES | Destination Chain Token symbol (e.g.,`USDT`) | ### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/cross-chain/supported/bridge-tokens-pairs?fromChainId=784' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code": "0", "data": [ { "fromChainId": "1", "toChainId": "10", "fromTokenAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "toTokenAddress": "0x0b2c639c533813f4aa9d7837caf62653d097ff85", "fromTokenSymbol": "USDC", "toTokenSymbol": "USDC" } ], "msg": "" } ``` - [Get supported bridges](https://web3.okx.com/onchainos/docs/waas/dex-get-supported-bridges.md) {/* api-page */} # Get supported bridges Get information of the cross-chain bridges supported by OKX’s DEX cross-chain aggregator protocol. ### Request address GET `https://web3.okx.com/api/v5/dex/cross-chain/supported/bridges` ### Request param | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chainId | String | No | Chain ID (e.g., `1` for Ethereum. See [Chain IDs](https://web3.okx.com/web3/build/docs/waas/wallet-supported-networks)) | ### Response param | Parameter | Type | Required | Description | |-----------------|--------|----------|--------------------------------------------------------------------------------------------------------------------| | bridgeName | String | Yes |Name of bridge (e.g., `cBridge`) | | bridgeId | Integer| Yes |Bridge ID (e.g., `211`) | | requiredOtherNativeFee | boolean | Yes | if this bridge require native fee | | logo | String | Yes | Bridge Logo URL | | supportedChains | Array| Yes |Return chain id that bridge supported | ### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/cross-chain/supported/bridges' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code": "0", "data": [ { "bridgeId":211, "bridgeName":"cBridge", "requireOtherNativeFee": false, "logoUrl":"...", "supportedChains": [ "1", "56", "137" ] }, { "bridgeId":235, "bridgeName":"swft", "requireOtherNativeFee": false, "logoUrl":"...", "supportedChains": [ "56", "137", "43114" ] } ], "msg": "" } ``` - [Get route information](https://web3.okx.com/onchainos/docs/waas/dex-get-route-information.md) {/* api-page */} # Get route information Find the best route for a cross-chain swap through OKX’s DEX cross-chain aggregator. ### Request address GET `https://web3.okx.com/api/v5/dex/cross-chain/quote` ### Request param | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | fromChainId | String | Yes | Source chain ID (e.g., `1` for Ethereum. See [Chain IDs](https://web3.okx.com/web3/build/docs/waas/wallet-supported-networks)) | | toChainId | String | Yes | Destination chain ID (e.g., `1` for Ethereum. See [Chain IDs](https://web3.okx.com/web3/build/docs/waas/wallet-supported-networks)) | | fromTokenAddress | String | Yes | The contract address of a token to be sold (e.g., `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` ) | | toTokenAddress | String | Yes | The contract address of a token to be bought (e.g., `TEkxiTehnzSmSe2XqrBj4w32RUN966rdz8`) | | amount | String | Yes | The input amount of a token to be sold (set in minimal divisible units, e.g., `1.00` USDT set as `1000000`, `1.00` DAI set as `1000000000000000000`),you could get the minimal divisible units from [Tokenlist](https://web3.okx.com/web3/build/docs/waas/dex-crosschain-get-tokens). | | slippage | String | Yes | The slippage you are willing to accept. If you set `0.5`, it means 50% slippage is acceptable. `min:0.002` `max:0.5`
1. If you're bridging the same token Y from A chain to B chain, we suggest 0.002.
2. If you're bridging the token X from A chain to B chain and swap to token Y, we suggest 0.01 - 0.025, depending on the token trading volume. | | sort | Integer | No | Cross-chain swap routes,defalut return is 1
0 is the default route that would get you the most tokens.
1 is the optimal route after calculating the received amount, network fees, slippage, and cross-chain bridge costs.
2 is the quickest route with the least swap time. | | dexIds | String | No | DexId of the liquidity pool for limited quotes, multiple combinations separated by , (e.g., 1,50,180, see liquidity list for more) | | feePercent | String | No | The percentage of fromTokenAmount will be sent to the referrer's address, the rest will be set as the input amount to be sold. `min percentage:0` `max percentage:3`| | allowBridge | Array | No | Specify bridge that should be included in routes (e.g.,`[211,235]`) | | denyBridge | Array | No | Specify bridge that should be excluded in routes (e.g.,`[211,235]`) | | priceImpactProtectionPercentage | String | No | (Optional. The default is 90%.) The percentage (between 0 - 1.0) of the price impact allowed.

When the priceImpactProtectionPercentage is set, if the estimated price impact is above the percentage indicated, an error will be returned. For example, if PriceImpactProtectionPercentage = .25 (25%), any quote with a price impact higher than 25% will return an error.
This is an optional feature, and the default value is 0.9. When it’s set to 1.0 (100%), the feature will be disabled, which means that every transaction will be allowed to pass.
Note: If we’re unable to calculate the price impact, we’ll return null, and the price impact protection will be disabled. |
### Response param | Parameter | Type | Description | |---------------------------|-------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | fromChainId | String | Source chain ID (e.g., 1: Ethereum, see the chain ID list for more details) | | toChainId | String | Target chain ID (e.g., 1: Ethereum, see the chain ID list for more details) | | fromTokenAmount | String | The amount of the quoted token to be exchanged (e.g., 500000000000000000000000) | | **fromToken** | **Object** | **Quoted token information** | | decimals | Integer | Token precision (e.g., 18) | | tokenContractAddress | String | Token contract address (e.g., 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2) | | tokenSymbol | String | Token symbol (e.g., WETH) | | **toToken** | **Object** | **Target chain token basic information** | | decimals | Integer | Token precision (e.g., 6) | | tokenContractAddress | String | Token contract address (e.g., 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48) | | tokenSymbol | String | Token symbol (e.g., USDC) | | **routerList** | **Array** | **Quotation path data collection** | | **router** | **Object** | **Cross-chain bridge basic information** | | bridgeId | Integer | Cross-chain bridge ID (e.g., 211) | | bridgeName | String | Cross-chain bridge name (e.g., cBridge) | | otherNativeFee | String | Some cross-chain bridges charge an additional amount of the source chain's native token as a bridge fee. Not all bridges charge this fee. Currently, bridges like Stargate, Wanchain, Arbitrum Official Bridge, zkSync Era Official Bridge, and Linea Official Bridge charge this fee. Transactions using these bridges require payment of `otherNativeFee` to complete. | | otherNativeFeeUsd | String | USD-denominated value of the additional fee charged by some bridges | | crossChainFee | String | Fee charged by the cross-chain bridge, usually in stablecoins or WETH | | crossChainFeeUsd | String | USD-denominated value of the fee charged by the cross-chain bridge | | crossChainFeeTokenAddress | String | Token address for the cross-chain bridge fee (e.g., 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE represents the native token address) | | estimateGasFee | String | Estimated gas consumption in wei | | estimateGasFeeUsd | String | USD-denominated value of the estimated gas consumption | | estimatedTime | String | Estimated time for cross-chain transaction completion, in seconds. The time is dynamically calculated based on historical successful order completion times. | | **fromDexRouterList** | **Array** | **Source chain exchange path basic information. Returns empty if no source chain exchange path is needed.** | | **percent** | **String** | **Percentage of the exchanged assets in a single DEX protocol relative to all DEX protocols in a path** | | router | String | A single path for token exchange | | **subRouterList** | **Array** | **DEX router collection information** | | **dexProtocol** | **Array** | **DEX protocol executed in the exchange path** | | dexName | String | DEX protocol name | | **fromToken** | **Object** | **Quoted token information** | | decimals | Integer | Token precision (e.g., 18) | | tokenContractAddress | String | Token contract address (e.g., 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2) | | tokenSymbol | String | Token symbol (e.g., WETH) | | **toToken** | **Object** | **Target token information** | | decimals | Integer | Token precision (e.g., 6) | | tokenContractAddress | String | Token contract address (e.g., 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48) | | tokenSymbol | String | Token symbol (e.g., USDC) | | **toDexRouterList** | **Array** | **Target chain exchange path basic information. Returns empty if no target chain exchange path is needed.** | | percent | String | Percentage of the exchanged assets in a single DEX protocol relative to all DEX protocols in a path | | router | String | A single path for token exchange | | **subRouterList** | **Array** | **DEX Router collection information** | | dexName | String | DEX protocol name | | percent | String | The percentage of assets handled by the protocol (e.g.,`100`) | | **fromToken** | **Object** | **Quoted token information** | | decimals | Integer | Token precision (e.g., 18) | | tokenContractAddress | String | Token contract address (e.g., 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2) | | tokenSymbol | String | Token symbol (e.g., WETH) | | **toToken** | **Object** | **Target token information** | | decimals | Integer | Token precision (e.g., 6) | | tokenContractAddress | String | Token contract address (e.g., 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48) | | tokenSymbol | String | Token symbol (e.g., USDC) | | fromChainNetworkFee | String | Estimated source chain network fee consumption for the quotation path (displayed in native token precision) | | toChainNetworkFee | String | Estimated target chain network fee consumption for the quotation path (displayed in native token precision) | | minimumReceived | String | Minimum amount of the target token to be received (the amount of the target token when the exchange price reaches the slippage limit) | | toTokenAmount | String | The amount of the target token to be exchanged |
### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/cross-chain/quote?amount=15&fromChainId=324&toChainId=42161&fromTokenAddress=0x3355df6d4c9c3035724fd0e3914de96a5a83aaf4&toTokenAddress=0xff970a61a04b1ca14834a43f5de4533ebddb5cc8&slippage=0.07' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code":"0", "data":[ { "fromChainId":"56", "fromToken":{ "decimals":18, "tokenContractAddress":"0x55d398326f99059ff775485246999027b3197955", "tokenSymbol":"USDT" }, "fromTokenAmount":"30000000000000000000", "routerList":[ { "estimateTime":"290", "fromDexRouterList":[ { "router":"0x55d398326f99059ff775485246999027b3197955--0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c--0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", "routerPercent":"100", "subRouterList":[ { "dexProtocol":[ { "dexName":"Uniswap V3", "percent":"100" } ], "fromToken":{ "decimals":18, "tokenContractAddress":"0x55d398326f99059ff775485246999027b3197955", "tokenSymbol":"USDT" }, "toToken":{ "decimals":18, "tokenContractAddress":"0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", "tokenSymbol":"WBNB" } }, { "dexProtocol":[ { "dexName":"Uniswap V3", "percent":"100" } ], "fromToken":{ "decimals":18, "tokenContractAddress":"0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", "tokenSymbol":"WBNB" }, "toToken":{ "decimals":18, "tokenContractAddress":"0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", "tokenSymbol":"USDC" } } ] } ], "minimumReceived":"28635611", "needApprove":1, "router":{ "bridgeId":235, "bridgeName":"swft", "crossChainFee":"1.090044714717251827012", "crossChainFeeTokenAddress":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619", "otherNativeFee":"0" }, "toDexRouterList":[ { "router":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619--0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "routerPercent":"100", "subRouterList":[ { "dexProtocol":[ { "dexName":"Uniswap V3", "percent":"100" } ], "fromToken":{ "decimals":18, "tokenContractAddress":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619", "tokenSymbol":"WETH" }, "toToken":{ "decimals":18, "tokenContractAddress":"0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270", "tokenSymbol":"WMATIC" } } ] } ], "toTokenAmount":"28924860" } ], "toChainId":"42161", "toToken":{ "decimals":6, "tokenContractAddress":"0xff970a61a04b1ca14834a43f5de4533ebddb5cc8", "tokenSymbol":"USDC.e" } } ], "msg":"" } ```
- [Approve transactions](https://web3.okx.com/onchainos/docs/waas/dex-crosschain-approve-transaction.md) {/* api-page */} # Approve transactions According to the [ERC-20 standard ](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/), we need to make sure that the OKX router has permission to spend funds with the user's wallet before making a transaction. This API will generate the relevant data for calling the contract. ### Request address GET `https://web3.okx.com/api/v5/dex/aggregator/approve-transaction` ### Request param | Parameter | Type | Required | Description | |----------------------|--------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------| | chainId | String | Yes | Chain ID (e.g., `1` for Ethereum. See [Chain IDs](https://web3.okx.com/web3/build/docs/waas/wallet-supported-networks)) | | tokenContractAddress | String | Yes | Token contract address (e.g., `0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`) | | approveAmount | String | Yes | The amount of token that needs to be permitted (set in minimal divisible units, e.g. `1.00` USDT set as `1000000`, `1.00` DAI set as `1000000000000000000`) | ### Response param | Parameter | Type | Description | |--------------------|--------|----------------------------------------| | data | String | Call data | | dexContractAddress | String | The contract address of OKX DEX router (e.g., `0x6f9ffea7370310cd0f890dfde5e0e061059dcfd9`) | | gasLimit | String | Gas limit (e.g., `50000`) | | gasPrice | String | Gas price in wei (e.g., `110000000`) | ### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/approve-transaction?chainId=1&tokenContractAddress=0x6f9ffea7370310cd0f890dfde5e0e061059dcfd9&approveAmount=1000000' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code": "0", "data": [ { "data": "0x095ea7b3000000000000000000000000c67879f4065d3b9fe1c09ee990b891aa8e3a4c2f00000000000000000000000000000000000000000000000000000000000f4240", "dexContractAddress": "0xc67879F4065d3B9fe1C09EE990B891Aa8E3a4c2f", "gasLimit": "50000", "gasPrice": "110000000" } ], "msg": "" } ``` - [Cross-chain swap](https://web3.okx.com/onchainos/docs/waas/dex-crosschain-swap.md) {/* api-page */} # Cross-chain swap Generate the data to execute a cross-chain swap. ### Request address GET `https://web3.okx.com/api/v5/dex/cross-chain/build-tx` ### Request param | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | fromChainId | String | Yes | Source chain ID (e.g., `1` for Ethereum. See [Chain IDs](https://web3.okx.com/web3/build/docs/waas/wallet-supported-networks)) | | toChainId | String | Yes | Destination chain ID (e.g., `1` for Ethereum. See [Chain IDs](https://web3.okx.com/web3/build/docs/waas/wallet-supported-networks)) | | fromTokenAddress | String | Yes | The contract address of a token to be sold (e.g., `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` ) | | toTokenAddress | String | Yes | The contract address of a token to be bought (e.g., `TEkxiTehnzSmSe2XqrBj4w32RUN966rdz8`) | | amount | String | Yes | The input amount of a token to be sold (set in minimal divisible units, e.g., `1.00` USDT set as `1000000`, `1.00` DAI set as `1000000000000000000`),you could get the minimal divisible units from [Tokenlist](https://web3.okx.com/web3/build/docs/waas/dex-crosschain-get-tokens). | | slippage | String | Yes | The slippage you are willing to accept. If you set `0.5`, it means 50% slippage is acceptable. `min:0.002` `max:0.5`
1. If you're bridging the same token Y from A chain to B chain, we suggest 0.002.
2. If you're bridging the token X from A chain to B chain and swap to token Y, we suggest 0.01 - 0.025, depending on the token trading volume.| | sort | Integer | No | Cross-chain swap routes,default return is 1
0 is the route that would get you the most tokens.
1 is the optimal route after calculating the received amount, network fees, slippage, and cross-chain bridge costs.
2 is the quickest route with the least swap time. | | dexIds | String | No | DexId of the liquidity pool for limited quotes, multiple combinations separated by , (e.g., 1,50,180, see liquidity list for more) | | userWalletAddress | String | Yes | User’s wallet address, AA wallet address does not support cross-chain swap (e.g., `0x6f9ffea7370310cd0f890dfde5e0e061059dcfd9`) | | allowBridge | Array | No | Specify bridge that should be included in routes (e.g.,`[211,235]`) | | denyBridge | Array | No | Specify bridge that should be excluded in routes (e.g.,`[211,235]`) | | receiveAddress | String | No | Receive address of a bought token if not set, the `userWalletAddress` will receive a bought token. TRON, SUI and other non-EVM chains need to set a receiving address (e.g., `0x3f6a3f57569358a512ccc0e513f171516b0fd42a`)| | feePercent | String | No | The percentage of the quoted token amount sent to the commission address.
**Minimum percentage**: `0`, **Maximum percentage**: `3`.

Cross-chain commission splitting is currently supported only for `fromToken`. | | referrerAddress | String | No | The commission address (e.g., `0x6f9ffea7370310cd0f890dfde5e0e061059dcfd9`).
This address will receive the commission fee. When using the API, you can set the commission rate using `feePercent`.

**Note:**
1. For **EVM**: Transactions involving wrapped pairs like ETH and WETH are not supported for commission.
2. For **Solana**: The commission address must deposit some SOL beforehand for activation. | | priceImpactProtectionPercentage | String | No | (Optional. The default is 90%.) The percentage (between 0 - 1.0) of the price impact allowed.

When the priceImpactProtectionPercentage is set, if the estimated price impact is above the percentage indicated, an error will be returned. For example, if PriceImpactProtectionPercentage = .25 (25%), any quote with a price impact higher than 25% will return an error.
This is an optional feature, and the default value is 0.9. When it’s set to 1.0 (100%), the feature will be disabled, which means that every transaction will be allowed to pass.
Note: If we’re unable to calculate the price impact, we’ll return null, and the price impact protection will be disabled. | | onlyBridge | boolean | No | Cross-chain transactions are executed directly through the bridge, without making a source-chain swap or a destination-chain swap. | | memo | String | No | You can customize the parameters carried in /build-tx by encoding the data into a 128-character 64-byte hexadecimal string. This can be queried through the /status API. |
### Response param | Parameter | Type | Description | |-----------------|--------------| --- | | fromTokenAmount | String | The input amount of a token to be sold
(Quantity needs to include accuracy. e.g., `1.00` USDT set as `1000000`) | | toTokenAmount | String | The resulting amount of a token to be bought
(Quantity needs to include accuracy. e.g., `1.00` USDT set as `1000000`) | | minmumReceive | String | The minimum amount of a token to buy when the price reaches maximum slippage | | ***router*** | ***Object*** | ***Bridge information*** | | bridgeId | Integer | Bridge ID (e.g., `211`)| | bridgeName | String | Name of bridge (e.g.,`cBridge`)| | otherNativeFee | String | Some cross-chain bridges charge a certain amount of the native tokens from the source chain as a cross-chain bridge fee. Not all cross-chain bridges charge such a fee. These are the current ones that charge bridge fees: Stargate, Wanchain, Arbitrum’s official network, zkSync Era’s official network, and Linea’s official network. `otherNativeFee` is required to be paid using these bridges to finish the transaction. | | crossChainFee | String | The cross-chain bridge fee is charged by the bridge, usually in stablecoin or WETH | | crossChainFeeTokenAddress | String | The cross-chain bridge fee token information (e.g., `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` represents the native token address) | | ***tx*** | ***Object*** | ***On chain transaction data*** | | data | String | InputData on chian | | from | String | User’s wallet address (e.g., `0x6f9ffea7370310cd0f890dfde5e0e061059dcfd9`)| | to | String | The referrer's address (e.g., `0x6dc1fb08decf9f95a01222baa359aa0e02e07716`) | | value | String | The amount of native tokens (in wei) that will be sent to the contract address (e.g., `0`)| | gasLimit | String | (Optional, The gas (in wei) for the swap transaction. If the value is too low to achieve the quote, an error will be returned (e.g., `50000`)| | gasPrice | String | Gas price in wei (e.g., `110000000`)| | maxPriorityFeePerGas | String | EIP-1559: Recommended priority cost of gas per unit (e.g., `500000000`)| | randomKeyAccount | Array | The randomKeyAccount parameter is not required for every transaction. It is only generated and returned during certain special transactions, such as when using the CCTP bridge for cross-chain token transfers. When this parameter is provided, you must use it along with the user’s wallet private key for multi-signature operations to ensure the transaction is secure and successfully completed. Click here to view a [multi-signature example](https://web3.okx.com/web3/build/docs/waas/dex-use-crosschain-solana-quick-start))| | signatureData | Array | If this parameter is returned, it indicates that the transaction requires additional signing data. Developers should use this parameter as one of the inputs for the transaction signature and ensure it is correctly applied during the signing process. |
### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/cross-chain/build-tx?amount=15&fromChainId=324&toChainId=42161&fromTokenAddress=0x3355df6d4c9c3035724fd0e3914de96a5a83aaf4&toTokenAddress=0xff970a61a04b1ca14834a43f5de4533ebddb5cc8&slippage=0.07&userWalletAddress=0x22497668Fb12BA21E6A132de7168D0Ecc69cDF7d&feePercent=1&referrerAddress=0x3f6a3f57569358a512ccc0e513f171516b0fd42a' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code":0, "msg":"", "data": [ { "fromTokenAmount": "1000000000000", "router": { "bridgeId": 235, "bridgeName": "swft", "crossChainFee": "4.67131461", "otherNativeFee": "1.50000000", "crossChainFeeTokenAddress":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619", }, "toTokenAmount": "1000000000000", "minmumReceive": "1000000000000", "tx":{ "data":"0xc748673057861a797275cd8a068abb95a902e8de", "from":"xxxxxxxxxxx", "to":"0x6dc1fb08decf9f95a01222baa359aa0e02e07716", "value":0, "gasLimit":"442621", "gasPrice":"3192374970", "maxPriorityFeePerGas":"3579" } } ] } ```
- [Get transaction status](https://web3.okx.com/onchainos/docs/waas/dex-get-transaction-status.md) {/* api-page */} # Get transaction status Check the final status of the cross-chain swap according to transaction hash. ### Request address GET `https://web3.okx.com/api/v5/dex/cross-chain/status` ### Request param | Parameter | Type | Required | Description | |----------------------|--------|----------|--------------------------------------------------------------------------------------------------------------------------| | hash | String | Yes | Hash address of the source chain | | chainId | String | No | Source chain ID (e.g., `1` for Ethereum. See [Chain IDs](https://web3.okx.com/web3/build/docs/waas/wallet-supported-networks)) | ### Response param | Parameter | Type | Description | |-------------------------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | fromChainId | String | Source chain ID (e.g., 1: Ethereum; more details can be found in the Chain ID list) | | toChainId | String | Target chain ID (e.g., 66: Ethereum; more details can be found in the Chain ID list) | | fromTxHash | String | Source chain transaction hash | | toTxHash | String | Target chain transaction hash | | fromAmount | String | Exchange amount of the quoted token (amount includes precision, e.g., 1.00 USDT would be 1000000) | | fromTokenAddress | String | Contract address of the quoted token (e.g., 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) | | toAmount | String | Exchange amount of the target token (amount includes precision, e.g., 1.00 USDT would be 1000000) | | toTokenAddress | String | Contract address of the target token (e.g., 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48) | | errorMsg | String | Error message | | bridgeHash | String | Cross-chain bridge transaction hash on the target chain | | refundChainId | String | Refund chain ID | | refundTokenAddress | String | Contract address of the refund token | | refundTxHash | String | Refund transaction hash | | sourceChainGasfee | String | Actual gas fee consumed on the source chain | | crossChainFee | Object | Actual fees charged by the cross-chain bridge | | symbol | String | Symbol of the cross-chain bridge token | | address | String | Address of the cross-chain bridge token | | amount | String | Amount charged by the cross-chain bridge | | crossChainInfo | Object | Information about the cross-chain bridge | | memo | String | Custom parameter carried in `/build-tx` | | destinationChainGasfee | String | Actual gas fee consumed on the target chain | | detailStatus | String | WAITING (Order in process), FROM_SUCCESS (Source chain order successful), FROM_FAILURE (Source chain order failed), BRIDGE_PENDING (Cross-chain bridge order pending), BRIDGE_SUCCESS (Bridge order successful), SUCCESS (Cross-chain exchange order successful), REFUND (Cross-chain failed, order refunded) | | status | String | PENDING (Cross-chain in progress), SUCCESS (Cross-chain successful), FAILURE (Cross-chain failed) | ### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/cross-chain/status?hash=0x0922d94d3bb459d05f16c64ba4b71ec1138940ed552a701837dba2536893e7fc' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code":0, "msg":"", "data": [ { "bridgeHash": "0x94ec8deac0dxxxb1c4ef09e0f29689xxxxfd9e66de822e2059bxxxx78c1ae1e8", "fromChainId": "109", "toChainId": "110", "fromAmount": 10000000000000, "toAmount": 25300000000000, "errorMsg": "", "toTxHash": "0x94ec8deac0d114b1c4ef09e0f29689dc53fd9e66de822e2059b9ad078c1ae1e8", "fromTxHash": "0xa917f8c0ff8dd4b7bdf2eac4d54be40f7a7d4a06a517c6c590ea9a9bd99f40ba", "refundTokenAddress": "", "detailStatus": "SUCCESS", "status": "SUCCESS" } ] } ``` - [Supported bridges](https://web3.okx.com/onchainos/docs/waas/dex-crosschain-supported-bridges.md) # Supported bridges Information of the cross-chain bridges supported by OKX’s DEX. | Supported bridges | Status | |-------------------------------|------------| | Stargate | [Supported](./dex-get-supported-bridges) | | CCTP | [Supported](./dex-get-supported-bridges) | | Across | [Supported](./dex-get-supported-bridges) | | Swft | [Supported](./dex-get-supported-bridges) | | Cbridge | [Supported](./dex-get-supported-bridges) | | Wanchain | [Supported](./dex-get-supported-bridges) | | Hyphen | [Supported](./dex-get-supported-bridges) | | Meson | [Supported](./dex-get-supported-bridges) | | Wormhole | [Supported](./dex-get-supported-bridges) | | Connext | [Supported](./dex-get-supported-bridges) | | XLayer bridge | [Supported](./dex-get-supported-bridges) | - [Smart contract](https://web3.okx.com/onchainos/docs/waas/dex-crosschain-smart-contract.md) # Smart contract The contract addresses of OKX DEX router and ABI The contract addresses of the DEX router and token approval may be subject to replacement due to contract upgrades. To ensure uninterrupted use of the API, we recommend using the contract addresses returned by the response parameters: `/approve-transaction` API and `/build-tx` API for approvals and transactions. ### DEX router The contract addresses of OKX DEX router,check [here](./dex-smart-contract) to get detail. ### Token approval A list of smart contracts for ERC-20 token approval,check [here](./dex-smart-contract) to get detail. ### DEX XBridge address The contract addresses of OKX Xbridge,used for signing cross-chain transactions | Chain | DEX XBridge contract address | |---------------|--------------------------------------------------------------------| | Ethereum | 0xFc99f58A8974A4bc36e60E2d490Bb8D72899ee9f | | BNB Chain | 0xFc99f58A8974A4bc36e60E2d490Bb8D72899ee9f | | OKTC | 0xf956D9FA19656D8e5219fd6fa8bA6cb198094138 | | Polygon | 0x89f423567c2648BB828c3997f60c47b54f57Fa6e | | Fantom | 0xf956D9FA19656D8e5219fd6fa8bA6cb198094138 | | Arbitrum | 0xFc99f58A8974A4bc36e60E2d490Bb8D72899ee9f | | Optimism | 0xf956D9FA19656D8e5219fd6fa8bA6cb198094138 | | Cronos | 0xf956D9FA19656D8e5219fd6fa8bA6cb198094138 | | Avalanche C | 0xf956D9FA19656D8e5219fd6fa8bA6cb198094138 | | TRON | TVaV2BBs8tpthbp19QAy7ibmXLoYsomKDD | | Solana | okxBd18urPbBi2vsExxUDArzQNcju2DugV9Mt46BxYE | | zkSync Era | 0x4040bEC373F6e8be2F913324de94A7b9242E5E92 | | Polygon zkEvm | 0x5965851f21DAE82eA7C62f87fb7C57172E9F2adD | | Linea | 0xf956D9FA19656D8e5219fd6fa8bA6cb198094138 | | Mantle | 0xf956D9FA19656D8e5219fd6fa8bA6cb198094138 | | Base | 0x5965851f21DAE82eA7C62f87fb7C57172E9F2adD | | Manta | 0x91EcECC4F2363770c621a8a061A80d67cfEafEC7 | | Metis | 0xa50FD06d2b099a4B06d54177C7d3AB08D3D3F004 | | SUI | 0x3d097b26cd6a13a0c37e983e81be72cd2965c4dc717a03471e3a7388c21c9263 | | Scroll | 0xf956D9FA19656D8e5219fd6fa8bA6cb198094138 | | Starknet | 0x00e704db07356df9a2ba8cd2a131e0192b9d9d9ddb518eb3bd4e8fb4a1f0901c | | Blast | 0xf956d9fa19656d8e5219fd6fa8ba6cb198094138 | | Merlin | 0xf956d9fa19656d8e5219fd6fa8ba6cb198094138 | | X Layer | 0x5965851f21DAE82eA7C62f87fb7C57172E9F2adD | ## The Application Binary Interface of Contract (ABI) Please refer to: https://github.com/okx/OKX-DEX-Aggregator-ABI - [Error codes](https://web3.okx.com/onchainos/docs/waas/dex-crosschain-error-code.md) # Error codes | Code | HTTP status | Message | | ----- | ----------- | -------------------------------------------------------------------------------------------------------- | | 0 | 200 | Succeeded | | 50011 | 429 | Rate limit reached. Please refer to API documentation and throttle requests accordingly | | 50014 | 400 | Parameter param0 cannot be empty | | 50026 | 500 | System error. Try again later | | 50103 | 401 | Request header "OK-ACCESS-KEY" cannot be empty | | 50104 | 401 | Request header "OK-ACCESS-PASSPHRASE" cannot be empty | | 50105 | 401 | Request header "OK-ACCESS-PASSPHRASE" incorrect | | 50106 | 401 | Request header "OK-ACCESS-SIGN" cannot be empty | | 50107 | 401 | Request header "OK-ACCESS-TIMESTAMP" cannot be empty | | 50111 | 401 | Invalid OK-ACCESS-KEY | | 50112 | 401 | Invalid OK-ACCESS-TIMESTAMP | | 50113 | 401 | Invalid signature | | 51000 | 400 | Parameter param0 error | | 80000 | 200 | Repeated request | | 82000 | 200 | Insufficient liquidity | | 82001 | 500 | The commission service is not available during the upgrade | | 82102 | 200 | Minimum amount is 0 | | 82103 | 200 | Maximum amount is 0 | | 82104 | 200 | This token is not supported | | 82105 | 200 | This chain is not supported | | 82112 | 200 | The value difference from this transaction’s quote route is higher than num, which may cause asset loss. | | 82114 | 200 | The slippage too low,Suggest 0 | | 82115 | 200 | The chain has not token pairs | | 82116 | 200 | No suitable cross-chain bridge found | - [FAQ](https://web3.okx.com/onchainos/docs/waas/dex-crosschain-faq.md) # FAQ ## Common reasons for cross-chain failures There are three categories of unsuccessful cross-chain swaps: unsuccessful source-chain swaps, unsuccessful destination-chain swaps, and unsuccessful cross-bridge transactions. 1. The source-chain swaps and the destination-chain swaps may fail for the following reasons: - Broadcast failure - Insufficient gas - Exceeded slippage setting - Insufficient approved crypto amount - Third-party DEX contract execution error - The transaction was sped up or canceled - Tokens traded were safeMoon or honeypot tokens 2. Cross-bridge transactions may fail for the following reasons: - Exceeded the third-party bridge’s slippage - Triggered the third-party bridge’s blocklist - The minimum/maximum cross-chain amount required by the bridge wasn’t met - Insufficient liquidity on the bridge - The cross-bridge transaction timed out ## Transaction time is too long NO, The transaction of source-chain swaps usually takes less than one minute. The official bridges have long transaction times because of their own cross-chain mechanisms. If the other third-party bridge doesn’t return the final status for a long time, you can check the transaction status on the chain or contact third-party customer service for confirmation. ## Are speed-ups and transaction cancellation supported? No, speed-ups and transaction cancellation aren’t supported. ## Cross-chain refund There are two types of cross-chain refunds at the moment. The first is a refund initiated by a third-party bridge. The second is a refund initiated by OKX DEX. 1. Refund initiated by a third-party bridge - The main reason for this type of refund is that the bridge refund rules have been triggered when the funds have entered the bridge, but the bridge transaction is unable to proceed normally. - Refunds are initiated generally because there is insufficient liquidity due to changes in the bridge’s pool, or the user’s cross-chain amount is below the minimum required by the bridge, or some other rules have been triggered, such as the third-party bridge’s blocklists. - The third-party bridge will initiate the refund. The refund token is generally USDT, USDC, DAI, WETH, and ETH. The refund is returned from the third-party bridge, and the final amount received by the user will have the gas fee deducted. - Common third-party bridges for cross-chain refunds include SWFT etc. 2. Refunds initiated by OKX DEX - There are two main reasons for refunds. The first is that when OKX pre-executes a swap on the destination chain, if the pre-executed transaction returns an error, a refund will be automatically triggered. The second is an actual unsuccessful swap on the destination chain. - If pre-execution transactions return errors, it’s usually because the set slippage has been exceeded, or errors have occurred during third-party DEX contract executions, or the traded tokens are safeMoon tokens or honeypot tokens, etc. - Failed transactions on the destination chain will also trigger automatic refunds. Common reasons for such failures can be found in the above-mentioned cross-chain scenarios. - OKX DEX will initiate the refund. The refund token is USDT, USDC, DAI, WETH, or ETH. The refund is returned from OKX DEX, and the final amount received by the user will have the gas fee deducted. - [Limit order API](https://web3.okx.com/onchainos/docs/waas/dex-limit-order.md) # Limit order API - [API reference](https://web3.okx.com/onchainos/docs/waas/dex-limit-order-reference.md) # API reference - [Get supported chains](https://web3.okx.com/onchainos/docs/waas/dex-limit-order-chains.md) {/* api-page */} # Get supported chains Get information from chains that support limit order transactions. Use a request to return a supported chain. ### Supported Chains - Ethereum Mainnet - OP Mainnet - Polygon Mainnet - BNB Smart Chain Mainnet - OKT Chain - Avalanche C-Chain - Fantom Opera - Arbitrum One For network and chainId correlations, please visit the [Network chainId mapping](./walletapi-resources-supported-networks) . ### Request address GET `https://web3.okx.com/api/v5/dex/aggregator/limit-order/chain` ### Request param | Parameter | Type | Required | Description | |------------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | chainId | Integer | No | Unique identifier for the chain.
If left empty ````, the response will return all supported chain information.
If a specific chain ID is provided, information for that chain will be returned, e.g., `1`: Ethereum. See more [here](./walletapi-resources-supported-networks). |
### Response param | Parameter | Type | Description | |-----------------|--------|-----------------------------------------------------------------------------------------------------------------------| | chainId | Integer| Unique identifier for the chain (e.g., `1`: Ethereum; see more [here](./walletapi-resources-supported-networks)). | | chainName | String | Chain name (e.g.,`Optimism`) | | dexTokenApproveAddress | String | dex token Approve Contract Address |
### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/limit-order/chain?chainId=1' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code":"0", "data":[ { "chainId":137, "chainName":"Polygon", "dexTokenApproveAddress":"0x3B86917369B83a6892f553609F3c2F439C184e31" }, { "chainId":43114, "chainName":"Avalanche C", "dexTokenApproveAddress":"0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f" }, { "chainId":1, "chainName":"Ethereum", "dexTokenApproveAddress":"0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f" }, { "chainId":66, "chainName":"OKTC", "dexTokenApproveAddress":"0x70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58" }, { "chainId":56, "chainName":"BNB Chain", "dexTokenApproveAddress":"0x2c34A2Fb1d0b4f55de51E1d0bDEfaDDce6b7cDD6" }, { "chainId":250, "chainName":"Fantom", "dexTokenApproveAddress":"0x70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58" }, { "chainId":42161, "chainName":"Arbitrum", "dexTokenApproveAddress":"0x70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58" }, { "chainId":10, "chainName":"Optimism", "dexTokenApproveAddress":"0x68D6B739D2020067D1e2F713b999dA97E4d54812" } ], "msg":"" } ```
- [Get allowance](https://web3.okx.com/onchainos/docs/waas/dex-limit-order-get-allowance.md) # Get allowance You need to use a third-party method since OKX DEX has discontinued its interface that queries the authorized amount of a transaction. The recommended method is as follows. ## Third-party query method ### Taking ETH chain as an example - `This demo is in JavaScript` 1. `Connect to an Ethereum node`: You need to ensure that you have connected to an available Ethereum node. You can use web3.js or other Ethereum development libraries to connect to the node. In the code, you need to specify the node's HTTP or WebSocket endpoint. 2. `Obtain a token contract instance`: Using the contract address and ABI of the token, you need to create an instance of the token contract. You can use the web3.eth.Contract in web3.js to achieve this. Pass the contract address and ABI as arguments to the contract instance. 3. `Query the authorized amount`: Query the authorized allowance by calling the allowance function of the contract instance. This function requires two parameters: the owner's address and the authorized party's address (spenderAddress). You can query the authorized allowance by providing these two addresses during the call. 4. The spenderAddress can refer to the dexTokenApproveAddress from [Here](https://web3.okx.com/web3/build/docs/waas/dex-limit-order-chains) in the Response interface.。 ```js const { Web3 } = require('web3'); // Connect to an Ethereum node const web3 = new Web3('https://xxxxx'); // token address and ABI const tokenAddress = '0xxxxxxxxx'; // user address const ownerAddress = '0xxxxxxxx'; // ETH dex token approval address const spenderAddress = '0x40aa958dd87fc8305b97f2ba922cddca374bcd7f'; const tokenABI = [ { "constant": true, "inputs": [ { "name": "_owner", "type": "address" }, { "name": "_spender", "type": "address" } ], "name": "allowance", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" } ]; // Create token contract instance const tokenContract = new web3.eth.Contract(tokenABI, tokenAddress); // Query token approve allowance function async function getAllowance(ownerAddress, spenderAddress) { try { const allowance = await tokenContract.methods.allowance(ownerAddress, spenderAddress).call(); console.log(`Allowance for ${ownerAddress} to ${spenderAddress}: ${allowance}`); } catch (error) { console.error('Failed to query allowance:', error); } } getAllowance(ownerAddress, spenderAddress).then(r => console.log(r)); ``` - [Approve transactions](https://web3.okx.com/onchainos/docs/waas/dex-limit-order-approve-transaction.md) {/* api-page */} # Approve transactions According to the [ERC-20 standard ](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/), we need to make sure that the OKX router has permission to spend funds with the user's wallet before making a transaction. This API will generate the relevant data for calling the contract. ### Request address GET `https://web3.okx.com/api/v5/dex/aggregator/approve-transaction` ### Request param | Parameter | Type | Required | Description | |----------------------|--------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------| | chainId | String | Yes | Chain ID (e.g., `1` for Ethereum. See [Chain IDs](./walletapi-resources-supported-networks)) | | tokenContractAddress | String | Yes | Token contract address (e.g., `0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`) | | approveAmount | String | Yes | The amount of token that needs to be permitted (set in minimal divisible units, e.g. `1.00` USDT set as `1000000`, `1.00` DAI set as `1000000000000000000`) | ### Response param | Parameter | Type | Description | |--------------------|--------|----------------------------------------| | data | String | Call data | | dexContractAddress | String | The contract address of OKX DEX router (e.g., `0x6f9ffea7370310cd0f890dfde5e0e061059dcfd9`) | | gasLimit | String | Gas limit (e.g., `50000`) | | gasPrice | String | Gas price in wei (e.g., `110000000`) ### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/approve-transaction?chainId=1&tokenContractAddress=0x6f9ffea7370310cd0f890dfde5e0e061059dcfd9&approveAmount=1000000' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code": "0", "data": [ { "data": "0x095ea7b3000000000000000000000000c67879f4065d3b9fe1c09ee990b891aa8e3a4c2f00000000000000000000000000000000000000000000000000000000000f4240", "dexContractAddress": "0xc67879F4065d3B9fe1C09EE990B891Aa8E3a4c2f", "gasLimit": "50000", "gasPrice": "110000000" } ], "msg": "" } ``` - [Get tokens](https://web3.okx.com/onchainos/docs/waas/dex-limit-order-get-tokens.md) {/* api-page */} # Get tokens Get a list of tokens that are available for swap in the OKX aggregation protocol. ### Request address GET `https://web3.okx.com/api/v5/dex/aggregator/all-tokens` ### Request param | Parameter | Type | Required | Description | |-----------|--------|----------|--------------------------------------------------------------------------------------------------------------------------| | chainId | String | Yes | Chain ID (e.g., `1` for Ethereum. See [Chain IDs](./walletapi-resources-supported-networks)) | ### Response param | Parameter | Type | The precision of tokens | |----------------------|--------|--------------------------| | decimals | String | The precision of tokens (e.g., `18`) | | tokenContractAddress | String | Token contract address (e.g., `0x382bb369d343125bfb2117af9c149795c6c65c50`) | | tokenLogoUrl | String | Token logo (e.g., `https://static.okx.com/cdn/wallet/logo/USDT-991ffed9-e495-4d1b-80c2-a4c5f96ce22d.png`) | | tokenName | String | Token full name (e.g., `Tether`) | | tokenSymbol | String | Token symbol (e.g., `USDT`) | ### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/all-tokens?chainId=1' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code": "0", "data": [ { "decimals": "18", "tokenContractAddress": "0x382bb369d343125bfb2117af9c149795c6c65c50", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/USDT-991ffed9-e495-4d1b-80c2-a4c5f96ce22d.png", "tokenName": "Tether", "tokenSymbol": "USDT" }, { "decimals": "18", "tokenContractAddress": "0xc946daf81b08146b1c7a8da2a851ddf2b3eaaf85", "tokenLogoUrl": "https://static.okx.com/cdn/explorer/okexchain/exchain_usdc.png", "tokenName": "USD Coin", "tokenSymbol": "USDC" }, { "decimals": "18", "tokenContractAddress": "0xdf54b6c6195ea4d948d03bfd818d365cf175cfc2", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/okb.png", "tokenName": "OKB", "tokenSymbol": "OKB" }, { "decimals": "18", "tokenContractAddress": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/okt.png", "tokenName": "OKTC", "tokenSymbol": "OKT" }, { "decimals": "18", "tokenContractAddress": "0x218c3c3d49d0e7b37aff0d8bb079de36ae61a4c0", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/BNB-20220308.png", "tokenName": "Binance Coin", "tokenSymbol": "BNB" }, { "decimals": "18", "tokenContractAddress": "0x332730a4f6e03d9c55829435f10360e13cfa41ff", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/BUSD-20220308.png", "tokenName": "Binance USD", "tokenSymbol": "BUSD" }, { "decimals": "18", "tokenContractAddress": "0xdcac52e001f5bd413aa6ea83956438f29098166b", "tokenLogoUrl": "https://static.okx.com/cdn/wallet/logo/eth_usdk.png", "tokenName": "USDK", "tokenSymbol": "USDK" } ], "msg": "" } ``` [//]: # () [//]: # (//移动端页面布局(注释迁移时忽略)) [//]: # () [//]: # (//下一行填写 API名称) [//]: # (# 获取币种列表) [//]: # () [//]: # (获取欧易DEX聚合器协议支持兑换的币种列表) [//]: # () [//]: # () [//]: # () [//]: # () [//]: # (### 请求地址) [//]: # (「GET」https://web3.okx.com/api/v5/dex/aggregator/all-tokens) [//]: # () [//]: # (### 请求参数) [//]: # (// 下方填写请求参数表格(如果存在path 和 query 则分别分点描述)) [//]: # () [//]: # (| 参数名 | 类型 | 是否必须 | 描述 |) [//]: # (|---------|--------|------|---------------------------------|) [//]: # (| chainId | String | 是 | 链 ID (如`1`: Ethereum,更多可查看数据字典) |) [//]: # () [//]: # () [//]: # () [//]: # (### 请求示例) [//]: # () [//]: # () [//]: # (//下方填写shell 代码) [//]: # () [//]: # (```shell) [//]: # (curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/all-tokens?chainId=1') [//]: # (```) [//]: # () [//]: # () [//]: # (//下方填写java 代码) [//]: # () [//]: # () [//]: # () [//]: # (//此区域可写其他补充性内容) [//]: # () [//]: # () [//]: # (### 响应参数) [//]: # (// 下方填写响应参数表格) [//]: # () [//]: # () [//]: # (### 响应示例) [//]: # () [//]: # () [//]: # () [//]: # () [//]: # (```json) [//]: # ({) [//]: # ( "code": "0",) [//]: # ( "data": [) [//]: # ( {) [//]: # ( "decimals": 18,) [//]: # ( "tokenContractAddress": "0xdf54b6c6195ea4d948d03bfd818d365cf175cfc2",) [//]: # ( "tokenLogoUrl": "https://static.coinall.ltd/cdn/wallet/logo/okb.png",) [//]: # ( "tokenName": "OKB",) [//]: # ( "tokenSymbol": "OKB") [//]: # ( },) [//]: # ( {) [//]: # ( "decimals": 6,) [//]: # ( "tokenContractAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7",) [//]: # ( "tokenLogoUrl": "https://static.coinall.ltd/cdn/wallet/logo/usdt.png",) [//]: # ( "tokenName": "Tether",) [//]: # ( "tokenSymbol": "USDT") [//]: # ( },) [//]: # ( {) [//]: # ( "decimals": 6,) [//]: # ( "tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",) [//]: # ( "tokenLogoUrl": "https://static.oklink.com/cdn/explorer/okexchain/exchain_usdc.png",) [//]: # ( "tokenName": "USD Coin",) [//]: # ( "tokenSymbol": "USDC") [//]: # ( },) [//]: # ( {) [//]: # ( "decimals": 18,) [//]: # ( "tokenContractAddress": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",) [//]: # ( "tokenLogoUrl": "https://static.coinall.ltd/cdn/wallet/logo/eth01.png",) [//]: # ( "tokenName": "Ethereum",) [//]: # ( "tokenSymbol": "ETH") [//]: # ( }) [//]: # ( ],) [//]: # ( "msg": "") [//]: # (}) [//]: # (```) [//]: # () [//]: # () [//]: # () [//]: # (//此区域可写其他补充性内容) [//]: # () [//]: # () [//]: # () [//]: # () - [Create limit order](https://web3.okx.com/onchainos/docs/waas/dex-create-limit-order.md) {/* api-page */} # Create limit order Create a DEX limit order. ### Request address POST `https://web3.okx.com/api/v5/dex/aggregator/limit-order/save-order` ### Request parameters | Parameter | Type | Required | Description | |-------------------|--------|------------|-----------------------------------------------------------------------------------------------| | orderHash | String | Yes | order hash | | signature | String | Yes | signature | | chainId | String | Yes | Chain ID (e.g., `1` for Ethereum. See [Chain IDs](./walletapi-resources-supported-networks)) | | ***data*** | ***Object*** | ***Yes*** | ***data object*** | | salt | String | Yes | random number salt as idempotent identifier
Current timestamp (second value) (e.g.,`1691499249`) | | makingAmount | String | Yes | The number of a token to be sold (set in minimal divisible units, e.g., `1.00` USDT set as `1000000`, `1.00` DAI set as `1000000000000000000`) | | takingAmount | String | Yes | The number of a token to be bought (set in minimal divisible units, e.g., `1.00` USDT set as `1000000`, `1.00` DAI set as `1000000000000000000`) | | makerToken | String | Yes | The contract address of a token to be sold (e.g.,`0x53e0bca35ec356bd5dddfebbd1fc0fd03fabad39`) | | takerToken | String | Yes | The contract address of a token to be bought (e.g.,`0x2791bca1f2de4661ed88a30c99a7a9449aa84174`) | | maker | String | Yes | The wallet address for current transaction (e.g.,`0x6f9ffea7370310cd0f890dfde5e0e061059dcfd9`) | | deadLine | String | Yes | Current order’s effective deadline
timestamp (second value) (e.g.,`1699520029`) | | allowedSender | String | Yes | Setting up a zero address (`0x0000000000000000000000000000000000000000`) Everyone can deal with the current limit order. If you set a value, the limit order will only be executable at the specified address. (e.g.,`0x6f9ffea7370310cd0f890dfde5e0e061059dcfd9`) | | receiver | String | Yes | Assets will be sent to the current receiver's address. (e.g.,`0x6f9ffea7370310cd0f890dfde5e0e061059dcfd9`) | | minReturn | String | Yes | Minimum number of coins to be bought
(the number must include precision, e.g. for `1.00` USDT set as `1000000`, for `1.00` DAI set as `1000000000000000000`). | | partiallyAble | Bool | Yes | Whether partial transactions are supported (`true` for yes, `false` for no) |
### Response parameters | Parameter | Type | Description | |------------------|--------|-----------------------------------------| | code | String | Status code (e.g. `0`: operation successful, `51000`: mandatory parameter cannot be null. See error codes list for more information.) | | msg | String | Server-side response information. If interface is normal, then no value; if abnormal, it will return an exception. |
### Request example ```json { "orderHash":"0xf1852a5c82b9ff891123456731325f4a778603471c2e8fa8d80583824c21e97a", "signature":"0x78645ba7ed8c0266e01e46302160aad1234567ac9a0c751b9c315a516f44f54765acd11c11ffc88c9dd7f74fa63c606506ab145f94592bbbcb3cf2bac1cb13a01b", "chainId":"137", "data":{ "salt":"1697032618", "makingAmount":"5900000", "takingAmount":"6000000", "makerToken":"0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "takerToken":"0xc2132d05d31c914a87c6611c10748aeb04b58e8f", "maker":"0x230293u8238sh823472hjskq92j38ahj2i391k20", "deadLine":"1697784060", "allowedSender":"0x0000000000000000000000000000000000000000", "receiver":"0x230293u8238sh823472hjskq92j38ahj2i391k20", "minReturn":"6000000", "partiallyAble" : true } } ``` ### Response example ```json { "code":"0", "msg":"save order success" } ```
- [Limit order list](https://web3.okx.com/onchainos/docs/waas/dex-query-limit-order-all.md) {/* api-page */} # Limit order list Query list of DEX limit order. ### Request address GET `https://web3.okx.com/api/v5/dex/aggregator/limit-order/all` ### Request parameters | Parameter | Type | Required | Description | |-------------------|--------|------------|-----------------------------------------------------------------------------------------------| | chainId | String | Yes | Chain ID (e.g., `1` for Ethereum. See [Chain IDs](./walletapi-resources-supported-networks)) | | page | String | No | Pagination step, default: 1 (page = offset / limit) | | limit | String | No | Number of limit orders to receive (default: 100, max: 500) | | statuses | String | No | An array of statuses by which limit orders will be filtered. Valid statuses include: 1 - Valid orders, 2 - Temporarily invalid orders, 3 - Occupied orders , 4 - Expired, 5 - Cancelled, 6 - Success, 7 - Failed orders. | | takerAsset | String | No | Address of the taker asset | | makerAsset | String | No | Address of the maker asset | ### Response parameters | Parameter | Type | Description | |----------------------|--------|-----------------------------------------| | chainId | string | chainID (e.g. `1`: Ethereum, see list of chain IDs for more) | | createTime | string | Order creation time | | expireTime | string | Current order’s effective deadline | | makerAssetAddress | string | The wallet address for current transaction | | makerRate | string | takingAmount/makingAmount | | makerTokenAddress | string | The contract address of a token to be sold | | makingAmount | string | The number of a token to be sold | | orderHash | string | orderHash | | receiver | string | Default is zero address, and the recipient’s assets will be sent to the address of the limit order creator. If you set a value, the asset will be sent to the current address. | | remainingMakerAmount | string | Remaining tradable quantity | | salt | string | random number salt as idempotent identifier
Current timestamp (second value) | | signature | string | signature | | status | string | Order status (`0`: available, `1`: temporarily disabled, `3`: unavailable, `4` order fully filled) | | takerTokenAddress | string | The contract address of a token to be bought | | takingAmount | string | The number of a token to be bought | | takerRate | string | makingAmount/takingAmount | | takerAssetAddress | string | Default is zero address, and everyone can fill the current limit order. If you set a value, the limit order will only be executable at the specified address. |
### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/limit-order/all?chainId=137' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code": "0", "data":[ { "chainId": "137", "createTime": "2023-12-07 17:54:20", "expireTime": "2023-12-10 13:59:31", "makerAssetAddress": "0xc171a1caa36b1c9e2c56fe71a24ceac127ff5ae4", "makerRate": "16.700084079252467628", "makerTokenAddress": "0x53e0bca35ec356bd5dddfebbd1fc0fd03fabad39", "makingAmount": "2.095797831550000000", "orderHash": "0x618d6abcde06366ae5bd70e8fc661443bd7f9da5073305b39273f1b426cda443", "receiver": "", "remainingMakerAmount": "2.095797831550000000", "salt": "1701942829", "signature": "0x867ad0143a04bbee935fde6fcd2a4ddb6cf734a0c6d59352cd5d769d366caf2b25f4480e83d4e9b31274314ec24b88b04686c4df0ad4658b898fd56d630c049e1b", "status": "3", "takerAssetAddress": "0x0000000000000000000000000000000000000000", "takerRate": "0.059879938044285714", "takerTokenAddress": "0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "takingAmount": "35.000000000000000000" }, { "chainId": "137", "createTime": "2023-11-09 16:54:40", "expireTime": "2023-11-15 21:30:49", "makerAssetAddress": "0xc171a1caa36b1c9e2c56fe71a24ceac127ff5ae4", "makerRate": "17.142857142857142857", "makerTokenAddress": "0x53e0bca35ec356bd5dddfebbd1fc0fd03fabad39", "makingAmount": "0.700000000000000000", "orderHash": "0xf834d285a8bee9c4edf2d3de4acff5acbc350bafe81d0491fc2448d6122a98ee", "receiver": "0x0a0de421eb2d6cbef3b81a9d5561f6d2f26c3d07", "remainingMakerAmount": "0.000000000000000000", "salt": "1699520029", "signature": "0xe028369231a0c7d8224c68001bdf16fcdbd3a92ca05d3f50fc880b6688c0980626dc4ac76c5c25276a0197a0db92fd358959d231e31d6eb78488bf34f709edbc1c", "status": "3", "takerAssetAddress": "0x0000000000000000000000000000000000000000", "takerRate": "0.058333333333333333", "takerTokenAddress": "0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "takingAmount": "12.000000000000000000" }, { "chainId": "137", "createTime": "2023-12-06 11:17:01", "expireTime": "2023-12-20 10:36:05", "makerAssetAddress": "0xc171a1caa36b1c9e2c56fe71a24ceac127ff5ae4", "makerRate": "16.700084079252467628", "makerTokenAddress": "0x53e0bca35ec356bd5dddfebbd1fc0fd03fabad39", "makingAmount": "2.095797831550000000", "orderHash": "0xe1cb49dad5d3b23585c9f99cd75d10a87be70b7f59aa92e04fc5f1fa9023f93c", "receiver": "", "remainingMakerAmount": "2.095797831550000000", "salt": "1701832383", "signature": "0x6880a1c3b7c05d1a1c027494512090390789ebae7211ba5a087fe29161394b9320f6ac4eee14ce404902743668d6d1a50170c3c906d47fe0fdcec45a25b111a71b", "status": "3", "takerAssetAddress": "0x0000000000000000000000000000000000000000", "takerRate": "0.059879938044285714", "takerTokenAddress": "0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "takingAmount": "35.000000000000000000" }, { "chainId": "137", "createTime": "2023-12-07 16:02:14", "expireTime": "2023-12-10 13:59:31", "makerAssetAddress": "0xc171a1caa36b1c9e2c56fe71a24ceac127ff5ae4", "makerRate": "16.700084079252467628", "makerTokenAddress": "0x53e0bca35ec356bd5dddfebbd1fc0fd03fabad39", "makingAmount": "2.095797831550000000", "orderHash": "0x555199460dea70eed738b4e782929c8e1e02f9abfaea31494ce90ba300306292", "receiver": "", "remainingMakerAmount": "2.095797831550000000", "salt": "1701936038", "signature": "0x7b00c8b608cb9769c37825f41248d4e5b1502ee705c4255b5074f544482177724a7227daed6cd7acb199e2a46436dc76e71ee16d5c751bd4eb8d2d65e18b7ae21c", "status": "3", "takerAssetAddress": "0x0000000000000000000000000000000000000000", "takerRate": "0.059879938044285714", "takerTokenAddress": "0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "takingAmount": "35.000000000000000000" }, { "chainId": "137", "createTime": "2023-12-07 17:18:00", "expireTime": "2023-12-10 13:59:31", "makerAssetAddress": "0xc171a1caa36b1c9e2c56fe71a24ceac127ff5ae4", "makerRate": "16.700084079252467628", "makerTokenAddress": "0x53e0bca35ec356bd5dddfebbd1fc0fd03fabad39", "makingAmount": "2.095797831550000000", "orderHash": "0x596d7bd82d82d9766154f9c1884963c06a8d4d26991cd7f9b2448cbdde750a27", "receiver": "", "remainingMakerAmount": "2.095797831550000000", "salt": "1701940627", "signature": "0x8185c0bc38ee22ac6cfd9eee078f0526b47c2b31d31f5fdaaa66b8c1ddef930960a1206939fcbf9074471bdeb0fe4875e313616e838ba378096fef6e8fb408491c", "status": "3", "takerAssetAddress": "0x0000000000000000000000000000000000000000", "takerRate": "0.059879938044285714", "takerTokenAddress": "0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "takingAmount": "35.000000000000000000" } ], "msg": "" } ```
- [Cancellation of limit order calldata](https://web3.okx.com/onchainos/docs/waas/dex-query-limit-order-cancel.md) {/* api-page */} # Cancellation of limit order calldata Cancellation of limit order calldata. ### Request address GET `https://web3.okx.com/api/v5/dex/aggregator/limit-order/cancel/calldata` ### Request parameters | Parameter | Type | Required | Description | |-------------------|--------|------------|---------------| | orderHash | String | Yes | order hash | ### Response parameters | Parameter | Type | Description | |----------------------|--------|---------------| | data | string | calldata | ### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/limit-order/cancel/calldata?orderhash=xxxx' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code": "0", "data": "0xe2cf089e0000000000000000000000000000000000000000000000000000018c43b2a04000000000000000000000000053e0bca35ec356bd5dddfebbd1fc0fd03fabad390000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa84174000000000000000000000000c171a1caa36b1c9e2c56fe71a24ceac127ff5ae4000000000000000000000000c171a1caa36b1c9e2c56fe71a24ceac127ff5ae400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d15c50616925b800000000000000000000000000000000000000000000000000000000002160ec00000000000000000000000000000000000000000000000000000000002160ec00000000000000000000000000000000000000000000000000000018c524f31b80000000000000000000000000000000000000000000000000000000000010001", "msg": "" } ``` - [Query limit order](https://web3.okx.com/onchainos/docs/waas/dex-query-limit-order.md) {/* api-page */} # Query limit order Query status of a DEX limit order. ### Request address GET `https://web3.okx.com/api/v5/dex/aggregator/limit-order/detail` ### Request parameters | Parameter | Type | Required | Description | |-------------------|--------|------------|-----------------------------------------------------------------------------------------------| | orderHash | String | Yes | orderHash | ### Response parameters | Parameter | Type | Description | |----------------------|--------|-----------------------------------------| | createTime | string | Order creation time | | expireTime | string | Current order’s effective deadline | | failureReason | string | Error message (if any) | | orderHash | string | orderHash | | signature | string | signature | | chainId | string | chainID (e.g. `1`: Ethereum, see list of [chain IDs](./walletapi-resources-supported-networks) for more) | | makerAssetAddress | string | The wallet address for current transaction | | makerTokenAddress | string | The contract address of a token to be sold | | makingAmount | string | The number of a token to be sold | | takerTokenAddress | string | The contract address of a token to be bought | | takingAmount | string | The number of a token to be bought | | makerRate | string | takingAmount/makingAmount | | takerRate | string | makingAmount/takingAmount | | receiver | string | Default is zero address, and the recipient’s assets will be sent to the address of the limit order creator. If you set a value, the asset will be sent to the current address. | | remainingMakerAmount | string | Remaining tradable quantity | | salt | string | random number salt as idempotent identifier
Current timestamp (second value) | | status | string | Order status (1 - Valid orders, 2 - Temporarily invalid orders, 3 - Occupied orders , 4 - Expired, 5 - Cancelled, 6 - Success, 7 - Failed orders.) | | takerAssetAddress | string | Default is zero address, and everyone can fill the current limit order. If you set a value, the limit order will only be executable at the specified address. |
### Request example ```shell curl --location --request GET 'https://web3.okx.com/api/v5/dex/aggregator/limit-order/detail?orderHash=0xf1852a5c82b9ff8919aaacce31325f4a778603471c2e8fa8d80583824c21e97a' \ --header 'OK-ACCESS-PROJECT: 86af********d1bc' \ --header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \ --header 'OK-ACCESS-SIGN: leaV********3uw=' \ --header 'OK-ACCESS-PASSPHRASE: 1****6' \ --header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' ``` ### Response example ```json { "code":"0", "data":{ "createTime":"2023-10-13 14:22:47", "chainId":"137", "makerAssetAddress":"0xc171a1caA36b1c9e2C56fE71A24cEAC127FF5ae4", "makerRate":"2.000000000000000000", "makerTokenAddress":"0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "makingAmount":"3.000000000000000000", "takingAmount":"6.000000000000000000", "receiver":"", "remainingMakerAmount":"2.500000000000000000", "salt":"1697032618", "status":"1", "takerAssetAddress":"0x0000000000000000000000000000000000000000", "takerRate":"0.5", "takerTokenAddress":"0xc2132d05d31c914a87c6611c10748aeb04b58e8f" "expireTime":"2023-10-20 14:41:00", "failureReason":"", "orderHash":"0xf1852a5c82b9ff8919aaacce31325f4a778603471c2e8fa8d80583824c21e97a", "signature":"0x78645ba7ed8c0266e01e46302160aad94537dbac9a0c751b9c315a516f44f54765acd11c11ffc88c9dd7f74fa63c606506ab145f94592bbbcb3cf2bac1cb13a01b" }, "msg":"" } ```
- [Smart contract](https://web3.okx.com/onchainos/docs/waas/dex-limit-order-smart-contract.md) # Smart contract The contract addresses of OKX Limit Order ### DEX limit order router The contract addresses of OKX DEX router | Chain | DEX router address | |----------------|--------------------------------------------| | Ethereum | 0x2ae8947FB81f0AAd5955Baeff9Dcc7779A3e49F2 | | Optimism | 0x2ae8947FB81f0AAd5955Baeff9Dcc7779A3e49F2 | | Polygon | 0x2ae8947FB81f0AAd5955Baeff9Dcc7779A3e49F2 | | BNB Chain | 0x2ae8947FB81f0AAd5955Baeff9Dcc7779A3e49F2 | | OKC | 0x2ae8947FB81f0AAd5955Baeff9Dcc7779A3e49F2 | | Avalanche C | 0x2ae8947FB81f0AAd5955Baeff9Dcc7779A3e49F2 | | Fantom | 0x2ae8947FB81f0AAd5955Baeff9Dcc7779A3e49F2 | | Arbitrum | 0x2ae8947FB81f0AAd5955Baeff9Dcc7779A3e49F2 | ### Token approval A list of smart contracts for ERC-20 token approval | 链名称 | Approval contract address | |----------------|-------------------------------------------| | Ethereum | 0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f | | Optimism | 0x68D6B739D2020067D1e2F713b999dA97E4d54812 | | Polygon | 0x3B86917369B83a6892f553609F3c2F439C184e31 | | BNB Chain | 0x2c34A2Fb1d0b4f55de51E1d0bDEfaDDce6b7cDD6 | | OKC | 0x70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58 | | Avalanche C | 0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f | | Fantom | 0x70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58 | | Arbitrum | 0x70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58 | - [Error codes](https://web3.okx.com/onchainos/docs/waas/dex-limit-order-error-code.md) # Error codes | Code | HTTP status | Message | | ----- | ----------- | --------------------------------------------------------------------------------------- | | 0 | 200 | Succeeded | | 50011 | 429 | Rate limit reached. Please refer to API documentation and throttle requests accordingly | | 50014 | 400 | Parameter param0 cannot be empty | | 50026 | 500 | System error. Try again later | | 50103 | 401 | Request header "OK-ACCESS-KEY" cannot be empty | | 50104 | 401 | Request header "OK-ACCESS-PASSPHRASE" cannot be empty | | 50105 | 401 | Request header "OK-ACCESS-PASSPHRASE" incorrect | | 50106 | 401 | Request header "OK-ACCESS-SIGN" cannot be empty | | 50107 | 401 | Request header "OK-ACCESS-TIMESTAMP" cannot be empty | | 50111 | 401 | Invalid OK-ACCESS-KEY | | 50112 | 401 | Invalid OK-ACCESS-TIMESTAMP | | 50113 | 401 | Invalid signature | | 51000 | 400 | Parameter param0 error | | 80000 | 200 | Repeated request | | 82000 | 200 | Insufficient liquidity | | 82001 | 500 | The commission service is not available during the upgrade | | 82102 | 200 | Minimum amount is 0 | | 82103 | 200 | Maximum amount is 0 | | 82104 | 200 | This token is not supported | | 82105 | 200 | This chain is not supported | - [FAQ](https://web3.okx.com/onchainos/docs/waas/dex-limit-order-faq.md) # FAQ ## What is the difference between a limit order and a swap? A swap is executed at the real-time market price, whereas a limit order allows trading at a specified price, granting the trader control over pricing. Swaps are immediately executed and don’t require waiting. In contrast, a limit order is executed only when the token’s price reaches the set limit. ## Who is the counterparty for a limit order? The API limit order is integrated into the OKX DEX to provide liquidity. The counterparties in this case are the users of OKX DEX. Users trading on OKX DEX can complete a transaction once they match an execution path coming from a limit order. ## How are network fees charged? Network fees for limit orders are incurred only during the execution of an order. Placing or withdrawing a limit order doesn’t incur any network fees. In the context of API limit orders on OKX DEX, the network fees are borne by the transactions’ counterparties. ## Why doesn’t an order execute immediately even when the market price reaches the set limit? Non-execution can occur for two reasons: 1. If the market price reaches the limit price but there’s insufficient liquidity to fulfill the order, the order can’t be executed. 2. If there’s no available counterparty on OKX DEX to carry out the transaction, the order remains unexecuted. ## Why can’t I sell ETH with a limit order? ETH can’t be sold via a limit order because it isn’t an ERC-20 token. Limit orders on OKX DEX are currently designed only for ERC-20 tokens. If you want to sell ETH using a limit order, you should first wrap your ETH and use WETH (Wrapped ETH) as the sell token. - [DEX Widget](https://web3.okx.com/onchainos/docs/waas/dex-widget-home.md) # DEX Widget - [使用 Widget](https://web3.okx.com/onchainos/docs/waas/dex-widget.md) # 使用 Widget 本文将告诉你如何将功能强大的欧易 Widget 与你的产品进行整合,让你只需 30 分钟即可搭建一个高效交易界面! ## 安装 ```bash yarn add @okxweb3/dex-widget // or npm install @okxweb3/dex-widget // or pnpm add @okxweb3/dex-widget ``` ## 快速开始 下方的例子将向你演示如何在一个 React 项目中使用 `@okxweb3/dex-widget`。你还可以通过此[链接](https://github.com/okx/dex-widget/tree/develop/packages/widget-configurator/src/react-cra)查看更多例子。 实际 Demo:https://okx.github.io/dex-widget/ ```javascript import React, { useRef, useEffect } from 'react'; import ReactDOM from 'react-dom/client'; import { createOkxSwapWidget } from '@okxweb3/dex-widget'; function App() { const widgetRef = useRef(); useEffect(() => { const params = { width: 375, providerType: 'EVM', }; const provider = window.ethereum; const listeners = [ { event: 'ON_CONNECT_WALLET', handler: () => { provider.enable(); }, }, ]; const instance = createOkxSwapWidget(widgetRef.current, { params, provider, listeners, }); return () => { instance.destroy(); }; }, []); return
; } const root = ReactDOM.createRoot(document.getElementById('root')); root.render( ); ``` ## 钱包提供方 如果需要连接钱包,你可以从你的应用中传递钱包提供方信息。同时添加 ON_CONNECT_WALLET 事件,即可无缝连接并使用 Widget。 - 如果提供方是在 Ethereum 或其他 EVM 网络上,它必须要符合 EIP-1193 才能创建交易界面。 - 如果提供方是在 Solana 网络上,它必须从你的应用中传递钱包提供方的信息。 ```typescript import { createOkxSwapWidget, ProviderType } from '@okxweb3/dex-widget'; const widgetEthInstance = createOkxSwapWidget( document.getElementById('widget'), { params: { providerType: ProviderType.EVM, }, provider: window.ethereum, // e.g. window.okexchain } ); const widgetSolanaInstance = createOkxSwapWidget( document.getElementById('widget'), { params: { providerType: ProviderType.SOLANA, }, provider: window.solana, // window.okexchain.solana } ); ``` Rainbow 连接钱包组件的示例可参考这个[链接](https://github.com/okx/dex-widget/blob/faf69c76b90268f2352507c9a90fb37bb80fdbc7/example/widget-demo/src/main.tsx#L22)。 ## 参数 下方表格内是对 Params 的描述。 | 参数 | 类型 | 默认值 | 描述 | | ----------------- | --------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------- | | `width` | `number` | 450 | 用 css 值 (px) 表示的 Widget 宽度。如果未设置宽度,则宽度的展示样式为:>767px 显示为 450 px,<768 px 显示为 100%,< 375 px 则显示为 375 px。 | | `theme` | `THEME` | light | 兑换 Widget 提供默认的日间、夜间主题选项。你可以按下方示例来切换 Widget 的主题。 | | `lang` | `string` | en_us | 你可以调整 Widget 所使用的语言,请在多语言配置部分了解更多细节信息。 | | `tradeType` | `TradeType` | auto | 交易的类型,可以是"swap"、"bridge",或"auto"。注意:"自动"包含"swap"和"bridge"。 | | `chainIds` | `Array` | \[] | 承载单链兑换的区块链的 ID,请在 ChainId 配置部分查看你可选的所有网络。 | | `feeConfig` | `IFeeConfig` | \{} | 你可以选择在 Widget 中为所有交易类型设置一个费率,请在自定义费率部分了解详情。 | | `tokenPair` | `ITokenPair` | \{} | 你所设定使用的兑换默认代币对,请在默认币对配置部分了解详情。 | | `bridgeTokenPair` | `ITokenPair` | \{} | 你所设定使用的跨链默认代币对,请在默认币对配置部分了解详情。 | | `providerType` | `ProviderType` | ' ' | ProviderType 是和提供方一致的类型参数,例如,如果提供方是 Solana,那么 providerType 就会是 SOLANA。 | | `defaultTab` | `TradeTab` | 'swap' | 可设定默认打开为单链、跨链。1.3.16 版本及后续版本支持。 | | `walletName` | `string` | ' ' | 连接的钱包名称,该参数帮助 DEX widget 持续改进产品和服务,来提供更好的交互体验。1.3.16 版本及后续版本支持。 | ## 类型描述 ```typescript interface IFeeConfig { [key: string]: { feePercent?: string | number; referrerAddress?: { [key: string]: { feePercent: string | number; }; }; }; } interface ITokenPair { fromChain: string | number; toChain: string | number; fromToken?: string; toToken?: string; } enum ProviderType { EVM = 'EVM', SOLANA = 'SOLANA', WALLET_CONNECT = 'WALLET_CONNECT', } enum TradeType { SWAP = 'swap', BRIDGE = 'bridge', AUTO = 'auto', } enum THEME { LIGHT = 'light', DARK = 'dark', } ``` ## 多语言配置 | lang | 描述 | | -------- | ----------------------- | | `en_us` | English,默认 | | `zh_cn` | 简体中文 | | `zh_tw` | 繁體中文 | | `fr_fr` | Français (Afrique) | | `id_id` | Bahasa Indonesia | | `ru_ru` | Русский | | `tr_tr` | Türkçe | | `vi_vn` | Tiếng Việt | | `de_de` | Deutsch | | `it_it` | Italiano | | `pl_pl` | Polski | | `pt_pt` | Português (Portugal) | | `es_es` | Español (España) | | `pt_br` | Português (Brasil) | | `es_419` | Español (Latinoamérica) | | `cs_cz` | Čeština | | `ro_ro` | Română | | `uk_ua` | Українська | | `ar_eh` | العربية | | `nl_nl` | Nederlands | ## ChainId 配置 | 网络 | ChainId | 主网币合约地址 | | ----------- | ------- | ------------------------------------------ | | Ethereum | 1 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Solana | 501 | 11111111111111111111111111111111 | | Arbitrum | 42161 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Base | 8453 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Sonic | 146 | 0x4Efa4b8545a3a77D80Da3ECC8F81EdB1a4bda783 | | Optimism | 10 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | zkSync Era | 324 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | BNB Chain | 56 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Linea | 59144 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Polygon | 137 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Avalanche C | 43114 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Mantle | 5000 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Scroll | 534352 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | X layer | 196 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | | Blast | 81457 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE | ## 默认币对配置 `tokenPair`:如果没有配置,则单链兑换将默认设置在 Ethereum 网络,且 `fromToken` 为 ETH,`toToken` 为 USDC。 `bridgeTokenPair`:如果没有配置,则跨链兑换将默认设置为从 Ethereum 跨链至 BNB Chain,且 `fromToken` 为 ETH,`toToken` 为 BNB。 ```javascript import React, { useEffect, useRef } from 'react'; import { OkxSwapWidgetParams, ProviderType, TradeType, } from '@okxweb3/dex-widget'; const provider = window.ethereum; export function EvmWidget() { const widgetRef = useRef(); const params = { chainIds: ['1', '10'], lang: 'zh_cn', providerType: ProviderType.EVM, theme: 'dark', tradeType: TradeType.AUTO, tokenPair: { fromChain: 1, //ETH toChain: 1, // ETH fromToken: '0xdac17f958d2ee523a2206206994597c13d831ec7', // USDT toToken: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // ETH }, bridgeTokenPair: { fromChain: 1, //ETH toChain: 56, // BNB fromToken: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // ETH toToken: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // BNB }, }; const initialConfig = { params, provider, listeners: [ { event: 'ON_CONNECT_WALLET', handler: (token, preToken) => { provider.enable(); }, }, ], }; useEffect(() => { const widgetHandler = createOkxSwapWidget(widgetRef.current, initialConfig); return () => { widgetHandler?.destroy(); }; }, []); return
; } ``` | 参数 | 类型 | 描述 | | --------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------- | | fromChain | String | fromToken 所属的源链 ID(例如,1:Ethereum,可在 ChainId 配置部分查看所有已支持的网络和对应的链 ID)。 | | fromToken | String | 试图卖出的代币的合约地址,例如 ETH:0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE。如果 fromToken 是某一区块链的主网币,请查看链 ID 以获取合约地址。 | | toChain | String | toToken 所属的目标链 ID(例如,1:Ethereum,可在 ChainId 配置部分查看所有已支持的网络和对应的链 ID)。 | | toToken | String | 试图买入的代币的合约地址,例如 USDC:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48。如果 toToken 是某一区块链的主网币,请查看链 ID 以获取合约地址。 | ## Widget 更新 ### updateParams 可更新的属性:theme、lang、width ```javascript // 1. Create and initialize the widget const widgetHandler = createOkxSwapWidget(container, initialConfig); // 2. Update the widget's parameters (e.g., change theme or size) widgetHandler.updateParams({ width: 700, theme: 'light', lang: 'tr_tr', }); ``` ### updateProvider Widget 支持 EVM 和 Solana。当从 EVM 切换到 Solana 时,请记得更新相应的 Widget 提供方,反之亦然。 如果首次渲染时没有传递提供方信息,并想要 Widget 响应钱包绑定,就需要调用 updateProvider。 更新 provider 可同时增加 walletName 参数,用来识别用户所连接的插件钱包。 ```javascript // 3. Update the provider if the user connects a different wallet, EVM => SOLANA const walletName = 'phantom'; widgetHandler.updateProvider(window.solana, ProviderType.SOLANA, walletName); // SOLANA => EVM // widgetHandler.updateProvider(window.ethereum, ProviderType.EVM); ``` ### updateListeners 你可以更新 Widget 监听的事件。 ```javascript // 4. Modify event listeners to handle new types of events widgetHandler.updateListeners([ { event: OkxEvents.ON_FROM_CHAIN_CHANGE, handler: (payload) => { // }, }, ]); ``` - Listeners 主要用于监听 Widget 向外部暴露的接口,通过不同事件进行定制化处理。而 updateListeners 则用于在切换链后更新定制化处理。 - 通过添加事件监听器,可以捕获并处理从 iframe 中传递出来的事件数据。这些数据通常是 iframe 内部发生的事件或状态变化,并通过事件传递到外部页面。 - 接收到的数据可以根据需求进行灵活处理和操作。这意味着你可以根据传递的数据类型或内容,执行不同的逻辑或更新界面元素。 - 通过 updateListeners 方法,你可以为不同类型的事件(如 `OkxEvents.ON_FROM_CHAIN_CHANGE`)添加处理函数。当事件触发时,处理函数会接收到相关的 payload 数据,以便你进一步操作。 ### destroy 当清除 Widget 模块时,调用此方法。 ```javascript const widgetHandler = createOkxSwapWidget(container, initialConfig); widgetHandler.destroy(); ``` **注意:** 每当你刷新和更新时,请确保调用 destroy 方法来清除先前绑定的事件,以避免出现重复订单请求。 ## 事件监听 Widget 为 ON_CONNECT_WALLET 和 ON_FROM_CHAIN_CHANGE 提供事件监听。 - `ON_CONNECT_WALLET`:当 Widget 未连接钱包并点击了连接钱包按钮时触发此事件。 - `ON_FROM_CHAIN_CHANGE`:当 fromChain 发生变化时会触发此事件。 - `ON_SUBMIT_TX`:当交易完成后触发此事件,返回该交易的 txHash 以及 chainId;1.3.16 版本后支持。 使用方法如下: ```typescript import { createOkxSwapWidget, OkxSwapWidgetParams, OkxEventListeners, OkxEvents, } from '@okxweb3/dex-widget'; const params: OkxSwapWidgetParams = { // ... }; const listeners: OkxEventListeners = [ { event: OkxEvents.ON_CONNECT_WALLET, handler: () => { // open connect wallet method, eg openConnectModal of the rainbow kit. window.ethereum.enable(); }, }, { event: OkxEvents.ON_FROM_CHAIN_CHANGE, handler: (token) => { // }, }, { event: OkxEvents.ON_SUBMIT_TX, handler: (res) => { console.log( `Transaction submitted successfully, txHash: ${res.data.txHash}` ); }, }, ]; const { updateListeners } = createOkxSwapWidget(container, { params, listeners, provider, }); ``` - [Introduction](https://web3.okx.com/onchainos/docs/waas/marketplace-introduction.md) # Introduction Welcome to the developers' documentation for the OKX NFT Marketplace, a one-stop decentralized NFT aggregated exchange platform that supports multi-chain NFT creations and cross-platform transactions. OKX NFT Marketplace provides real-time on-chain data for users and developers, and is dedicated to building a decentralized multi-chain NFT ecosystem. ## NFT aggregator OKX NFT Marketplace combines the order book depth from multiple mainstream marketplaces and platforms to provide up-to-date order data for developers and users. OKX Marketplace also includes abundant NFT collection data, and supports real-time and accurate on-chain data. Marketplaces that support aggregation are OKX NFT, Opensea, Magic Eden, Looksrare, IMX, and X2Y2. OKX NFT Marketplace allows NFT holders to list their NFTs on multiple platforms simultaneously with the least of efforts and the best liquidity. Marketplaces that support listings are OKX NFT, Opensea, Looksrare, and Magic Eden. OKX NFT Marketplace supports ETH, OKTC, BSC, Polygon, IMX, AVAX-C, Solana, Arbitrum One, zkSync Era, Aptos, Optimism, Klaytn, Arbitrum Nova, Base and Linea. We also plan to support NFT aggregated transactions on more chains. ## Issuance Marketplace & Secondary Marketplace Issuance Marketplace: OKX NFT's exclusive primary issuance platform selects high-quality NFT projects for completely decentralized offerings, allowing users to obtain their preferred NFT at lower prices in the issuance market as soon as possible. Secondary Marketplace: OKX NFT Marketplace lets users conduct peer-to-peer transactions and helps both buyers and sellers seek the best price. OKX is dedicated to providing users with an efficient and low-cost NFT trading experience with high liquidity. ## Contract architecture ### Overview ![contract-overview-uml](../images/contract-overview-uml.jpg) #### Features that EVM contract supports - Batch purchasing - Collection offers - Listing - Offer functions - Instant royalties for the creator - ERC-2981 royalties support #### Features that Solana contract supports - Batch purchasing - Listing - Instant royalties for the creator ### OKX NFT Marketplace contract Users authorize the OKX secondary market to authorize ```union approve``` contract to use tokens (this step is not required for native tokens) Users then call the OKX ```Aggregator``` contract interface to interact with the OKX secondary market, such as making bids or listing orders ### OKX NFT aggregator contract Develop ```Adapter``` contracts for different markets Register ```Adapter``` contracts to ```Market Registry``` contracts OKX ```Aggregator``` contracts are linked to different markets via ```Adapter``` contracts; for instance, OKX ```Aggregator``` contracts interact with ```OpenSea``` markets via ```OpenSea Adapter``` contracts

![contract-architecture-image](../images/contract-architecture-img.jpg) ## How to start Go to [NFT Market](https://web3.okx.com/web3/marketplace/nft) to begin your NFT journey. [//]: # (![nft-wallet](./images/nft-wallet.png)) Go to the marketplace and choose NFTs to bid or purchase directly. Visit your profile to view your NFT assets and begin trading. [//]: # (![nft-asset](./images/nft-asset.png)) If you are a digital artist, you are welcome to make your own NFT on our Create NFT page. [//]: # (![nft-create](./images/nft-create.png)) ## Deployed contract ### OKX NFT aggregator contract | **Number** | **Network** | **Contract address** | |------------|---------------|--------------------------------------------| | 1 | Ethereum | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 2 | OKTC | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 3 | BNB Chain | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 4 | Polygon | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 5 | Avalanche-C | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 6 | Arbitrum One | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 7 | Arbitrum Nova | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 8 | zkSync Era | 0x444b2Fd4395Ec890fbC492753DCe1bE2fC8Ff63D | | 9 | Optimism | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 10 | Klaytn | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 11 | Base | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 12 | Linea | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 13 | opBNB | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 14 | Polygon zkEVM | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | ### OKX self-operated marketplace contract | **Number** | **Network** | **Contract address** | |------------|---------------|--------------------------------------------| | 1 | Ethereum | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 2 | OKTC | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 3 | BNB Chain | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 4 | Polygon | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 5 | Avalanche-C | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 6 | Arbitrum One | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 7 | Arbitrum Nova | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 8 | zkSync Era | 0xd756E8070b33a35E42f00140Ac92c4b4e0bBfb82 | | 9 | Optimism | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 10 | Klaytn | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 11 | Base | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 12 | Linea | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 13 | opBNB | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 14 | Polygon zkEVM | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | - [Runes API](https://web3.okx.com/onchainos/docs/waas/marketplace-runes-api.md) # Runes API - [Get Runes collection](https://web3.okx.com/onchainos/docs/waas/marketplace-get-runes-collection.md) # Get Runes collection This API is used to get runes information, including the number of holders, collection link, transaction volume, number of transactions, and floor price. ### Request address GET `https://web3.okx.com/api/v5/mktplace/nft/runes/detail` ### Request param | **Parameter** | **Type** | **Required** | **Description** | |-----------------|----------|--------------|---------------------------------------------------------------------------| | runesId | String | Yes | runesId, supports batch queries, separated by ',', e.g., 840000:3,840000:28 | ### Response param | **Parameter** | **Type** | **Description** | |-------------------|----------|-------------------------------------------------------------------------------------------------------| | runesId | String | runeid | | name | String | Name of the rune | | spacename | String | Rune name with dots | | maxMintNumber | String | Maximum mint number | | mintedNumber | String | Minted number | | limitPerMint | String | Limit per mint | | deployedTime | Long | Deployment time | | startBlock | String | Start block | | endBlock | String | End block | | symbol | String | Symbol | | divisibility | Integer | Precision | | collectionUrl | String | OKX collection link | | totalVolume | String | Total volume in BTC | | usdTotalVolume | String | Total volume in USD | | marketCap | String | Market cap in BTC | | usdMarketCap | String | Market cap in USD | | floorprice | String | Floor price in Sats | | usdFloorPrice | String | Floor price in USD | | holders | Integer | Number of holders | | salesCount | Integer | Number of sales | ### Request example ```shell curl --location 'https://web3.okx.com/api/v5/mktplace/nft/runes/detail?runesId=840000%3A3%2C840000%3A28' \ --header 'OK-ACCESS-PASSPHRASE: xxx' \ --header 'OK-ACCESS-KEY: xxx' \ ``` ### Response example ```json { "code": 0, "data": [ { "collectionUrl": "https://web3.okx.com/web3/marketplace/runes/token/DOG•GO•TO•THE•MOON/840000:3", "deployedTime": 1713571767, "divisibility": 5, "marketData": { "floorPrice": "10.6509577683", "holders": 72903, "marketCap": "10651.030343051788712385", "salesCount": 35436, "totalVolume": "1124.64783456999999", "usdFloorPrice": "0.006598097922137557", "usdMarketCap": "659814288.103509427870310934", "usdTotalVolume": "69670133.915076187380516" }, "maxMintNumber": "100000000000", "mintedNumber": "100000000000", "name": "DOG•GO•TO•THE•MOON", "runesId": "840000:3", "spaceName": "DOGGOTOTHEMOON", "startBlock": 840000, "symbol": "🐕" } ], "msg": "" } ``` - [Get Popular collections](https://web3.okx.com/onchainos/docs/waas/marketplace-runes-popular-collections.md) # Get Popular collections This API is used to get trading data of popular collections. ### Request address GET `https://web3.okx.com/api/v5/mktplace/nft/runes/get-hot-collection` ### Request param | **Parameter** | **Type** | **Required** | **Description** | |-----------------|----------|--------------|---------------------------------------------------------------------------| | timeType | Integer | No | Returns data for N projects, sorted by transaction volume in the specified time range. Enum values: 1. 24h 2. 7d 3. 30d 4. all Defaults to 24h if not provided. | | cursor | String | No | Cursor for pagination, default is empty. | | limit | Integer | No | Page size for query results, default is 10. | ### Response parameters | **Parameter** | **Type** | **Description** | |-------------------|----------|-------------------------------------------------------------------------------------------------------| | cusor | String | Cursor for pagination | | runesId | String | runeid | | name | String | Rune name | | spaceName | String | Rune name with dots | | maxMintNumber | String | Maximum mint number | | mintedNumber | String | Minted number | | limitPerMint | String | Limit per mint | | deployedTime | Long | Deployment time | | startBlock | String | Start block | | endBlock | String | End block | | symbol | String | Symbol | | divisibility | Integer | Precision | | collectionUrl | String | OKX collection link | | totalVolume | String | Transaction volume in BTC and USD | | usdTotalVolume | String | Transaction volume in USD | | marketCap | String | Market cap in BTC | | usdMarketCap | String | Market cap in USD | floorprice | String | Floor price in Sats | | usdFloorPrice | String | Floor price in USD | | holders | Integer | Number of holders | | salesCount | Integer | Number of sales | | volumeGains | String | Transaction volume growth | ### Request example ```shell curl --location 'https://web3.okx.com/api/v5/mktplace/nft/runes/get-hot-collection?timeType=2&cursor=Mg%3D%3D' \ --header 'OK-ACCESS-PASSPHRASE: xxxxxx' \ --header 'OK-ACCESS-KEY: xxxx' \ ``` ### Response example ```json { "code":0, "data":{ "items":[ { "collectionUrl":"https://web3.okx.com/web3/marketplace/runes/token/DOG•GO•TO•THE•MOON/840000:3", "deployedTime":1713571767, "divisibility":5, "marketData":{ "floorPrice":"10.6509577683", "holders":72903, "marketCap":"10651.030343051788712385", "salesCount":35436, "totalVolume":"1124.64783456999999", "usdFloorPrice":"0.006598097922137557", "usdMarketCap":"659814288.103509427870310934", "usdTotalVolume":"69670133.915076187380516" }, "maxMintNumber":"100000000000", "mintedNumber":"100000000000", "name":"DOG•GO•TO•THE•MOON", "runesId":"840000:3", "spaceName":"DOGGOTOTHEMOON", "startBlock":840000, "symbol":"🐕" } ], "cursor":"" }, "msg":"" } ``` - [Get sale activity](https://web3.okx.com/onchainos/docs/waas/marketplace-runes-trade-history.md) # Get sale activity This API is used to get the transaction data under the collection (latest transaction price, quantity), supporting retrieving specific project transaction events by runesId. ### Request address GET `https://web3.okx.com/api/v5/mktplace/nft/runes/trade-history` ### Request parameter | **Parameter** | **Type** | **Required** | **Description** | |-----------------|----------|--------------|---------------------------------------------------------------------------| | runesIds | String | No | Unique token identifier; if multiple, separate by commas (,) with a maximum of 20. An empty string will query the transaction history of all tokens. | | cursor | String | No | Cursor pointing to the sorting sequence to retrieve | | limit | Integer | No | Pagination size (default value 10, maximum 100). Returns the maximum number of transaction histories | | startTime | Long | No | Start time of the transaction activity (in seconds) | | endTime | Long | No | End time of the transaction activity (in seconds) | ### Response parameter | **Parameter** | **Type** | **Description** | |-------------------|----------|-------------------------------------------------------------------------------------------------------| | runesId | String | runesId | | name | String | Token name | | txHash | String | Transaction hash | | typeName | String | Activity type name (SALE, TRANSFER, etc.) | | amount | String | Token amount | | from | String | From address | | to | String | To address | | createOn | Date | Creation time | | platformName | Long | Platform name | | currency | String | Total price - currency | | currencyUrl | String | Total price - currency URL | | satPrice | BigDecimal | Total price in sat | | price | BigDecimal | Total price in BTC | | usdPrice | BigDecimal | Total price in USD | | currency | String | Unit price - currency | | currencyUrl | String | Unit price - currency URL | | satPrice | BigDecimal | Unit price in sat | | price | BigDecimal | Unit price in BTC | | usdPrice | BigDecimal | Unit price in USD | | status | Integer | Status (1: Success, 2: Pending) | ### Request example ```shell curl --location --request GET 'https://beta.okex.org/api/v5/mktplace/nft/runes/trade-history?runesIds=840000:3&type=SALE&startTime=1713604337&endTime=1713607937' \ --header 'OK-ACCESS-KEY: XXXX' \ --header 'OK-ACCESS-PASSPHRASE: XXXX' ``` ### Response example ```json { "code": 0, "data": { "activityList": [ { "amount": "3360", "createOn": 1714398184000, "from": "bc1p0a9xxqvh7c4l3xzcxuhdmsntlau69jnzu79jau20fza8676lfwmqnyy393", "name": "RSIC•GENESIS•RUNE", "platformName": "OKX", "runesId": "840000:28", "status": 1, "to": "bc1pnhukwhm2vmgsepkfxjyccgv2l0h2nu4fq0dchxdlkjpssmt2k45qkvnqjr", "totalPrice": { "currency": "BTC", "currencyUrl": "https://static.coinall.ltd/cdn/nft/4834651a-7c4e-4249-91c1-cf680af39dc0.png", "price": "0.00079968", "satPrice": "79968", "usdPrice": "49.54137552" }, "txHash": "6ef9a11965cd8771a383f6447a5cdf438832368c86a46fa465aee1cd59cc4ad7", "typeName": "SALE", "unitPrice": { "currency": "BTC", "currencyUrl": "https://static.coinall.ltd/cdn/nft/4834651a-7c4e-4249-91c1-cf680af39dc0.png", "price": "0.000000238", "satPrice": "23.8", "usdPrice": "0.014744457" } } ], "cursor": "MTMyMjM3MTEwNTQyMzM2MTE=", "hasNext": true }, "msg": "" } ``` - [Get asset for an address](https://web3.okx.com/onchainos/docs/waas/marketplace-runes-asset.md) # Get asset for an address This API is used to get rune assets under a specific address. ### Request address GET `https://web3.okx.com/api/v5/mktplace/nft/runes/get-owned-asserts` ### Request param | **Parameter** | **Type** | **Required** | **Description** | |-----------------|----------|--------------|---------------------------------------------------------------------------| | runesId | String | Yes | Unique token identifier | | walletAddresses | String | Yes | Wallet address(es), separated by commas (,) if multiple; up to 20 wallet addresses | | cursor | String | No | Cursor pointing to the sorting sequence to retrieve (maximum 1,000) | | limit | Integer | No | Pagination size (default value 10, maximum 100). Returns the maximum number of entries | ### Response param | **Parameter** | **Type** | **Description** | |-------------------|----------|-------------------------------------------------------------------------------------------------------| | assetId | String | id (DB primary key, no actual meaning) | | tickerType | Integer | Token type (4-Runes) | | ticker | String | Token name | | tickerId | String | Token id | | ownerAddress | String | Wallet address | | amount | String | XRC20 amount in the UTXO | | chain | Integer | Chain | | inscriptionNum | String | Inscription number | | utxoTxHash | String | Transaction hash | | utxoVout | Integer | utxoVout | | utxoValue | String | utxoValue | | txHash | String | Transaction hash | | name | String | Token name | | tickerIcon | String | Token icon link | | status | Integer | Listing status (0-unlisted, 1-listed, 2-pending) | | listTime | Long | Listing time | | orderId | Long | Order id | | confirmations | Long | Block height information | | currency | String | Total price - currency | | currencyUrl String Total price - currency URL | | satPrice | BigDecimal | Total price in sat | | price | BigDecimal | Total price in BTC | | usdPrice | BigDecimal | Total price in USD | | currency | String | Unit price - currency | | currencyUrl | String | Unit price - currency URL | | satPrice | BigDecimal | Unit price in sat | | price | BigDecimal | Unit price in BTC | | usdPrice | BigDecimal | Unit price in USD | | unavailable | Integer | 1 - UTXO contains multiple Atomicals assets; 2 - UTXO contains multiple protocol assets | | symbol | String | Symbol | ### Request example ```shell curl --location --request GET 'https://beta.okex.org/api/v5/mktplace/nft/runes/get-owned-asserts?runesId=840000:3&walletAddresses=bc1p3fj806enwnmz04444mpm42ykgdcta9p5mvzx46hp8wmg2knpwxpq0k46x9&limit=10' \ --header 'OK-ACCESS-KEY: XXXX' \ --header 'OK-ACCESS-PASSPHRASE: XXXX' ``` ### Response example ```json { "code": 0, "data": { "cursor": "1", "items": [ { "amount": "500000", "assetId": "28912795273673038", "chain": 0, "confirmations": null, "inscriptionNum": "", "listTime": 1714399069, "name": "DOG•GO•TO•THE•MOON", "orderId": 201296, "ownerAddress": "bc1p3fj806enwnmz04444mpm42ykgdcta9p5mvzx46hp8wmg2knpwxpq0k46x9", "status": 1, "symbol": "🐕", "ticker": "DOG•GO•TO•THE•MOON", "tickerIcon": "https://static.coinall.ltd/cdn/web3/currency/token/1714125941761.png/type=png_350_0", "tickerId": "840000:3", "tickerType": 4, "totalPrice": { "currency": "BTC", "currencyUrl": "https://static.coinall.ltd/cdn/nft/4834651a-7c4e-4249-91c1-cf680af39dc0.png", "price": "0.031895", "satPrice": "3189500", "usdPrice": "1979.7003235" }, "txHash": "", "unavailable": null, "unitPrice": { "currency": "BTC", "currencyUrl": "https://static.coinall.ltd/cdn/nft/4834651a-7c4e-4249-91c1-cf680af39dc0.png", "price": "0.00000006379", "satPrice": "6.379", "usdPrice": "0.003959400647" }, "utxoTxHash": "ce302f5c946ff3ef502eade58405d64b545d59de9fcd731314b88ddadf709ca6", "utxoValue": "546", "utxoVout": 2 } ] }, "msg": "" } ``` - [Get Runes listing](https://web3.okx.com/onchainos/docs/waas/marketplace-runes-listings.md) # Get Runes listing This API is used to get listings on OKX Runes, supporting retrieving specific collection listing information by runesId. ### Request address GET `https://web3.okx.com/api/v5/mktplace/nft/runes/get-runes-order-list` ### Request parameters | **Parameter** | **Type** | **Required** | **Description** | |-----------------|----------|--------------|---------------------------------------------------------------------------| | runesId | String | Yes | runesId, the unique identifier for the runes token | | cursor | String | No | Cursor pointing to the sorting sequence to retrieve (maximum 1,000) | | limit | Integer | No | Pagination size (default value 10, maximum 100). Returns the maximum number of orders | | sortBy | String | No | Order sorting rule, default is ascending unit price (unitPriceAsc). Sorting enum: unitPriceAsc, unitPriceDesc, totalPriceAsc, totalPriceDesc, listedTimeAsc, listedTimeDesc | ### Response parameters | **Parameter** | **Type** | **Description** | |-------------------|----------|-------------------------------------------------------------------------------------------------------| | assetId | Integer | id (DB primary key, no actual meaning) | | tickerType | String | Token type (4-Runes) | | ticker | Integer | Token name | | tickerId | String | Token id | | ownerAddress | String | Wallet address | | amount | String | XRC20 amount in the UTXO | | chain | Integer | Chain | | inscriptionNum | String |Inscription number | | utxoTxHash | String | Transaction hash | | utxoVout | Integer | utxoVout | | utxoValue | String | utxoValue | | txHash | String | Transaction hash | | name | String | Token name | | tickerIcon | String | Token icon link | | status | Integer | Listing status (0-unlisted, 1-listed, 2-pending) | | listTime | Long | Listing time | | orderId | Long | Order id | | confirmations | Long | Block height information | | currency | String | Total price - currency | | currencyUrl | String | Total price - currency URL | | satPrice | BigDecimal | Total price in sat | | price | BigDecimal | Total price in BTC | | usdPrice | BigDecimal | Total price in USD | | currency | String | Unit price - currency | | currencyUrl | String | Unit price - currency URL | | satPrice | BigDecimal | Unit price in sat | | price | BigDecimal | Unit price in BTC | | usdPrice | BigDecimal | Unit price in USD | | unavailable | Integer | 1 - UTXO contains multiple Atomicals assets; 2 - UTXO contains multiple protocol assets | | symbol | String | Symbol | ### Request example ```shell curl --location --request GET 'https://beta.okex.org/api/v5/mktplace/nft/runes/get-runes-order-list?runesId=840000:3' \ --header 'OK-ACCESS-KEY: XXXX' \ --header 'OK-ACCESS-PASSPHRASE: XXXX' ``` ### Response example ```json { "code": 0, "data": { "cursor": "1", "items": [ { "amount": "889806", "assetId": "28734126488062286", "chain": 0, "confirmations": null, "inscriptionNum": "", "listTime": 1714398972, "name": "DOG•GO•TO•THE•MOON", "orderId": 201268, "ownerAddress": "bc1pxav32udnt0062dlvmjn7tp3qneamudpg492t7qmxsu7m73ldd7uq768q8p", "status": 1, "symbol": "🐕", "ticker": "DOG•GO•TO•THE•MOON", "tickerIcon": "https://static.coinall.ltd/cdn/web3/currency/token/1714125941761.png/type=png_350_0", "tickerId": "840000:3", "tickerType": 4, "totalPrice": { "currency": "BTC", "currencyUrl": "https://static.coinall.ltd/cdn/nft/4834651a-7c4e-4249-91c1-cf680af39dc0.png", "price": "0.05472306", "satPrice": "5472306", "usdPrice": "3388.298650632" }, "txHash": "", "unavailable": null, "unitPrice": { "currency": "BTC", "currencyUrl": "https://static.coinall.ltd/cdn/nft/4834651a-7c4e-4249-91c1-cf680af39dc0.png", "price": "0.0000000615", "satPrice": "6.15", "usdPrice": "0.0038079078" }, "utxoTxHash": "80efaeffcbf70be91579afb631e45cd28df75b0883f45525d1bb6b04b21969f3", "utxoValue": "546", "utxoVout": 1015 } ] }, "msg": "" } ``` - [Create listing](https://web3.okx.com/onchainos/docs/waas/marketplace-runes-create-listing.md) # Create listing This API is used to list a single Runes inscription on the OKX platform. Before listing, you can [get wallet assets](./marketplace-runes-asset) (get the holding information of a specific token in the wallet) to first get the list of Runes inscriptions you hold. ### Request address POST `https://web3.okx.com/api/v5/mktplace/nft/runes/make-order` ### Request param | **Parameter** | **Type** | **Required** | **Description** | |-----------------|----------|--------------|---------------------------------------------------------------------------| | runesId | String | Yes | runes token's unique identifier, e.g., 840000:3 | | walletAddress | String | Yes | Wallet address holding the above runesId inscription | | utxo | String | Yes | UTXO where the rune token is located, format: txHash:vout, e.g., d578a0967605257f75be625cbdc2506f2a52f9135f56f302badab6a3da54e0d4:0 | | unitPrice | BigDecimal | Yes | Listing unit price of the inscription, in Satoshis | | totalPrice | BigDecimal | Yes | Listing total price of the inscription, in BTC | | psbt | String | Yes | Signed listing PSBT, currently only accepts base64-encoded PSBT. The UTXO containing the inscription must be placed in the input at index=1, and the receiving address and amount must be placed in the corresponding output at index=1 | ### Response param | **Parameter** | **Type** | **Description** | |-------------------|----------|-------------------------------------------------------------------------------------------------------| | code | Integer | Response result code, code=0 indicates success, other values indicate failure | | data | Object | Response result body, specific fields refer to response example | | msg | String | Result message, refer to this when code is not 0 | ### Request example ```shell curl --location 'https://web3.okx.com/api/v5/mktplace/nft/runes/make-order' \ --header 'OK-ACCESS-KEY: your apikey' \ --header 'OK-ACCESS-PASSPHRASE: your passphrase' \ --header 'Content-Type: application/json' \ --data '{ "runesId": "840000:3", "walletAddress": "bc1pud5f80a06y6jcwlllt2t5vdq24sd8d24f39jccay24dqhqmgelkq9dqghx", "utxo": "c1dd6736a19d7744353731c85f7f3b7fb9908041e03a1fe66507102e5af930ec:2", "unitPrice": 130000, "totalPrice": 1300000, "psbt": "j2li1jlkjsalkdfjsalkjdo" }' ``` ### Response example ```json { "code": 0, // code=0 indicates success, other values indicate failure "data": { "assetId": "1", // asset id of the listing }, "msg": "" } ``` - [Market API](https://web3.okx.com/onchainos/docs/waas/marketplace-api-reference.md) # Market API - [NFT API](https://web3.okx.com/onchainos/docs/waas/marketplace-nft-api.md) # NFT API - [Retrieve NFT details](https://web3.okx.com/onchainos/docs/waas/marketplace-retrieve-nft-details.md) {/* api-page */} # Retrieve NFT details This interface provides token details, the collection details of the token, the contract details of the token, and the token's attributes. ### Request address GET `https://web3.okx.com/api/v5/mktplace/nft/asset/detail` ### Request param | **Parameter** | **Type** | **Required** | **Description** | |-----------------|----------|--------------|---------------------------------------------------------------------------| | chain | String | Yes | Chain name refer to [Supported blockchains](./marketplace-supported-blockchains) for details | | contractAddress | String | Yes | Collection contract address, which must be a valid contract address | | tokenId | String | Yes | NFT's token ID | ### Response param | **Parameter** | **Type** | **Description** | |-------------------|----------|-------------------------------------------------------------------------------------------------------| | name | String | The name of the NFT | | tokenId | String | The token ID of the NFT | | tokenUri | String | NFT MetaData stored address | | image | String | An image of the item; note that this is the cached URL we store on our end | | imagePreviewUrl | String | A preview image of the item; note that this is the cached URL we store on our end | | imageThumbnailUrl | String | A thumbnail image of the item; note that this is the cached URL we store on our end | | animationUrl | String | A link to animation resource url for the item; note that this is the cached URL we store on our end | | attributes | Object | An object of the token [attributes model](./marketplace-nft-model#attributes-model) | | assetContracts | Object | An object of the token [asset contract model](./marketplace-collection-model#asset-contract-model) | | collection | Object | An object of the token [collection model](./marketplace-collection-model#collection-model) | ### Request example ```shell curl -X GET "https://web3.okx.com/api/v5/mktplace/nft/asset/detail" \ -H 'OK-ACCESS-KEY: XXX' \ -H 'OK-ACCESS-TIMESTAMP: XXX' \ -H 'OK-ACCESS-PASSPHRASE: XXX' \ -H 'OK-ACCESS-SIGN: XXX' \ -d "chain=xxx" \ -d "contractAddress=xxx" \ -d "tokenId=xxx" ``` ### Response example ```json { "code": 0, "data": { "animationUrl": "", "assetContract": { "chain": "Ethereum", "contractAddress": "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", "erc2981": false, "ownerAddress": "0xaba7161a7fb69c88e16ed9f455ce62b791ee4d03", "tokenStandard": "erc721" }, "attributes": "[{\"trait_type\":\"Mouth\",\"value\":\"Grin\"},{\"trait_type\":\"Clothes\",\"value\":\"Vietnam Jacket\"},{\"trait_type\":\"Background\",\"value\":\"Orange\"},{\"trait_type\":\"Eyes\",\"value\":\"Blue Beams\"},{\"trait_type\":\"Fur\",\"value\":\"Robot\"}]", "collection": { "assetContracts": [ { "chain": "Ethereum", "contractAddress": "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", "erc2981": false, "ownerAddress": "0xaba7161a7fb69c88e16ed9f455ce62b791ee4d03", "tokenStandard": "erc721" } ], "backgroundImage": "https://static.coinall.ltd/cdn/nft/files/collection/205-background.png", "categoryList": [ "Collectibles" ], "certificateFlag": true, "des": "The Bored Ape Yacht Club is a collection of 10,000 unique Bored Ape NFTs— unique digital collectibles living on the Ethereum blockchain. Your Bored Ape doubles as your Yacht Club membership card, and grants access to members-only benefits, the first of which is access to THE BATHROOM, a collaborative graffiti board. Future areas and perks can be unlocked by the community through roadmap activation. Visit www.BoredApeYachtClub.com for more details.", "discordUrl": "https://discord.gg/3P5K3dzgdB", "image": "https://static.coinall.ltd/cdn/nft/d962ef0d-1cc1-4333-b19f-fc19c7322335.jpg", "instagramUrl": "", "mediumUrl": "", "name": "Bored Ape Yacht Club", "officialWebsite": "http://www.boredapeyachtclub.com/", "slug": "bored-ape-yacht-club", "stats": { "floorPrice": "105752.05", "latestPrice": "102662.45", "ownerCount": "5666", "totalCount": "10000", "totalVolume": "2239291136.375853" }, "twitterUrl": "https://twitter.com/BoredApeYC" }, "image": "https://static.coinall.ltd/cdn/nft/files/8bd603f4-687e-4ce7-827a-c41a859b2d18.webp", "imagePreviewUrl": "https://static.coinall.ltd/cdn/nft/files/8bd603f4-687e-4ce7-827a-c41a859b2d18.webp/type=list", "imageThumbnailUrl": "https://static.coinall.ltd/cdn/nft/files/8bd603f4-687e-4ce7-827a-c41a859b2d18.webp/type=detail", "name": "Bored Ape Yacht Club #1", "tokenId": "1", "tokenUri": "ipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/1" }, "msg": "" } ``` - [Retrieve NFT list](https://web3.okx.com/onchainos/docs/waas/marketplace-retrieve-nft-list.md) {/* api-page */} # Retrieve NFT list This endpoint provides a list of NFTs for a specific chain and the contract address supported and vetted by OKX. ### Request address GET `https://web3.okx.com/api/v5/mktplace/nft/asset/list` ### Request param | **Parameter** | **Type** | **Required** | **Description** | |-----------------|----------|--------------|--------------------------------------------------------------------------------------------------------| | chain | String | Yes | Chain name refer to [Supported blockchains](./marketplace-supported-blockchains) for details | | contractAddress | String | Yes | Collection contract address, which must be a valid one | | cursor | String | No | For pagination. A cursor pointing to the page to retrieve. | | limit | String | No | For pagination. The maximum number of collections to return. The default value is 300. The maximum value is 300. | ### Response param An array of objects of the [NFT Model](./marketplace-nft-model.html#nft-model) | **Parameter** | **Type** | **Description** | |-------------------|----------|-------------------------------------------------------------------------------------------------------| | name | String | The name of the NFT | | tokenId | String | The token ID of the NFT | | tokenUri | String | The address where NFT MetaData is stored | | image | String | An image of the item; note that this is the cached URL we store on our end | | imagePreviewUrl | String | A preview image of the item; note that this is the cached URL we store on our end | | imageThumbnailUrl | String | A thumbnail image of the item; note that this is the cached URL we store on our end | | animationUrl | String | A link to animation resource URL for the item; note that this is the cached URL we store on our end | | attributes | Object | An object of the token [attributes model](./marketplace-nft-model#attributes-model) | | assetContracts | Object | An object of the token [asset contract model](./marketplace-collection-model#asset-contract-model) | | collection | Object | An object of the token [collection model](./marketplace-collection-model#collection-model) | ### Request example ```shell curl -X GET "https://web3.okx.com/api/v5/mktplace/nft/asset/detail" \ -H 'OK-ACCESS-KEY: XXX' \ -H 'OK-ACCESS-TIMESTAMP: XXX' \ -H 'OK-ACCESS-PASSPHRASE: XXX' \ -H 'OK-ACCESS-SIGN: XXX' \ -d "chain=xxx" \ -d "contractAddress=xxx" ``` ### Response example ```json { "code": 0, "data": [ { "animationUrl": "", "assetContract": { "chain": "Ethereum", "contractAddress": "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", "erc2981": false, "ownerAddress": "0xaba7161a7fb69c88e16ed9f455ce62b791ee4d03", "tokenStandard": "erc721" }, "attributes": "[{\"trait_type\":\"Background\",\"value\":\"Gray\"},{\"trait_type\":\"Fur\",\"value\":\"Dark Brown\"},{\"trait_type\":\"Hat\",\"value\":\"Laurel Wreath\"},{\"trait_type\":\"Mouth\",\"value\":\"Bored Unshaven Cigarette\"},{\"trait_type\":\"Clothes\",\"value\":\"Smoking Jacket\"},{\"trait_type\":\"Eyes\",\"value\":\"Bloodshot\"}]", "collection": { "assetContracts": [ { "chain": "Ethereum", "contractAddress": "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", "erc2981": false, "ownerAddress": "0xaba7161a7fb69c88e16ed9f455ce62b791ee4d03", "tokenStandard": "erc721" } ], "backgroundImage": "https://static.coinall.ltd/cdn/nft/files/collection/205-background.png", "categoryList": [ "Collectibles" ], "certificateFlag": true, "des": "The Bored Ape Yacht Club is a collection of 10,000 unique Bored Ape NFTs— unique digital collectibles living on the Ethereum blockchain. Your Bored Ape doubles as your Yacht Club membership card, and grants access to members-only benefits, the first of which is access to THE BATHROOM, a collaborative graffiti board. Future areas and perks can be unlocked by the community through roadmap activation. Visit www.BoredApeYachtClub.com for more details.", "discordUrl": "https://discord.gg/3P5K3dzgdB", "image": "https://static.coinall.ltd/cdn/nft/d962ef0d-1cc1-4333-b19f-fc19c7322335.jpg", "instagramUrl": "", "mediumUrl": "", "name": "Bored Ape Yacht Club", "officialWebsite": "http://www.boredapeyachtclub.com/", "slug": "bored-ape-yacht-club", "stats": { "floorPrice": "105752.05", "latestPrice": "102662.45", "ownerCount": "5666", "totalCount": "10000", "totalVolume": "2239291136.375853" }, "twitterUrl": "https://twitter.com/BoredApeYC" }, "image": "https://static.coinall.ltd/cdn/nft/files/8e8fd651-40cd-46e0-8e81-9d670f61e25b.webp", "imagePreviewUrl": "https://static.coinall.ltd/cdn/nft/files/8e8fd651-40cd-46e0-8e81-9d670f61e25b.webp/type=list", "imageThumbnailUrl": "https://static.coinall.ltd/cdn/nft/files/8e8fd651-40cd-46e0-8e81-9d670f61e25b.webp/type=detail", "name": "Bored Ape Yacht Club #11", "tokenId": "11", "tokenUri": "ipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/11" } ], "msg": "" } ``` - [Asset API](https://web3.okx.com/onchainos/docs/waas/marketplace-asset-api.md) # Asset API - [Retrieve asset list](https://web3.okx.com/onchainos/docs/waas/marketplace-retrieve-asset-list.md) {/* api-page */} # Retrieve asset list This interface provides personal assets queries including the token details, the collection details of the token, the contract details of the token, and the token's attributes. ### Request address GET `https://web3.okx.com/api/v5/mktplace/nft/owner/asset-list` ### Request param | **Parameter** | **Type** | **Required** | **Description** | |-----------------|----------|--------------|--------------------------------------------------------------------------------------------------------| | chain | String | Yes | Chain name refer to [Supported blockchains](./marketplace-supported-blockchains) for details | | contractAddress | String | No | Contract address, which must be a valid one | | ownerAddress | String | Yes | Owner address, which must be a valid contract address | | cursor | String | No | For pagination. A cursor pointing to the page to retrieve. | | limit | String | No | For pagination. The maximum number of collections to return. The default value is 10. The maximum value is 100. | ### Response param An object of the [Asset Model](./marketplace-asset-model.html#asset-model) | **Parameter** | **Type** | **Description** | |-------------------|----------|-------------------------------------------------------------------------------------------------------| | name | String | The name of the NFT | | tokenId | String | The token ID of the NFT | | amount | String | Specified tokenId NFT's total supply | | tokenUri | String | NFT MetaData stored address | | image | String | An image of the item; note that this is the cached URL we store on our end | | imagePreviewUrl | String | A preview image of the item; note that this is the cached URL we store on our end | | imageThumbnailUrl | String | A thumbnail image of the item; note that this is the cached URL we store on our end | | animationUrl | String | A link to animation resource URL for the item; note that this is the cached URL we store on our end | | attributes | Object | An object of the token attributes Model. | | assetContracts | Object | An object of the token [asset contract model](./marketplace-collection-model#asset-contract-model) | | collection | Object | An object of the token [collection model](./marketplace-collection-model#collection-model) | | ownerAddress | String | The address of the assets' owner | | isLazyMintType | Boolean | If it is delayed minting and no transfer has occurred | ### Request example ```shell curl -X GET "https://web3.okx.com/api/v5/mktplace/nft/owner/asset-list" \ -H 'OK-ACCESS-KEY: XXX' \ -H 'OK-ACCESS-TIMESTAMP: XXX' \ -H 'OK-ACCESS-PASSPHRASE: XXX' \ -H 'OK-ACCESS-SIGN: XXX' \ -d "contractAddress=0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d" \ -d "ownerAddress=0x46efbaedc92067e6d60e84ed6395099723252496" \ -d "limit=1" ``` ### Response example ```json { "code": 0, "data": { "cursor": "MzQ2MDQ4Mg==", "data": [ { "animationUrl": "", "assetContract": { "chain": "Ethereum", "contractAddress": "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", "erc2981": false, "ownerAddress": "0xaba7161a7fb69c88e16ed9f455ce62b791ee4d03", "tokenStandard": "erc721" }, "attributes": "[{\"trait_type\":\"Mouth\",\"value\":\"Grin\"},{\"trait_type\":\"Clothes\",\"value\":\"Vietnam Jacket\"},{\"trait_type\":\"Background\",\"value\":\"Orange\"},{\"trait_type\":\"Eyes\",\"value\":\"Blue Beams\"},{\"trait_type\":\"Fur\",\"value\":\"Robot\"}]", "collection": { "assetContracts": [ { "chain": "Ethereum", "contractAddress": "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", "erc2981": false, "ownerAddress": "0xaba7161a7fb69c88e16ed9f455ce62b791ee4d03", "tokenStandard": "erc721" } ], "backgroundImage": "https://static.coinall.ltd/cdn/nft/files/collection/205-background.png", "categoryList": [ "Collectibles" ], "certificateFlag": true, "des": "The Bored Ape Yacht Club is a collection of 10,000 unique Bored Ape NFTs— unique digital collectibles living on the Ethereum blockchain. Your Bored Ape doubles as your Yacht Club membership card, and grants access to members-only benefits, the first of which is access to THE BATHROOM, a collaborative graffiti board. Future areas and perks can be unlocked by the community through roadmap activation. Visit www.BoredApeYachtClub.com for more details.", "discordUrl": "https://discord.gg/3P5K3dzgdB", "image": "https://static.coinall.ltd/cdn/nft/d962ef0d-1cc1-4333-b19f-fc19c7322335.jpg", "instagramUrl": "", "mediumUrl": "", "name": "Bored Ape Yacht Club", "officialWebsite": "http://www.boredapeyachtclub.com/", "slug": "bored-ape-yacht-club", "stats": { "floorPrice": "83119.7", "latestPrice": "104451.04", "ownerCount": "5703", "totalCount": "10000", "totalVolume": "2304507531.1537676" }, "twitterUrl": "https://twitter.com/BoredApeYC" }, "image": "https://static.coinall.ltd/cdn/nft/files/0acbff90-be06-4f4f-b7df-d951310735f2.webp", "imagePreviewUrl": "https://static.coinall.ltd/cdn/nft/files/0acbff90-be06-4f4f-b7df-d951310735f2.webp/type=list", "imageThumbnailUrl": "https://static.coinall.ltd/cdn/nft/files/0acbff90-be06-4f4f-b7df-d951310735f2.webp/type=detail", "isLazyMintType": false, "name": "Bored Ape Yacht Club #1", "ownerAddress": "0x46efbaedc92067e6d60e84ed6395099723252496", "tokenId": "1", "tokenUri": "ipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/1" } ] }, "msg": "" } ``` - [Collection API](https://web3.okx.com/onchainos/docs/waas/marketplace-collection-api.md) # Collection API - [Retrieve collection details](https://web3.okx.com/onchainos/docs/waas/marketplace-retrieve-collection-details.md) {/* api-page */} # Retrieve collection details This interface is used to retrieve more information about individual collections, including real-time statistics such as floor prices. ### Request address GET `https://web3.okx.com/api/v5/mktplace/nft/collection/detail` ### Request param | **Parameter** | **Type** | **Required** | **Description** | |---------------|----------|--------------|--------------------------------------------------------------------| | slug | String | Yes | Collection slug, which is the unique identifier of the collection | ### Response param | **Parameter** | **Type** | **Description** | |-----------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | name | String | Collection name | | des | String | Collection description | | image | String | Collection logo URL | | backgroundImage | String | Collection background image URL | | slug | String | Collection slug, which is the unique identifier of the collection | | certificateFlag | Boolean | Collection certification flag | | officialWebsite | String | Collection official website | | instagramUrl | String | The Instagram URL of the collection | | discordUrl | String | The Discord URL of the collection | | mediumUrl | String | The Medium URL of the collection | | twitterUrl | String | The Twitter URL of the collection | | categoryList | Array | The category list of the collection | | assetContracts | Array | An array of the [asset contract model](./marketplace-collection-model#asset-contract-model) that are associated with this collection, including the contract address, the protocol standard, the owner address, and whether the ERC-2981 protocol is supported, etc. | | stats | Object | A dictionary containing some statistics related to this collection, including the trade volume and the floor prices. An object of the [collection stats model](./marketplace-collection-model#collection-stats-model) | ### Request example ```shell curl -X GET "https://web3.okx.com/api/v5/mktplace/nft/collection/detail" \ -H 'OK-ACCESS-KEY: XXX' \ -H 'OK-ACCESS-TIMESTAMP: XXX' \ -H 'OK-ACCESS-PASSPHRASE: XXX' \ -H 'OK-ACCESS-SIGN: XXX' \ -d "slug=xxx" ``` ### Response example ```json { "code": 0, "data": { "cursor": "NA==", "data": [ { "assetContracts": [ { "chain": "Ethereum", "contractAddress": "0xff9c1b15b16263c61d017ee9f65c50e4ae0113d7", "erc2981": false, "ownerAddress": "0xf296178d553c8ec21a2fbd2c5dda8ca9ac905a00", "tokenStandard": "erc721" } ], "backgroundImage": "https://static.coinall.ltd/cdn/nft/files/collection/8000-background.png", "categoryList": [], "certificateFlag": true, "des": "Loot is randomized adventurer gear generated and stored on chain. Stats, images, and other functionality are intentionally omitted for others to interpret. Feel free to use Loot in any way you want.", "discordUrl": "", "image": "https://static.coinall.ltd/cdn/nft/78d10ba9-63fc-4104-a13c-73e51ac2acb6.jpg", "instagramUrl": "", "mediumUrl": "", "name": "Loot (for Adventurers)", "officialWebsite": "https://lootproject.com", "slug": "loot-for-adventurers", "stats": { "floorPrice": "866.74799", "latestPrice": "616.4433", "ownerCount": "2522", "totalCount": "7779", "totalVolume": "552505219.5371664" }, "twitterUrl": "" } ] }, "msg": "" } ``` - [Retrieve collection list](https://web3.okx.com/onchainos/docs/waas/marketplace-retrieve-collection-list.md) {/* api-page */} # Retrieve collection list This interface provides a list of all the collections supported and vetted by OKX. To get the collection list of the specified chain, set the ```chain``` field in the request parameter. ### Request address GET `https://web3.okx.com/api/v5/mktplace/nft/collection/list` ### Request param | **Parameter** | **Type** | **Required** | **Description** | |---------------|----------|--------------|----------------------------------------------------------------------------------------------------------| | chain | String | No | Chain name refer to [Supported blockchains](./marketplace-supported-blockchains) for details | | cursor | String | No | For pagination; a cursor pointing to the page to retrieve | | limit | String | No | For pagination; the maximum number of collections to return; the default value is 2, and the max is 300 | ### Response param Array of objects of the [collection model](./marketplace-collection-model.html#collection-model) | **Parameter** | **Type** | **Description** | |-----------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | name | String | Collection name | | des | String | Collection description | | image | String | Collection logo URL | | backgroundImage | String | Collection background image URL | | slug | String | Collection slug, which is the unique identifier of the collection | | certificateFlag | Boolean | Collection certification flag | | officialWebsite | String | Collection official website | | instagramUrl | String | The Instagram URL of the collection | | discordUrl | String | The Discord URL of the collection | | mediumUrl | String | The Medium URL of the collection | | twitterUrl | String | The Twitter URL of the collection | | categoryList | Array | The category list of the collection | | assetContracts | Array | An array of the [asset contract model](./marketplace-collection-model#asset-contract-model) that are associated with this collection, including contract address, protocol standard, owner address, whether the ERC-2981 protocol is supported, etc. | | stats | Object | A dictionary containing some statistics related to this collection, including trade volume and floor prices, an object of the [collection stats model](./marketplace-collection-model#collection-stats-model) | ### Request example ```shell curl -X GET "https://web3.okx.com/api/v5/mktplace/nft/collection/list" \ -H 'OK-ACCESS-KEY: XXX' \ -H 'OK-ACCESS-TIMESTAMP: XXX' \ -H 'OK-ACCESS-PASSPHRASE: XXX' \ -H 'OK-ACCESS-SIGN: XXX' \ -d "chain=eth" \ -d "limit=1" ``` ### Response example ```json { "code": 0, "data": [ { "animationUrl": "", "assetContract": { "chain": "Ethereum", "contractAddress": "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", "erc2981": false, "ownerAddress": "0xaba7161a7fb69c88e16ed9f455ce62b791ee4d03", "tokenStandard": "erc721" }, "attributes": "[{\"trait_type\":\"Background\",\"value\":\"Gray\"},{\"trait_type\":\"Fur\",\"value\":\"Dark Brown\"},{\"trait_type\":\"Hat\",\"value\":\"Laurel Wreath\"},{\"trait_type\":\"Mouth\",\"value\":\"Bored Unshaven Cigarette\"},{\"trait_type\":\"Clothes\",\"value\":\"Smoking Jacket\"},{\"trait_type\":\"Eyes\",\"value\":\"Bloodshot\"}]", "collection": { "assetContracts": [ { "chain": "Ethereum", "contractAddress": "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", "erc2981": false, "ownerAddress": "0xaba7161a7fb69c88e16ed9f455ce62b791ee4d03", "tokenStandard": "erc721" } ], "backgroundImage": "https://static.coinall.ltd/cdn/nft/files/collection/205-background.png", "categoryList": [ "Collectibles" ], "certificateFlag": true, "des": "The Bored Ape Yacht Club is a collection of 10,000 unique Bored Ape NFTs— unique digital collectibles living on the Ethereum blockchain. Your Bored Ape doubles as your Yacht Club membership card, and grants access to members-only benefits, the first of which is access to THE BATHROOM, a collaborative graffiti board. Future areas and perks can be unlocked by the community through roadmap activation. Visit www.BoredApeYachtClub.com for more details.", "discordUrl": "https://discord.gg/3P5K3dzgdB", "image": "https://static.coinall.ltd/cdn/nft/d962ef0d-1cc1-4333-b19f-fc19c7322335.jpg", "instagramUrl": "", "mediumUrl": "", "name": "Bored Ape Yacht Club", "officialWebsite": "http://www.boredapeyachtclub.com/", "slug": "bored-ape-yacht-club", "stats": { "floorPrice": "105752.05", "latestPrice": "102662.45", "ownerCount": "5666", "totalCount": "10000", "totalVolume": "2239291136.375853" }, "twitterUrl": "https://twitter.com/BoredApeYC" }, "image": "https://static.coinall.ltd/cdn/nft/files/8e8fd651-40cd-46e0-8e81-9d670f61e25b.webp", "imagePreviewUrl": "https://static.coinall.ltd/cdn/nft/files/8e8fd651-40cd-46e0-8e81-9d670f61e25b.webp/type=list", "imageThumbnailUrl": "https://static.coinall.ltd/cdn/nft/files/8e8fd651-40cd-46e0-8e81-9d670f61e25b.webp/type=detail", "name": "Bored Ape Yacht Club #11", "tokenId": "11", "tokenUri": "ipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/11" } ], "msg": "" } ``` - [Order API](https://web3.okx.com/onchainos/docs/waas/marketplace-order-api.md) # Order API - [Query listing](https://web3.okx.com/onchainos/docs/waas/marketplace-query-listing.md) {/* api-page */} # Query listing This endpoint is used to fetch the set of active listings on a given NFT for the Seaport contract. ### Request address GET `https://web3.okx.com/api/v5/mktplace/nft/markets/listings` ### Request param | **Parameter** | **Type** | **Required** | **Description** |-------------------|----------|--------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | chain | String | Yes | Chain name refer to [Supported blockchains](./marketplace-supported-blockchains) for details | | collectionAddress | String | No | Address of the contract for an NFT | | tokenId | String | No | The token for an NFT | | maker | String | No | Filter by the order makers wallet address | | createAfter | String | No | Only show orders listed after this timestamp; seconds since the UNIX epoch | | createBefore | String | No | Only show orders listed before this timestamp; seconds since the UNIX epoch | | updateAfter | String | No | Only show orders updated before this timestamp; seconds since the UNIX epoch | | updateBefore | String | No | Only show orders updated before this timestamp; seconds since the UNIX epoch | | status | String | No | Filter by the order status; the options are active, inactive, cancelled, and sold | | platform | String | No | For supported platform, refer to [Integrated markets](./marketplace-integrated-markets) | | sort | String | No | How to sort the orders: can be create_time_desc for when they were made, or price_desc to see the highest-priced orders first or price_asc to see the lowest-priced orders first; the default sort is in positive order | | limit | String | No | Number of listings to retrieve. The default value is 50 | | cursor | String | No | A cursor to be supplied as a query param to retrieve a specified page | ### Response param An array of [OKX order model](./marketplace-order-model.html#okx-order-model) | **Parameter** | **Type** | **Description** | |-------------------|----------|----------------------------------------------------------------------------------------| | orderId | String | ID of order | | createTime | Long | The date order was created | | updateTime | Long | The date order was updated | | listingTime | Long | The date order was listed | | expirationTime | Long | The endTime indicates the block timestamp at which the order expires | | status | String | The order status, includes active, cancelled, sold, and inactive | | orderHash | String | The order hash | | protocolData | String | The parameters of order (JSON) | | protocolAddress | String | The contract address for fulfilling the order | | chain | String | Chain name refer to [Supported blockchains](./marketplace-supported-blockchains) for details | | maker | String | The wallet address initiating the order | | orderType | String | Offer indicates offer; BuyNow indicates listings | | price | String | Unit price of NFT for the order | | currencyAddress | String | Address of the currency for paying the order | | collectionAddress | String | Address of the contract for an NFT | | tokenId | String | The token for an NFT | | amount | String | Count of NFT for the order | ### Request example An array of [OKX Order Model](./marketplace-order-model.html#okx-order-model) ```shell curl -X GET "https://web3.okx.com/api/v5/mktplace/nft/markets/listings?{REQUEST PARAMS}" \ -H 'OK-ACCESS-KEY: XXX' \ -H 'OK-ACCESS-TIMESTAMP: XXX' \ -H 'OK-ACCESS-PASSPHRASE: XXX' \ -H 'OK-ACCESS-SIGN: XXX' \ ``` ### Response example ```json { "code": 0, "data": { "cursor": "NjE5MTQ0MTM5", "data": [ { "amount": "1", "chain": "OKTC", "collectionAddress": "0xe4c0578279269c4f0265bc486c199509566fe863", "createTime": 1672828395, "updateTime": 1672828395, "status": "active", "currencyAddress": "0x382bb369d343125bfb2117af9c149795c6c65c50", "expirationTime": 1673433171, "listingTime": 1672828387, "maker": "0x5164370b3ba971474d10da1d409ce8872cb8ca97", "orderHash": "0x5bdaa259cb76ace593f3e631099319f955b48397482e7e4d45c008d985b61ade", "orderType": "BuyNow", "price": "1000000000000000", "protocolAddress": "0x34df5c035e31c0edfd104f3ea83d9548f108df56", "protocolData": { "parameters": { "conduitKey": "0x618Cf13c76c1FFC2168fC47c98453dCc6134F5c8888888888888888888888888", "consideration": [ { "endAmount": "1000000000000000", "identifierOrCriteria": "0", "itemType": 1, "recipient": "0x5164370b3ba971474d10da1d409ce8872cb8ca97", "startAmount": "1000000000000000", "token": "0x382bb369d343125bfb2117af9c149795c6c65c50" } ], "counter": 0, "endTime": 1673433171, "offer": [ { "endAmount": "1", "identifierOrCriteria": "17230", "itemType": 2, "startAmount": "1", "token": "0xe4c0578279269c4f0265bc486c199509566fe863" } ], "offerer": "0x5164370b3ba971474d10da1d409ce8872cb8ca97", "orderType": 2, "salt": "27454607645473204", "startTime": 1672828387, "totalOriginalConsiderationItems": 1, "zone": "0xa472fAd4B6cAdFDEd63f7aE5BFEe6eCf4F08Ae95", "zoneHash": "0x0000000000000000000000000000000000000000000000000000000000000000" }, "signature": "0x" }, "tokenId": "17230" } ] }, "msg": "" } ``` - [Query offer](https://web3.okx.com/onchainos/docs/waas/marketplace-query-offer.md) {/* api-page */} # Query offer This endpoint is used to fetch the set of active offers on a given NFT for the Seaport contract. ### Request address GET `https://web3.okx.com/api/v5/mktplace/nft/markets/offers` ### Request param | **Parameter** | **Type** | **Required** | **Description** | |-------------------|----------|--------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | chain | String | Yes | Chain name refer to [Supported blockchains](./marketplace-supported-blockchains) for details | | collectionAddress | String | No | Address of the contract for an NFT | | tokenId | String | No | The token for an NFT | | maker | String | No | Filter by the order maker's wallet address | | createAfter | String | No | Only show orders listed after this timestamp; seconds since the UNIX epoch | | createBefore | String | No | Only show orders listed before this timestamp; seconds since the UNIX epoch | | updateAfter | String | No | Only show orders updated after this timestamp; seconds since the UNIX epoch | | updateBefore | String | No | Only show orders updated before this timestamp; seconds since the UNIX epoch | | status | String | No | Filter by the order status; the options are active, inactive, cancelled, and sold | | sort | String | No | How to sort the orders: can be create_time_desc for when they were made, or update_time_desc for when they were updated, or price_desc to see the highest-priced orders first or price_asc to see the lowest-priced orders first; the default sort is in positive order | | limit | String | No |Number of listings to retrieve; the default value is 50 | | cursor | String | No | A cursor to be supplied as a query param to retrieve a specified page | ### Response param An array of [OKX order model](./marketplace-order-model.html#okx-order-model) | **Parameter** | **Type** | **Description** | |-------------------|----------|----------------------------------------------------------------------------------------| | orderId | String | ID of order | | createTime | Long | The date order was created | | updateTime | Long | The date order was updated | | listingTime | Long | The date order was listed | | expirationTime | Long | The endTime indicates the block timestamp at which the order expires | | status | String | The order status, includes active, cancelled, sold, and inactive | | orderHash | String | The order hash | | protocolData | String | The parameters of order (JSON) | | protocolAddress | String | The contract address for fulfilling the order | | chain | String | Chain name, includes ETH, Polygon, AVAX, BSC, OKTC, Arbitrum One, Optimism, Klaytn, and zkSync Era | | maker | String | The wallet address initiating the order | | orderType | String | Offer indicates offer; BuyNow indicates listings | | price | String | Unit price of NFT for the order | | currencyAddress | String | Address of the currency for paying the order | | collectionAddress | String | Address of the contract for an NFT | | tokenId | String | The token for an NFT | | amount | String | Count of NFT for the order | ### Request example An array of [OKX Order Model](./marketplace-order-model.html#okx-order-model) ```shell curl -X GET "https://web3.okx.com/api/v5/mktplace/nft/markets/offers?{REQUEST PARAMS}" \ -H 'OK-ACCESS-KEY: XXX' \ -H 'OK-ACCESS-TIMESTAMP: XXX' \ -H 'OK-ACCESS-PASSPHRASE: XXX' \ -H 'OK-ACCESS-SIGN: XXX' \ ``` ### Response example ```json { "code": 0, "data": { "cursor": "ODg0MjY2NDgz", "data": [ { "amount": "1", "chain": "eth", "collectionAddress": "0x457efd33def0bff2dfe33089d385898d919d3a10", "createTime": 1680047938, "currencyAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "expirationTime": 1680307118, "listingTime": 1680047927, "maker": "0x72fde15006cff1bfc1be596f03855a2c55b546e1", "orderHash": "0x48cc57480fdbe993821b6679910657845201351448bca623a6b7726fc1f7ff4b", "orderType": "Offer", "price": "110000", "protocolAddress": "0x90a77dd8ae0525e08b1c2930eb2eb650e78c6725", "protocolData": { "parameters": { "conduitKey": "0x618Cf13c76c1FFC2168fC47c98453dCc6134F5c8888888888888888888888888", "consideration": [ { "endAmount": "1", "identifierOrCriteria": "77735144008553370296572895450686144694166639583550383356598452408298996120723", "itemType": 2, "recipient": "0x72fde15006cff1bfc1be596f03855a2c55b546e1", "startAmount": "1", "token": "0x457efd33def0bff2dfe33089d385898d919d3a10" } ], "counter": "0", "endTime": 1680307118, "offer": [ { "endAmount": "110000", "identifierOrCriteria": "0", "itemType": 1, "startAmount": "110000", "token": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" } ], "offerer": "0x72fde15006cff1bfc1be596f03855a2c55b546e1", "orderType": 3, "salt": "1144075581", "startTime": 1680047927, "totalOriginalConsiderationItems": 1, "zone": "0x868B0635A8858dB9D984B5A27559f961Fd2736c0", "zoneHash": "0x0000000000000000000000000000000000000000000000000000000000000000" }, "signature": "0xa413e6e3496fcd8bc28af88d4e1f2db4ccb7b524763ba6d87a56b15b20510d5d1eb782121c96ed61e2b68d537e03f96c51b37e0c325d03ad035091bf1933d4b81b" }, "status": "active", "tokenId": "77735144008553370296572895450686144694166639583550383356598452408298996120723", "updateTime": 1680047938 } ] }, "msg": "" } ``` - [Buy orders](https://web3.okx.com/onchainos/docs/waas/marketplace-buy-orders.md) {/* api-page */} # Buy orders Use this API to fill listings. ### Request address POST `https://web3.okx.com/api/v5/mktplace/nft/markets/buy` ### Request param - **Body param** | **Parameter** | **Type** | **Required** | **Description** | |---------------|----------|--------------|-----------------------------------------------------------| | chain | String | Yes | Chain name refer to [Supported blockchains](./marketplace-supported-blockchains) for details | | walletAddress | String | Yes | Address of wallet filling. | | items | object[] | Yes | List of [item](./marketplace-order-model#buy-item-model) to buy. | ### Request example ```shell curl -X POST "https://web3.okx.com/api/v5/mktplace/nft/markets/buy" \ -H "Content-Type: application/json" \ -H 'OK-ACCESS-KEY: XXX' \ -H 'OK-ACCESS-TIMESTAMP: XXX' \ -H 'OK-ACCESS-PASSPHRASE: XXX' \ -H 'OK-ACCESS-SIGN: XXX' \ -d '{ "chain": "bsc", "items": [ { "orderId": 1440952735, "takeCount": 1 }, { "orderId": 1440952735, "takeCount": 1 } ], "walletAddress": "0xb0295f8ed896413eecc1032b9f97ecc8608c55ad" }' ``` ### Response example ```json { "code":0, "data":{ "errors":[ ], "steps":[ { "action":"ApprovalCurrency", "items":[ { "amount":"300000000000000000", "approvalAddress":"0xcce3e3f79cf9091386f84610bb06947e2fc232a3", "chain":56, "currency":"USDC", "currencyUrl":"https://static.coinall.ltd/cdn/explorer/okexchain/exchain_usdc.png", "description":"Approval ERC20 to OKX", "kind":"erc20Approval", "orderIds":[ "1156591403" ], "platform":{ "icon":"https://static.coinall.ltd/cdn/nft/2ffcd699-3e14-4ac3-b6fc-e8e5369ab2fd.png", "name":"OKX", "source":4 }, "status":"complete", "tokenAddress":"0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d" } ] }, { "action":"TakeOrders", "items":[ { "chain":56, "contractAddress":"0xcce3e3f79cf9091386f84610bb06947e2fc232a3", "description":"Buy tokens on OKX", "input":"0x92e6f80700000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001183e781264880a5ca05dd025967c1e6dd790e1bd425adc1d14fced1b45bf102000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000004e4e7acab24000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000004c0618cf13c76c1ffc2168fc47c98453dcc6134f5c88888888888888888888888880000000000000000000000006c7874e005654fc975c82d55830b675e9b11a09100000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000b1f442c5a971e00599bf7858114b43fdc71347000000000000000000000000b74932867f98c4ca5099f7799cb364a6c97a07c600000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000645a0df00000000000000000000000000000000000000000000000000000000065475be9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b169239bd2f184618cf13c76c1ffc2168fc47c98453dcc6134f5c888888888888888888888888800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000047b4608e69317aa2ebc71148bec5b9f65ead61e5000000000000000000000000000000000000000000000000000000000000767f00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000429d069189e00000000000000000000000000000000000000000000000000000429d069189e000000000000000000000000000000b1f442c5a971e00599bf7858114b43fdc713470000000000000000000000000000000000000000000000000000000000000041c66d1c598227b6fff21f06a9735b41d46a933a38512e9d9cb6b7aa4a3de851ab72ada2f67f5ddc7715d7761ba65a7447218f961a693d6f80c24447fe91e7d3a41b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000429d069189e00000000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d00000000000000000000000047b4608e69317aa2ebc71148bec5b9f65ead61e5000000000000000000000000000000000000000000000000000000000000767f000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000003c00b1f442c5a971e00599bf7858114b43fdc713476c7874e005654fc975c82d55830b675e9b11a091000000000000000000000000000000000000000000000000", "kind":"transaction", "orderIds":[ "1156591403" ], "platform":{ "icon":"https://static.coinall.ltd/cdn/nft/2ffcd699-3e14-4ac3-b6fc-e8e5369ab2fd.png", "name":"OKX", "source":4 }, "status":"incomplete", "totalPrice":"0.3", "value":"0" } ] } ] }, "msg":"" } ``` - [Cancel orders](https://web3.okx.com/onchainos/docs/waas/marketplace-cancel-orders.md) {/* api-page */} # Cancel orders Use this API to cancel orders. ### Request address POST `https://web3.okx.com/api/v5/mktplace/nft/markets/cancel-listing` ### Request param | **Parameter** | **Type** | **Required** | **Description** | |---------------|----------|--------------|-----------------------------------------------------------| | chain | String | Yes | Chain name refer to [Supported blockchains](./marketplace-supported-blockchains) for details | | walletAddress | String | Yes | Wallet address for creating the listing. | | orderIds | List<String> | Yes | List of orderId to cancel. | ### Request example ```shell curl -X POST "https://web3.okx.com/api/v5/mktplace/nft/markets/cancel-listing" \ -H "Content-Type: application/json" \ -H 'OK-ACCESS-KEY: XXX' \ -H 'OK-ACCESS-TIMESTAMP: XXX' \ -H 'OK-ACCESS-PASSPHRASE: XXX' \ -H 'OK-ACCESS-SIGN: XXX' \ -d '{ "chain": "polygon", "walletAddress": "0xb0295f8ed896413eecc1032b9f97ecc8608c55ad", "orderIds": ["3401683780"] }' ``` ### Response example ```json { "code": 0, "data": { "errors": [], "steps": [ { "action": "CancelOrders", "items": [ { "chain": 137, "contractAddress": "0x00000000000000adc04c56bf30ac9d3c0aaf14dc", "description": "", "input": "0xfd9f1e100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000003f272ad1ce36553bd42b924a85610b7a8cb934530000000000000000000000002de95b9afd737b0814e5e6013593a9437c5532d500000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000658bc374000000000000000000000000000000000000000000000000000000006594fdf3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030c67a1f49e41a370000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000056423a158caceee70e85222d25675d14d67f474b00000000000000000000000000000000000000000000000000000000000005470000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000003f272ad1ce36553bd42b924a85610b7a8cb93453", "kind": "transaction", "orderIds": [ "3401683780" ], "platform": { "icon": "https://static.coinall.ltd/cdn/nft/2ffcd699-3e14-4ac3-b6fc-e8e5369ab2fd.png", "name": "OKX", "source": 4 }, "platforms": [ { "icon": "https://static.coinall.ltd/cdn/nft/2ffcd699-3e14-4ac3-b6fc-e8e5369ab2fd.png", "name": "OKX", "source": 4 } ], "status": "incomplete", "totalPrice": "0", "totalUsdPrice": "0", "value": "0" } ] } ] }, "msg": "" } ``` - [Get collection transaction history](https://web3.okx.com/onchainos/docs/waas/marketplace-retrieve-transaction-history.md) # Get collection transaction history This API is used to get NFT sales history information such as collectionAddress, platform, price, buyer and seller. ### Request address GET `https://web3.okx.com/api/v5/mktplace/nft/markets/trades` ### Request param | **Parameter** | **Type** | **Required** | **Description** | |-----------------|----------|--------------|---------------------------------------------------------------------------| | chain | Yes | String | Chain name refer to [Supported blockchains](./marketplace-supported-blockchains) for details. | | collectionAddress |Yes | String | The unique collection address of the transaction history to query for. | | platform | No | String | For supported platforms, refer to [Integrated markets](./marketplace-integrated-markets). If this is empty, it will query all platforms. | | limit | No | String | The number of records displayed per page ranges from 1 to 50. If the input value exceeds 50 or is not provided, it will default to 50. | | cursor | No | String | The cursor for pagination of the records. | | startTime | No | String | The starting time range of the sale history record you want to query from. | | endTime | No | String | The end time range of the sale history record you want to query from. | ### Response param | **Parameter** | **Type** | **Description** | |-------------------|----------|-------------------------------------------------------------------------------------------------------| | cursor | String | The cursor for pagination. Use this cursor as input for the next query. | | amount | Integer | The number of nft being transacted in this transaction history. | | chain | String | Chain name refer to [Supported blockchains](./marketplace-supported-blockchains) for details. | | collectionAddress | String | The unique collection address of the transaction history to query for. | | currencyAddress | String | Payment token address of this transaction. | | from | String | The seller. | | to | String | The buyer. | | platform | String | For supported platforms, refer to [Integrated markets](./marketplace-integrated-markets). | | price | BigDecimal | The unit price of each NFT. | | timestamp | Long | The time that of the transaction occured. | | tokenId | String | The unique Token ID of the NFT. | | txHash | String | The transaction hash of this record that is taken place. | ### Request example ```shell curl --location 'https://beta.okex.org/api/v5/mktplace/nft/markets/trades?chain=ethereum&collectionAddress=0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d' \ --header 'OK-ACCESS-KEY: your api access key' \ --header 'OK-ACCESS-PASSPHRASE: your api passphrase' \ ``` ### Response example ```json { "code": 0, "data": { "cursor": "MTcxOTk0NDQ0NzoweDRiYjNhZjY1MDQwOTdkMjBkY2QxMzAxZDg0NTdjOGVkNzEzMzQ3OGY2NjFiODdhN2M4YzdlNTk4OTIxMjcwNDktMTU4", "data": [ { "amount": 1, "chain": "Ethereum", "collectionAddress": "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", "currencyAddress": "0x0000000000000000000000000000000000000000", "from": "0xf15c93562bc3944a68e938ef75d2a3360d98ca57", "platform": "Blur", "price": 9.71, "timestamp": 1720113467, "to": "0xeb0abe3e9f38fc74ed900f118744275af3a99618", "tokenId": "4382", "txHash": "0x11b30e98235053d2749a41249db60c895ca8bac1942b526a993f3c4be058a0b4" }, { "amount": 1, "chain": "Ethereum", "collectionAddress": "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", "currencyAddress": "0x0000000000a39bb272e79075ade125fd351887ac", "from": "0x29469395eaf6f95920e59f858042f0e28d98a20b", "platform": "Blur", "price": 9.45, "timestamp": 1720110203, "to": "0x0f2bbce1fcb6702a4d9ab30e5c68868f82af3d41", "tokenId": "3854", "txHash": "0xe34400d02d0330cd7b4cbbdd3d2d2e458e4fd702ef768ab6de73591bc2060906" } ], "next": true, "total": 10000 }, "msg": "" } ``` - [Create a listing](https://web3.okx.com/onchainos/docs/waas/marketplace-create-a-listing.md) {/* api-page */} # Create a listing This interface is used for listing on OKX and other markets. ### Request address POST `https://web3.okx.com/api/v5/mktplace/nft/markets/create-listing` ### Request parameters - **Body param** | **Parameter** | **Type** | **Required** | **Description** | |---------------|----------|--------------|--------------------------------------------------------------------------------------| | chain | String | Yes | Chain name refer to [Supported blockchains](./marketplace-supported-blockchains) for details | | walletAddress | String | Yes | Wallet address for creating the listing | | collectionAddress | String | Yes | NFT contract address | | tokenId | String | Yes | NFT tokenId | | price | String | Yes | Price of the NFT in decimal, example: 2000000 represents 2 | | currencyAddress | String | Yes | Contract address of the pricing currency, native coins like ETH, OKT, etc. on different networks default to “0x000000000000000000000
0000000000000000000” | | count | String | Yes | Quantity of NFT, 1 for ERC-721 type | | validTime | String | Yes | Listing expiration timestamp (s), example: 2039-09-19 07:06:40 converts to timestamp 2200000000 | | platform | String | Yes | Target listing platform, refer to [Integrated markets](./marketplace-integrated-markets) |
### Request example ```shell curl -X POST "https://web3.okx.com/api/v5/mktplace/nft/markets/create-listing" \ -H "Content-Type: application/json" \ -H 'OK-ACCESS-KEY: XXX' \ -H 'OK-ACCESS-TIMESTAMP: XXX' \ -H 'OK-ACCESS-PASSPHRASE: XXX' \ -H 'OK-ACCESS-SIGN: XXX' \ -d '{ "chain": "polygon", "walletAddress": "0x76e2da406db566f0e79764a2bf01b992997d0586", "items" : [ { "collectionAddress": "0xa5561b779c086d37a77d7b35e97ce75bb9193491", "tokenId": "101837856840664764261208575168687881837850830083487668871567409609794568798800", "price": "50000000", "currencyAddress": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F", "count": 1, "validTime":1748057424, "platform": "okx" } ] }' ``` ### Response example ```json { "code": 0, "data": { "errors": [], "orders": [ { "collectionAddress": "0xa5561b779c086d37a77d7b35e97ce75bb9193491", "count": "1", "currencyAddress": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F", "id": "a07b10bb8da04a9183cd0ca216126071", "listingProfit": "", "nftId": "27278971523568785", "platform": "okx", "platformFeePoints": null, "price": "50000000", "project": "", "protocolFeePoints": null, "royaltyFeePoints": null, "source": 4, "tokenId": "101837856840664764261208575168687881837850830083487668871567409609794568798800", "validTime": 1748057424 } ], "steps": [ { "action": "ApprovalItems", "items": [ { "approvalAddress": "0x1e0049783f008a0085193e00003d00cd54003c71", "chain": 137, "collectionAddress": "0xa5561b779c086d37a77d7b35e97ce75bb9193491", "description": "", "kind": "nftApproval", "orderIds": [ "a07b10bb8da04a9183cd0ca216126071" ], "platform": { "icon": "https://static.coinall.ltd/cdn/nft/1f4d2f3f-774c-4386-b8e1-52533d1af81d.webp", "name": "OKX", "source": 4 }, "platforms": [ { "icon": "https://static.coinall.ltd/cdn/nft/1f4d2f3f-774c-4386-b8e1-52533d1af81d.webp", "name": "OKX", "source": 4 } ], "status": "complete" } ] }, { "action": "SignOrders", "items": [ { "data": { "conduitKey": "0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000", "consideration": [ { "endAmount": "49000000", "identifierOrCriteria": "0", "itemType": 1, "recipient": "0x76e2da406db566f0e79764a2bf01b992997d0586", "startAmount": "49000000", "token": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F" }, { "endAmount": "1000000", "identifierOrCriteria": "0", "itemType": 1, "recipient": "0xecd8c2d00b969fddbb06c2c6bec9a98a7d8dfb85", "startAmount": "1000000", "token": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F" } ], "counter": "0", "endTime": "1748057424", "offer": [ { "endAmount": "1", "identifierOrCriteria": "101837856840664764261208575168687881837850830083487668871567409609794568798800", "itemType": 2, "startAmount": "1", "token": "0xa5561b779c086d37a77d7b35e97ce75bb9193491" } ], "offerer": "0x76e2da406db566f0e79764a2bf01b992997d0586", "orderType": 2, "salt": "0x000000000000000000000000000000000000000000000000eb1c8424e64a1eec", "startTime": 1719209238, "totalOriginalConsiderationItems": 2, "zone": "0xdf2d4bffec010debd302674c9fb9cda99bb5e852", "zoneHash": "0x0000000000000000000000000000000000000000000000000000000000000000" }, "description": "", "domain": { "chainId": 137, "name": "Seaport", "verifyingContract": "0x0000000000000068f116a894984e2db1123eb395", "version": "1.6" }, "kind": "signature", "orderIds": [ "a07b10bb8da04a9183cd0ca216126071" ], "platform": { "icon": "https://static.coinall.ltd/cdn/nft/1f4d2f3f-774c-4386-b8e1-52533d1af81d.webp", "name": "OKX", "source": 4 }, "platforms": [ { "icon": "https://static.coinall.ltd/cdn/nft/1f4d2f3f-774c-4386-b8e1-52533d1af81d.webp", "name": "OKX", "source": 4 } ], "post": { "body": { "chain": 137, "items": [ { "collectionAddress": "0xa5561b779c086d37a77d7b35e97ce75bb9193491", "count": "1", "currencyAddress": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F", "id": "a07b10bb8da04a9183cd0ca216126071", "listingProfit": "", "nftId": "27278971523568785", "platform": "okx", "platformFeePoints": null, "price": "50000000", "project": "", "protocolFeePoints": null, "royaltyFeePoints": null, "source": 4, "tokenId": "101837856840664764261208575168687881837850830083487668871567409609794568798800", "validTime": 1748057424 } ], "orderData": "", "r": "", "s": "", "signature": "", "walletAddress": "0x76e2da406db566f0e79764a2bf01b992997d0586" }, "endpoint": "/priapi/v1/nft/trading/seaport/step/submitOrder", "method": "post" }, "primaryType": "OrderComponents", "signKind": "eip712", "status": "incomplete", "types": { "ConsiderationItem": [ { "name": "itemType", "type": "uint8" }, { "name": "token", "type": "address" }, { "name": "identifierOrCriteria", "type": "uint256" }, { "name": "startAmount", "type": "uint256" }, { "name": "endAmount", "type": "uint256" }, { "name": "recipient", "type": "address" } ], "OrderComponents": [ { "name": "offerer", "type": "address" }, { "name": "zone", "type": "address" }, { "name": "offer", "type": "OfferItem[]" }, { "name": "consideration", "type": "ConsiderationItem[]" }, { "name": "orderType", "type": "uint8" }, { "name": "startTime", "type": "uint256" }, { "name": "endTime", "type": "uint256" }, { "name": "zoneHash", "type": "bytes32" }, { "name": "salt", "type": "uint256" }, { "name": "conduitKey", "type": "bytes32" }, { "name": "counter", "type": "uint256" } ], "EIP712Domain": [ { "name": "name", "type": "string" }, { "name": "version", "type": "string" }, { "name": "chainId", "type": "uint256" }, { "name": "verifyingContract", "type": "address" } ], "OfferItem": [ { "name": "itemType", "type": "uint8" }, { "name": "token", "type": "address" }, { "name": "identifierOrCriteria", "type": "uint256" }, { "name": "startAmount", "type": "uint256" }, { "name": "endAmount", "type": "uint256" } ] } } ] } ] }, "msg": "" } ```
- [Supported blockchains](https://web3.okx.com/onchainos/docs/waas/marketplace-supported-blockchains.md) # Supported blockchains For network and chainId associations, please refer to [Network ChainId Mapping](./walletapi-resources-supported-networks) for more information. | Blockchain network | Key | | --- | --- | | Ethereum Mainnet | eth | | Polygon Mainnet | polygon | | Avalanche C-Chain | avax | | BNB Smart Chain Mainnet| bsc | | OKT Chain | oktc | | Arbitrum One | arbitrum | | Arbitrum Nova | arbitrum-nova | | OP Mainnet | optimism | | Klaytn Mainnet Cypress | klaytn | | zkSync Era Mainnet | zksync-era | | Base | base | | Linea | linea | | opBNB Mainnet | opbnb | | Polygon zkEVM | polygon-zkevm | | Scroll | scroll | | Manta Pacific Mainnet | manta-pacific | - [Integrated markets](https://web3.okx.com/onchainos/docs/waas/marketplace-integrated-markets.md) # Integrated markets | Marketplace | Key | Supported Networks for Listing | Supported Networks for Order Retrieval | | --- | --- | --- | --- | | OKX | okx | See [Supported blockchains](./marketplace-supported-blockchains) | See [Supported blockchains](./marketplace-supported-blockchains) | | opensea.io | opensea | eth, polygon, avax, arbitrum, arbitrum-nova, optimism, klaytn, base | eth, polygon, avax, arbitrum, arbitrum-nova, optimism, klaytn, base | | looksrare.org | looksrare | - | eth | | element.market | element | - | eth, polygon, bnb, zksync-era, arbitrum, avax | | x2y2.io | x2y2 | - | eth | - [Models](https://web3.okx.com/onchainos/docs/waas/marketplace-models.md) # Models - [NFT models](https://web3.okx.com/onchainos/docs/waas/marketplace-nft-model.md) # NFT models The primary object in the OKX API is NFT. It represents a unique digital item with its ownership managed by blockchain.
The below OKX Football Cup is an example of an NFT shown on OKX. ![nft](../images/nft.png) ## NFT model | **Parameter** | **Type** | **Description** | |-------------------|--------|-------------------------------------------------------------------------------------------------------| | name | String | Name of the NFT | | tokenId | String | Token ID of the NFT | | tokenUri | String | NFT address stored in Metadata | | image | String | Image of the NFT. Note: it is a cached url stored on our end | | imagePreviewUrl | String | Preview image of the NFT. Note: it is a cached url stored on our end | | imageThumbnailUrl | String | Thumbnail image of the NFT. Note: it is a cached url stored on our end | | animationUrl | String | Animation resource url for the NFT. Note: it is a cached url stored on our end | | attributes | Object | Attributes info of the NFT, an object of [Attributes Model](#attributes-model) | | assetContracts | Object | Contract info of the NFT, an object of [Asset Contract Model](./marketplace-collection-model.html#asset-contract-model) | | collection | Object | Collection info of the NFT, an object of [Collection Model](./marketplace-collection-model.html#collection-model) | ## Attributes model Attributes are special properties of an NFT. They can be either numbers or strings. Below is an example of how OKX displays the attributes for a specific NFT. | **Parameter** | **Type** | **Description** | |----------------|----------|--------------------------------------------------------------------------------------------------------| | trait_type | String | Name of the attribute (e.g. color) | | value | String | Value of the attribute (e.g., string/number) | | display_type | String | Format of the attribute (displayed in number, boost_percentage, boost_number, or date) | - [Asset models](https://web3.okx.com/onchainos/docs/waas/marketplace-asset-model.md) # Asset models One of the primary objects in the OKX API is the asset, which represents a unique digital item whose ownership is managed by the blockchain. ## NFT object details | **Parameter** | **Type** | **Description** | |-------------------|---------|-------------------------------------------------------------------------------------------------------| | name | String | The name of the NFT | | tokenId | String | The token ID of the NFT | | amount | String | Specified tokenId NFT's total supply | | tokenUri | String | NFT MetaData stored address | | image | String | An image of the item. Note that this is the cached url we store on our end. | | imagePreviewUrl | String | A preview image of the item. Note that this is the cached url we store on our end. | | imageThumbnailUrl | String | A thumbnail image of the item. Note that this is the cached url we store on our end. | | animationUrl | String | A link to animation Resource Url for the item. Note that this is the cached url we store on our end. | | attributes | Object | An object of the Token Attributes Model | | assetContracts | Object | An object of the Token [Asset Contract Model](./marketplace-collection-model#asset-contract-model) | | collection | Object | An object of the Token [Collection Model](./marketplace-collection-model#collection-model) | | ownerAddress | String | The address of the owner of the assets | | isLazyMintType | Boolean | Whether or not it is delayed minting and no transfer has occurred | - [Collection models](https://web3.okx.com/onchainos/docs/waas/marketplace-collection-model.md) # Collection models Collections are used to represent all the assets in a single (or multiple) contract address(es) and help users group items from the same creator. They have one or more owners and are typically associated with important metadata such as creator royalties and descriptions.

The below OKX Football Cup is an example of a collection shown on OKX. ![collection](../images/collection.png) ## Collection model All related information for the collection: | **Parameter** |
**Type**
| **Description** | |-----------------|-----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | name | String | Collection name | | des | String | Collection description | | image | String | Collection logo URL | | backgroundImage | String | Collection background image URL | | slug | String | Collection slug, which is the unique identifier of the collection | | certificateFlag | Boolean | Collection certification flag | | officialWebsite | String | Collection official website | | instagramUrl | String | The Instagram URL of the collection | | discordUrl | String | The Discord URL of the collection | | mediumUrl | String | The Medium URL of the collection | | twitterUrl | String | The Twitter URL of the collection | | categoryList | Array | The category list of the collection | | assetContracts | Array | An Array of the [Asset Contract Model](#asset-contract-model) that are associated with this collection, including contract address, protocol standard, owner address, whether the ERC-2981 protocol is supported, etc. | | stats | Object | A dictionary containing some statistics related to this collection, including trade volume and floor prices, an object of the [Collection Stats Model](#collection-stats-model) | ## Asset contract model The Information for Collection | **Parameter** | **Type** | **Description** | |-----------------|----------|--------------------------------------------------------------------| | chain | String | The chain of the contract that is associated with this collection | | contractAddress | String | A contract address that is associated with this collection | | tokenStandard | String | The protocol type of the contract eg: ERC-721, ERC-1155 | | ownerAddress | String | The owner address of the contract | | erc2981 | Boolean | Whether the contract supports 2981 protocol | ## Collection stats model The related statistics for the collection | **Parameter** | **Type** | **Description** | |----------------|----------|-------------------------------------------| | latestPrice | String | The latest sale price of this collection | | totalVolume | String | The total sale volume of this collection | | totalCount | String | The total NFT count of this collection | | ownerCount | String | The owner count of this collection | | floorPrice | String | The floor price of this collection | - [Order models ](https://web3.okx.com/onchainos/docs/waas/marketplace-order-model.md) # Order models ## Order status | Status | Description | |-----------|------------------------------------------------------------------------------------------| | active | Indicates that the order is currently valid and can be traded | | inactive | Indicates that the order is temporarily inactive and may become active again in the future | | cancelled | Indicates that the order has been cancelled and cannot be traded | | sold | Indicates that the order has been traded and cannot be traded again | ## OKX order model The response to creating an order or query order: | **Parameter** | **Type** | **Description** | |-------------------|----------|-------------------------------------------------------------------------------------------------| | orderId | String | Order ID | | createTime | Long | Creation time of the order, timestamp in seconds | | updateTime | Long | Time when order status is updated, timestamp in seconds | | listingTime | Long | Order listing time, timestamp in seconds | | expirationTime | Long | Expiry time of the order, end time, timestamp in seconds | | status | String | Order status, including active, cancelled, sold, inactive, see “Order Status Enumeration” | | orderHash | String | The Order hash | | protocolData | String | Order parameters (json), structure varies for each market | | protocolAddress | String | Order transaction contract address | | chain | String | Chain name refer to [Supported blockchains](./marketplace-supported-blockchains) for details | | maker | String | Address of the person who initiated the order | | orderType | String | Offer indicates offer; BuyNow indicates listings | | price | String | Price per NFT for the order | | currencyAddress | String | Address of the token used in the order | | collectionAddress | String | NFT contract address | | tokenId | String | NFT token ID | | amount | String | Quantity of NFTs for the order | | availableAmount | String | Quantity of NFTs that can be use for this order | ## Order parameters model The order parameters details for creating an order: | **Parameter** | **Type** | **Description** | |---------------------------------|-----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------| | offerer | String | The wallet address initiating the order | | offer | Array | The offerer of the order supplies all offered items list, an array of [Offer Item Model](#offer-item-model) | | consideration | Array | The consideration contains an array of items that must be received in order to fulfill the order, An array of [Consideration Item Model](#consideration-item-model) | | startTime | timestamp | The startTime indicates the block timestamp at which the order becomes active | | endTime | timestamp | The endTime indicates the block timestamp at which the order expires | | orderType | number | The orderType designates one of four types for the order depending on two distinct preferences: [OrderType](#ordertype) | | zone | String | | | zoneHash | String | A fixed value:0x00000000000000000000000000000000
00000000000000000000000000000000 | | salt | String | The salt represents an arbitrary source of entropy for the order | | conduitKey | String | A fixed value: 0x066003C1493A346357Af15158cD98
5b4A6e29D3F888888888888888888888888 | | totalOriginalConsiderationItems | number | The amount of consideration size | | counter | number | The counter indicates a value that must match the current counter for the given offerer | ## Offer item model The offerer of the order supplies all the offered items listed. When listing order, the offer array must have exactly one item, and it must be an ERC-721 or ERC-1155 token. When offering order, the offer array must have exactly one item, which must be a currency. | **Parameter** | **Type** | **Description** | |-----------------------|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [itemType](#itemtype) | number | The itemType designates the type of item, with valid types being Ether (or other native token for the given chain), ERC20, ERC721, ERC1155, ERC721 with "criteria" (explained below), and ERC1155 with criteria. | | token | String | The token designates the account of the item's token contract (with the null address used for Ether or other native tokens). | | | identifierOrCriteria | String | The identifierOrCriteria represents either the ERC721 or ERC1155 token identifier or, in the case of a criteria-based item type, a merkle root composed of the valid set of token identifiers for the item. This value will be ignored for Ether and ERC20 item types, and can optionally be zero for criteria-based item types to allow for any identifier. | | startAmount | number | The startAmount represents the amount of the item in question that will be required, should the order be fulfilled at the moment the order becomes active. | | | endAmount | number | The endAmount represents the amount of the item in question that will be required, should the order be fulfilled at the moment the order expires. If this value differs from the item's startAmount, the realized amount is calculated linearly based on the time elapsed since the order became active. | ## Consideration item model The consideration contains an array of items that must be received in order to fulfill the order. The consideration array must have exactly two or three items. The items are (in order): the asset (when offer is NFT, listing is the offerer fee), the optional OKX fee, and an optional collection fee. | **Parameter** | **Type** | **Description** | |-----------------------|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [itemType](#itemtype) | number | The itemType designates the type of item, with valid types being Ether (or other native token for the given chain), ERC20, ERC721, ERC1155, ERC721 with "criteria" (explained below), and ERC1155 with criteria. | | token | String | The token designates the account of the item's token contract (with the null address used for Ether or other native tokens). | | identifierOrCriteria | String | The identifierOrCriteria represents either the ERC721 or ERC1155 token identifier or, in the case of a criteria-based item type, a merkle root composed of the valid set of token identifiers for the item. This value will be ignored for Ether and ERC20 item types, and can optionally be zero for criteria-based item types to allow for any identifier. | | startAmount | number | The startAmount represents the amount of the item in question that will be required, should the order be fulfilled at the moment the order becomes active. | | endAmount | number | The endAmount represents the amount of the item in question that will be required, should the order be fulfilled at the moment the order expires. If this value differs from the item's startAmount, the realized amount is calculated linearly based on the time elapsed since the order became active. | | recipient | String | Recipient that will receive each item. | ### Enums #### OrderType ```java enum OrderType { FULL_OPEN, PARTIAL_OPEN, FULL_RESTRICTED, PARTIAL_RESTRICTED } ``` #### ItemType ```java enum ItemType { NATIVE, ERC20, ERC721, ERC1155, ERC721_WITH_CRITERIA, ERC1155_WITH_CRITERIA } ``` ## Buy item model | **Parameter** | **Type** | **Description** | |---------------|----------|----------------------------| | orderId | String | order ID to fill | | takeCount | Integer | Quantity of tokens to buy | - [Interact with different order types](https://web3.okx.com/onchainos/docs/waas/marketplace-order-types.md) # Interact with different order types Order types can be divided into the OKX Aggregator contract and OKX NFT Market contract. ## OKX Aggregator contract The OKX Aggregator API is ```trade```, and this interface encapsulates the calldata needed to make calls to other markets. ```sql function tradeV3( MarketRegistry.TradeDetails[] calldata tradeDetails, AggregatorParamV3[] calldata aggregatorParam, bool isAtomic ) external payable nonReentrant ``` **MarketRegistry** ``MarketRegistry`` is the registration contract in which all other markets supported by the aggregator need in order to be registered. ```sql struct TradeDetails { uint256 marketId; uint256 value; bytes32 orderHash; bytes tradeData; } ``` | **Parameter** | **Description** | |---------------|--------------------------------------------------------------------------------------------| | marketId | Marketplace custom ID | | value | Pay amount of native tokens, such as ETH | | orderHash | Order hash | | tradeData | Calldata of transaction executed in other markets. Please refer to the Using Marketplace API section. | **AggregatorParamV3** ```sql struct AggregatorParamV3 { uint256 actionType; uint256 payAmount; address payToken; address tokenAddress; uint256 tokenId; uint256 amount; uint256 tradeType; bytes extraData; } ``` | **Parameter** | **Description** | |---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | actionType | Operation type, currently only supporting seaport
```1```: ```_SEAPORT_BUY_ETH```
```2```: ```_SEAPORT_BUY_ERC20```
```3```: _```SEAPORT_ACCEPT``` | | payAmount | The number of ERC-20 tokens used for order payment | | payToken | ERC-20 token address for order payment | | tokenAddress | The token address of ERC-721/ERC-1155 | | tokenId | Token ID | | amount | Token amount | | tradeType | ```0```: ```NATIVE```, // ETH on mainnet, MATIC on Polygon
```1```: ```ERC721```,
```2```: ```ERC1155```,
```3```: ```ERC721_WITH_CRITERIA```,
```4```: ```ERC1155_WITH_CRITERIA```,
```5```: ```ERC20``` | | extraData | Extra data: address, address, address (order's maker, order's taker, approve contract's address) | **isAtomic** Setting this to true means a revert action will happen if any order execution fails during batch order execution, and setting this to false means a revert does not happen. ## OKX NFT market contract ### 1. Listing Listing order means to list the NFT and wait for the buyer to purchase. Order will be generated and signed during listing. Please refer to the [retrieve Marketplace listing structure](./marketplace-create-a-listing) section. ### 2. Order execution Support interfaces of ***fulfillBasicOrder*** and ***fulfillAdvancedOrder*** **2.1 fulfillBasicOrder** ```sql function fulfillBasicOrder(BasicOrderParameters calldata parameters) external payable override returns (bool fulfilled); ``` Indices of fulfillBasicOrder interface are shown below: ```sql struct BasicOrderParameters { address considerationToken; uint256 considerationIdentifier; uint256 considerationAmount; address payable offerer; address zone; address offerToken; uint256 offerIdentifier; uint256 offerAmount; BasicOrderType basicOrderType; uint256 startTime; uint256 endTime; bytes32 zoneHash; uint256 salt; bytes32 offererConduitKey; bytes32 fulfillerConduitKey; uint256 totalOriginalAdditionalRecipients; AdditionalRecipient[] additionalRecipients; bytes signature; } ``` ```considerationToken```: Consideration token address ```considerationIdentifier```: Consideration token ID ```considerationAmount```: The number of consideration tokens ```offerer```: The account address of the offerer ```zone```: Order zone ```offerToken```: Address of the offer token ```offerIdentifier```: Offer token ID ```offerAmount```: Number of the offer token ```basicOrderType```: Order type ```startTime```: Order effective time ```endTime```: Order expiration time ```zoneHash```: The hash value passed to the zone ```salt```: Order random entropy source ```offererConduitKey```: ConduitKey of the offerer ```fulfillerConduitKey```: ConduitKey of the fulfiller ```totalOriginalAdditionalRecipients```: The number of addresses that receives consideration tokens ```additionalRecipients```: Recipients of additional tokens ```signature```: Signature of the transaction executor ```sql enum BasicOrderType { // 0: no partial fills, anyone can execute ETH_TO_ERC721_FULL_OPEN, // 1: partial fills supported, anyone can execute ETH_TO_ERC721_PARTIAL_OPEN, // 2: no partial fills, only offerer or zone can execute ETH_TO_ERC721_FULL_RESTRICTED, // 3: partial fills supported, only offerer or zone can execute ETH_TO_ERC721_PARTIAL_RESTRICTED, // 4: no partial fills, anyone can execute ETH_TO_ERC1155_FULL_OPEN, // 5: partial fills supported, anyone can execute ETH_TO_ERC1155_PARTIAL_OPEN, // 6: no partial fills, only offerer or zone can execute ETH_TO_ERC1155_FULL_RESTRICTED, // 7: partial fills supported, only offerer or zone can execute ETH_TO_ERC1155_PARTIAL_RESTRICTED, // 8: no partial fills, anyone can execute ERC20_TO_ERC721_FULL_OPEN, // 9: partial fills supported, anyone can execute ERC20_TO_ERC721_PARTIAL_OPEN, // 10: no partial fills, only offerer or zone can execute ERC20_TO_ERC721_FULL_RESTRICTED, // 11: partial fills supported, only offerer or zone can execute ERC20_TO_ERC721_PARTIAL_RESTRICTED, // 12: no partial fills, anyone can execute ERC20_TO_ERC1155_FULL_OPEN, // 13: partial fills supported, anyone can execute ERC20_TO_ERC1155_PARTIAL_OPEN, // 14: no partial fills, only offerer or zone can execute ERC20_TO_ERC1155_FULL_RESTRICTED, // 15: partial fills supported, only offerer or zone can execute ERC20_TO_ERC1155_PARTIAL_RESTRICTED, // 16: no partial fills, anyone can execute ERC721_TO_ERC20_FULL_OPEN, // 17: partial fills supported, anyone can execute ERC721_TO_ERC20_PARTIAL_OPEN, // 18: no partial fills, only offerer or zone can execute ERC721_TO_ERC20_FULL_RESTRICTED, // 19: partial fills supported, only offerer or zone can execute ERC721_TO_ERC20_PARTIAL_RESTRICTED, // 20: no partial fills, anyone can execute ERC1155_TO_ERC20_FULL_OPEN, // 21: partial fills supported, anyone can execute ERC1155_TO_ERC20_PARTIAL_OPEN, // 22: no partial fills, only offerer or zone can execute ERC1155_TO_ERC20_FULL_RESTRICTED, // 23: partial fills supported, only offerer or zone can execute ERC1155_TO_ERC20_PARTIAL_RESTRICTED } ``` **2.2 fulfillAdvancedOrder** ```sql function fulfillAdvancedOrder( AdvancedOrder calldata advancedOrder, CriteriaResolver[] calldata criteriaResolvers, bytes32 fulfillerConduitKey address recipient ) external payable override returns (bool fulfilled) ``` Among them, the parameters ```fulfillerConduitKey```, ```CriteriaResolver``` and ```AdvancedOrder``` are resolved as follows: - **fulfillerConduitKey**: Order executor's ConduitKey - **recipient**: Specifies the recipient address of the token. If it is not set, it defaults to msg.sender. - **CriteriaResolver**: The condition resolver used to verify whether the parameters such as the merkle path of the restriction are satisfied ```sql struct CriteriaResolver { uint256 orderIndex; Side side; uint256 index; uint256 identifier; bytes32[] criteriaProof; } ``` ```orderIndex```: Specifies the order among multiple orders ```side```: The offerer or its counterparty to the offer ```index```: The index value of OfferItem or ConsiderationItem in the order ```identifier```: The token id of the order transaction ```criteriaProof```: Merkle proof - **Advanced Order**: Order indices ```sql struct AdvancedOrder { OrderParameters parameters; uint120 numerator; uint120 denominator; bytes signature; bytes extraData; } ``` ```numerator```: The numerator of the partial transaction ```denominator```: Denominator of the partial transaction ```signature```: Order signature ```parameters```: Order parameters, as follows: ```sql struct OrderParameters { address offerer; address zone; OfferItem[] offer; ConsiderationItem[] consideration; OrderType orderType; uint256 startTime; uint256 endTime; bytes32 zoneHash; uint256 salt; bytes32 conduitKey; uint256 totalOriginalConsiderationItems; } ``` ```offerer```: Order quoter ```offer```: The assets marked by the offerer ```Consideration```: Assets the offerer receives after the order is fulfilled ```zone```: The address of the account that can cancel an order and restrict parties to fulfill restricted order ```orderType```: Order type. This supports a duo combination of open or restricted and complete or partial orders. Open orders can be executed by anyone, and restricted orders are those that can only be executed by the offerer or the zone. ```startTime```: Order effective time ```endTime```: Order expiration time ```zoneHash```: The hash value used for the verification of restricted orders. The zone can decide whether to use the hash value. ```salt```: Order random entropy source ```conduitKey```: A bytes32 type value. conduitKey corresponds to a contract that can perform a token transfer on behalf of the order offerer. ```totalOriginalConsiderationItems```: The number of consideration items. This parameter must be defined because the caller may pass in additional underlying assets. - **OfferItem** ```sql struct OfferItem { ItemType itemType; address token; uint256 identifierOrCriteria; uint256 startAmount; uint256 endAmount; } ``` ```token```: The address of the quote token ```identifierOrCriteria```: This value can be 0, the value of a single token ID or the merkle root of token IDs ```startAmount```: The initial quantity ```endAmount```: The final amount. startAmount and endAmount are the same for fixed price orders, but in the auction endAmount would be greater or lesser than startAmount over time. Order type is expressed by **ItemType**: ```sql enum ItemType { // 0: ETH on mainnet, MATIC on polygon, etc. NATIVE, // 1: ERC20 items (ERC777 and ERC20 analogues could also technically work) ERC20, // 2: ERC721 items ERC721, // 3: ERC1155 items ERC1155, // 4: ERC721 items where a number of tokenIds are supported ERC721_WITH_CRITERIA, // 5: ERC1155 items where a number of ids are supported ERC1155_WITH_CRITERIA } ``` ```NATIVE```: Main chain token ```ERC721_WITH_CRITERIA```: Multiple ERC-721 standard NFTs. Can be used with identifierOrCriteria ```ERC1155_WITH_CRITERIA```: Multiple ERC-1155 standard NFTs. Can be used with identifierOrCriteria ```sql struct ConsiderationItem { ItemType itemType; address token; uint256 identifierOrCriteria; uint256 startAmount; uint256 endAmount; address payable recipient; } ``` ```ConsiderationItem``` and ```OfferItem``` almost have the same items. ConsiderationItem adds the recipient field to indicate which addresses will get the token from the order execution. ### 3. Order cancellation Support batch order cancellation. Only the ```offerer``` and the ```zone``` can cancel an order. ```sql function cancel(OrderComponents[] calldata orders) external override returns (bool cancelled); ``` Data structure of OrderComponents: ```sql struct OrderComponents { address offerer; address zone; OfferItem[] offer; ConsiderationItem[] consideration; OrderType orderType; uint256 startTime; uint256 endTime; bytes32 zoneHash; uint256 salt; bytes32 conduitKey; uint256 counter; } ``` ```OrderComponents``` and ```OrderParameters``` have very similar parameters. The ```counter``` is a count of the transaction number. - [Deployed contract](https://web3.okx.com/onchainos/docs/waas/marketplace-deployed-contract.md) # Deployed contract ## OKX NFT aggregator contract | **Number** | **Network** | **Contract address** | |------------|---------------|--------------------------------------------| | 1 | Ethereum | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 2 | OKTC | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 3 | BNB Chain | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 4 | Polygon | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 5 | Avalanche-C | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 6 | Arbitrum One | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 7 | Arbitrum Nova | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 8 | zkSync Era | 0x444b2Fd4395Ec890fbC492753DCe1bE2fC8Ff63D | | 9 | Optimism | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 10 | Klaytn | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 11 | Base | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 12 | Linea | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 13 | opBNB | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | | 14 | Polygon zkEVM | 0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c | ## OKX self-operated marketplace contract | **Number** | **Network** | **Contract address** | |------------|---------------|--------------------------------------------| | 1 | Ethereum | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 2 | OKTC | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 3 | BNB Chain | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 4 | Polygon | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 5 | Avalanche-C | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 6 | Arbitrum One | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 7 | Arbitrum Nova | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 8 | zkSync Era | 0xd756E8070b33a35E42f00140Ac92c4b4e0bBfb82 | | 9 | Optimism | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 10 | Klaytn | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 11 | Base | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 12 | Linea | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 13 | opBNB | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | | 14 | Polygon zkEVM | 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC | - [BTC Ordinals API](https://web3.okx.com/onchainos/docs/waas/marketplace-ordinals-api.md) # BTC Ordinals API - [Quick start](https://web3.okx.com/onchainos/docs/waas/ordinals-quick-start.md) # Quick start In this guide, we will show you how to create an ordinals listing on OKX. Note: Doing the steps below at a lower price point will lower the current listing price to the new request. This process includes: - Get valid inscription data - Get UTXO information - Get the PSBT signed - Submit ordinals listing ## 1. Make request to get valid inscription data First you need to get the available Bitcoin NFT/inscription in order to create a listing on OKX platform. Refer to [Retrieve valid inscriptions](https://web3.okx.com/web3/build/docs/waas/marketplace-ordinals-get-inscriptions) for more details. Step 1: Create header ``` javascript const apiBaseUrl = 'https://web3.okx.com'; const requestUrl = '/api/v5/mktplace/nft/ordinals/get-valid-inscriptions'; // const originalMessage = JSON.stringify({ slug: 'BTC Ordinals', walletAddress: 'bc1qek7lal8ghnmus3dw897atlpgvmv27zgdgqfawx', limit: '10', isBrc20: false // true for brc20 tokens. Note: Default value is true if not included }); const apiRequestUrl = getRequestUrl(apiBaseUrl, requestUrl); const headersParams = { 'Content-Type': 'application/json', 'OK-ACCESS-KEY': apiKey, 'OK-ACCESS-SIGN': cryptoJS.enc.Base64.stringify( cryptoJS.HmacSHA256(timestamp + 'POST' + '/api/v5/mktplace/nft/ordinals/get-valid-inscriptions' + originalMessage , secretKey) ), 'OK-ACCESS-TIMESTAMP': timestamp, 'OK-ACCESS-PASSPHRASE': passphrase, }; ``` Step 2: Make the request ``` javascript return fetch(apiRequestUrl, {method: 'post', headers: headersParams, body: originalMessage}) .then((res) => { console.log(res) return res.json() } ).then((res) => { console.log(JSON.stringify(res)) return res; }); ``` ``` json { "code": 0, "data": { "cursor": "MTY5MDQ1NzA3NTE2OToxNj...FwOW5wa3Z3Z2xjbWo4dGg0cXF6amVxbGtweXVxbGp3Y3AyMDh4MzM3ZmV4cDI2cDBteHA4cXQ4MjB4ZA==", "inscriptionInfos": [ { "amount": "1", "inscriptionId": "08ea6e794016c8f11dd...f85222561c15ba29a6f54d3c75fd184a9i0", "nftId": "16514...22585458", "ticker": "", "tickerId": "" }, { "amount": "1", "inscriptionId": "0c3020593597d1f5818...cf23cbcb91d9b7fb8e3e0cefa0b2dfi0", "nftId": "2105134...1490", "ticker": "", "tickerId": "" } ] }, "msg": "" } ``` ## 2. Get UTXO information In order to get PSBT of the transaction, it would need to match UTXO. Therefore, it is necessary to get UTXO of the inscription. You would need inscriptionId at this stage. Refer to [query UTXO](https://web3.okx.com/web3/build/docs/waas/api-transaction-get-utxo) for more details. Step 1: Create a new header and body to retrieve UTXO information ``` javascript const apiBaseUrl = 'https://web3.okx.com'; const requestUrl = '/api/v5/waas/transaction/get-utxo'; // this endpoint is to get UTXO information of the inscription const utxoRequestBody = JSON.stringify({ chainId:0, utxoRequests: [ { address: "bc1p9npkvwglc...ljwcp208x337fexp26p0mxp8qt820xd", // the wallet that holds the inscription coinAmount: 0, // use default value 0 serviceCharge: 0, // use default value 0 utxoType: 2, // default type 2 for utxo inscription check nftId: "1803359c...cfeb15d1aa6ade40i0" // this is inscription ID } ] }) const apiRequestUrl = getRequestUrl(apiBaseUrl, requestUrl); const headersParams = { 'Content-Type': 'application/json', 'OK-ACCESS-KEY': apiKey, 'OK-ACCESS-SIGN': cryptoJS.enc.Base64.stringify( cryptoJS.HmacSHA256(timestamp + 'POST' + requestUrl + utxoRequestBody , secretKey) ), 'OK-ACCESS-TIMESTAMP': timestamp, 'OK-ACCESS-PASSPHRASE': passphrase, }; ``` Step 2: Collect UTXO information ``` javascript return fetch(apiRequestUrl, {method: 'post', headers: headersParams, body: utxoRequestBody}) .then((res) => { console.log(res) return res.json() } ).then((res) => { console.log(JSON.stringify(res)) return res; }); ``` Then you will get the below UTXO information ``` json { "address": "bc1pt5w9...2m8cky8qxjn3rg", "canTransferAmount": "0", "utxoType": 2, "totalUtxoNum": 0, "utxoList": [ { "txHash": "02ecbe7ef51...87a7c6e64409883f66f4e3036", "vout": 0, "coinAmount": 546, "confirmations": 3548, "utxoType": 2, "status": 1, "utxoBizStatus": 0, "hasNft": true, "hasCheckNftExist": true, "nftLocaltionVOs": [ { "nftId": "02ecbe7ef5143...3f3de87a7c6e64409883f66f4e3036i0", // this is inscriptionId "nftLocation": "02ecbe7ef51431...fccb83f3de87a7c6e64409883f66f4e3036:0:0", "nftType": 2, "brc20Nft": true } ], "key": "02ecbe7ef514311523d0e7f...3f3de87a7c6e64409883f66f4e3036-0", "dummy": false, "spending": false } ] } ``` ## 3. Get PSBT information Next, we need to set the listing price and get PSBT with the listing price. Refer to [wallet SDK](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-bitcoin/src/psbtSign.ts) for more details. For lowering listing price - If the price is higher than current listing price, it will throw exception. For both lowering listing price and new listing - Exception will be thrown if the total amount is below 0.00001 BTC. Step 1: Create a message for PSBT data ``` javascript import { generateSignedListingPsbt, networks } from '@okxweb3/coin-bitcoin'; const listingData = { nftAddress: 'bc1pt5w9...2m8cky8qxjn3rg', nftUtxo: { txHash: '02ecbe7ef51...87a7c6e64409883f66f4e3036', vout: 0, coinAmount: 546, rawTransaction: undefined }, receiveBtcAddress: 'bc1p9npkvwglcmj8th4q...cp208x337fexp26p0mxp8qt820xd', // your btc wallet address price: 10000 // total price in Satoshi unit } ``` Step 2: Using [OKT wallet SDK](https://github.com/okx/js-wallet-sdk/blob/main/packages/coin-bitcoin/src/psbtSign.ts) will allow us to get psbt data ``` javascript const psbt = generateSignedListingPsbt(listingData, privateKey, networks.bitcoin); console.log(psbt); ``` ## 4. Submit ordinals listing to OKX platform With the PSBT signature and pricing information set this to the end point and you will be able to list the ordinals to OKX. Step 1: Create setup new endpoint information and create header information for submit listing unitPrice will vary for BRC-20 or BTC NFT. For BTC NFT it will be the same as totalPrice since BTC NFT amount is 1, but for BRC-20, the unitPrice will be totalPrice divided by the number of shares given. For example, totalPrice is 10000 sats and the number of inscriptions is 50, then the unitPrice would be 10000/50 = 200. ``` javascript const apiBaseUrl = 'https://web3.okx.com'; const requestUrl = '/api/v5/mktplace/nft/ordinals/okx/make-orders'; // this endpoint is to get UTXO information of the inscription const submitListingBody = JSON.stringify({ brc20: false, items: [ { inscriptionId: inscriptionId, nftId: nftId, // get this data part 1 step 2 by mapping it to inscriptionId orderType: 2, totalPrice: 100000, // this price should match part 3 step 1 unitPrice: 100000, // this price will varies for BRC20 or btc NFT. Check out NOTE on unitPrice psbt: 'cHNidP8BAP0GAQIAAAADAAAAAAAA...ZUDTZKgR6mGJSkBSJuPsgb2gGCekW+W04EtAAAAAA=', } ], tickerId: '' }) const apiRequestUrl = getRequestUrl(apiBaseUrl, requestUrl); const headersParams = { 'Content-Type': 'application/json', 'OK-ACCESS-KEY': apiKey, 'OK-ACCESS-SIGN': cryptoJS.enc.Base64.stringify( cryptoJS.HmacSHA256(timestamp + 'POST' + requestUrl + submitListingBody , secretKey) ), 'OK-ACCESS-TIMESTAMP': timestamp, 'OK-ACCESS-PASSPHRASE': passphrase, }; ``` Step 2: Request to submit listing ``` javascript return fetch(apiRequestUrl, {method: 'post', headers: headersParams, body: submitListingBody}) .then((res) => { console.log(res) return res.json() } ).then((res) => { console.log(JSON.stringify(res)) return res; }); ``` At the end you will get success message as shown below. ``` json { "result": [ { "nftID": 20824...473273458, // should be the same nftId as part 4 step 1 "errorMsg": "", "success": true, } ] } ``` - [Create listing to OKX](https://web3.okx.com/onchainos/docs/waas/create-ordinals-api.md) # Create listing to OKX - [Retrieve valid inscriptions](https://web3.okx.com/onchainos/docs/waas/marketplace-ordinals-get-inscriptions.md) {/* api-page */} # Retrieve valid inscriptions This interface is used to get the valid inscription data respectively to the given wallet address. ### Request address POST `https://web3.okx.com/api/v5/mktplace/nft/ordinals/get-valid-inscriptions` ### Request param | **Parameter** | **Type** | **Required** | **Description** | |----------------|----------|--------|-----------------------------------------| |slug | String | Yes | The collection’s slug, which is the unique identifier of the collection | | cursor | String | No | For pagination. A cursor pointing to the page to retrieve | | limit | String | Yes | For pagination. The maximum number of collections to return. The default value is 10, and the max is 100 | | sort | String | No | Order sorting rules: ‘listing_time_desc’ means sorting in descending order based on the order creation time, while ‘listing_time_asc’ means sorting in ascending order based on the order update time, ‘price_desc’ means default sorting of order prices from high to low, ‘price_asc’ means default sorting of order prices from low to high; ‘unitprice_desc’ means default sorting of order unit prices from low to high, and ‘unitprice_asc’ means default sorting of order unit prices from high to low. The default sorting rule is to sort in descending order by time | | isBrc20 | Boolean | No | Retrieve the list of BTC NFT or BRC 20 listings, the default is ‘Yes’ | | walletAddress | String | Yes | The wallet address which querying for the valid inscriptions | ### Response param An array of ordinals inscription information. | **Parameter** | **Type** | **Description** | |---------------|------------|-----------------------------------------| | inscriptionId | String | Inscription ID | | cursor | String | To retrieve next page on the request, add this cursor value into the next request | | nftId | String | NFT ID for that inscription | | ticker | String | Ticker for the BRC-20 token | | tickerId | String | ID for that ticker | | amount | String | Number of inscriptions in the order| ### Code request example ```shell curl --location 'https://web3.okx.com/api/v5/mktplace/nft/ordinals/get-valid-inscriptions' \ --header 'OK-ACCESS-KEY: your API key' \ --header 'OK-ACCESS-PASSPHRASE: your passphrase' \ --header 'Content-Type: application/json' \ --data '{ "slug": "BTC Ordinals", "walletAddress": "bc1qek.....27zgdgqfawx", "limit": "10", "isBrc20": false }' ``` ### Response example ```json { "code": 0, "data": { "cursor": "MTY5N.......WZhd3g=", "inscriptionInfos": [ { "amount": "1", "inscriptionId": "6218a48de6039b1e...fdce171601083961f45a326856dd30ffi0", "nftId": "208249...3273458", "ticker": "", "tickerId": "" }, { "amount": "1", "inscriptionId": "caf70bcc595389...a1ccb4ec81fa0a0612a95f2e8402a10710a373i0", "nftId": "20793046...2400114", "ticker": "", "tickerId": "" }, { "amount": "1", "inscriptionId": "ad14bd7fa6afee2bc37681f6...9b949746d258e0c8133c259a94198febf66bi0", "nftId": "17407619...517490", "ticker": "", "tickerId": "" }, { "amount": "1", "inscriptionId": "6f776f43d119094...37ce8abab7aea902a4455fc7b8b319122880f71a1ci0", "nftId": "16635...80929138", "ticker": "", "tickerId": "" }, { "amount": "1", "inscriptionId": "e0ae7e1ee159...d836fe692b1fb6b25911f9f6edec666da9fb090fdffe4i0", "nftId": "166355152...29586", "ticker": "", "tickerId": "" } ] }, "msg": "" } ``` - [Submit listing](https://web3.okx.com/onchainos/docs/waas/marketplace-ordinals-create-listing.md) {/* api-page */} # Submit listing This interface is used submit ordinals listings to OKX platform. Listing including BRC-20 and BTC NFT are possible. Psbt would require UTXO of the inscription which you can obtain from this interface [query UTXO](https://web3.okx.com/web3/build/docs/waas/api-transaction-get-utxo). ### Request address POST `https://web3.okx.com/api/v5/mktplace/nft/ordinals/okx/make-orders` ### Request param | **Parameter** | **Type** | **Required** | **Description** | |----------------|----------|--------|-----------------------------------------| | nftId | String | Yes | The unique identifier for the ordinal NFT that is listing | | inscriptionId | String | Yes | Inscription ID | | orderType | Integer | Yes | Type of this order. Use 2 to create ordinal listing | | unitPrice |BigDecimal | Yes | BRC-20 unit price/price of one NFT. Unit: satoshi | | isBrc20 | Boolean | No | If the respective listing is BRC-20, then true otherwise false. Default to true | | psbt | String | Yes | Partially signed Bitcoin transaction. Only base64 encoded PSBT is accepted | | totalPrice | BigDecimal | Yes | Total Price to be listed on the platform. Unit: satoshi| ### Response param | **Parameter** | **Type** | **Description** | |---------------|-----------|-----------------------------------------| | nftId | String | The unique NFT ID for this request | | success | Boolean | If it is successful, it will be true otherwise it will be false | | errorMsg | String | Detail error message for the failure of the request | ### Code request example ```shell curl --location 'https://web3.okx.com/api/v5/mktplace/nft/ordinals/okx/make-orders' \ --header 'OK-ACCESS-KEY: your api key' \ --header 'OK-ACCESS-PASSPHRASE: your passphrase' \ --header 'Content-Type: application/json' \ --data '{ "brc20": false, "items": [ { "inscriptionId": "02ecbe7ef5143...3f3de87a7c6e64409883f66f4e3036i0", "nftId": 20824...473273458, // get this data part 1 step 2 by mapping it to inscriptionId "orderType": 2, "totalPrice": 100000, // this price should match part 3 step 1 "unitPrice": 100000, // this price will varies for BRC20 or btc NFT. Check out NOTE on unitPrice "psbt": "cHNidP8BAP0GAQIAAAADAAAAAAAA...ZUDTZKgR6mGJSkBSJuPsgb2gGCekW+W04EtAAAAAA=", } ] } ' ``` ### Json response example ```json { "result": [ { "nftID": 20824...473273458, "errorMsg": "", "success": true, } ] } ``` - [Retrieve Ordinals collection](https://web3.okx.com/onchainos/docs/waas/marketplace-retrieve-ordinal-collection-list.md) {/* api-page */} # Retrieve Ordinals collection This interface is used to get the list of all BTC NFT and Brc20 collections, including the unique identifier slug of each collection, the range of inscription numbers, the volume, and the floor price. ### Request address GET `https://web3.okx.com/api/v5/mktplace/nft/ordinals/collections` ### Request param | **Parameter** | **Type** | **Required** | **Description** | |---------------|----------|--------------|---------------------------------------------------------------------------------------------------------------------------------------------| | slug | String | No | The collection‘s slug, which is the unique identifier of the collection.It means retrieve a specific collection when the value is not empty | | cursor | String | No | For pagination. A cursor pointing to the page to retrieve. | | limit | String | No | For pagination. The maximum number of collections to return. The default value is 100, and the max is 300. | | isBrc20 | Boolean | No | Retrieve the list of all BTC NFT and BRC-20 collections. The default value is true, and it will return the BRC-20 list. | ### Response param Array of objects of the [Ordinals collection model](./marketplace-ordinal-model.html#ordinals-collection-model) | **Parameter** | **Type** | **Description** | |---------------------|----------|--------------------------------------------------------------------------| | slug | String | The collection‘s slug, which is the unique identifier of the collection | | totalVolume | String | Total volume of a collection, priced in BTC | | floorPrice | String | Floor price of a collection, priced in BTC | | inscriptionNumRange | String | Range of inscription numbers for a collection | | volume24h | String | 24-hour trading volume of the collection, priced in BTC | | isBrc20 | Boolean | Used to distinguish Ordinals inscription types: Brc20 or BTC NFT | ### Request example ```shell curl -X GET "https://web3.okx.com/api/v5/mktplace/nft/ordinals/collections" \ -H 'OK-ACCESS-KEY: XXX' \ -H 'OK-ACCESS-TIMESTAMP: XXX' \ -H 'OK-ACCESS-PASSPHRASE: XXX' \ -H 'OK-ACCESS-SIGN: XXX' \ -d "limit=1" ``` ### Response example ```json { "code": 0, "data": { "cursor": "", "data": [ { "floorPrice": "0.00065", "inscriptionNumRange": "#10423123-#44607771", "isBrc20": false, "slug": "bitmap-4", "totalVolume": "3038.695704830937", "volume24h": "31.6151456383466366" } ] }, "msg": "" } ``` - [Retrieve Ordinals listings](https://web3.okx.com/onchainos/docs/waas/marketplace-retrieve-ordinal-listings.md) {/* api-page */} # Retrieve Ordinals listings This interface is used to get all active listings for a given collection. ### Request address POST `https://web3.okx.com/api/v5/mktplace/nft/ordinals/listings` ### Request param | **Parameter** | **Type** | **Required** | **Description** | |---------------|----------|--------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | slug | String | No | The collection‘s slug, which is the unique identifier of the collection. | | cursor | String | No | For pagination. A cursor pointing to the page to retrieve. | | limit | String | No | For pagination. The maximum number of collections to return. The default value is 10, and the max is 100. | | sort | String | No | Order sorting rules:
```listing_time_desc```: Listings sorted by newest creation time first
```listing_time_asc```: Listings sorted by oldest creation time first
```price_desc```: Listings with the highest price first
```price_asc```: Listings with the lowest price first
```unit_price_desc```: Listings with the highest unit price first
```unit_price_asc```: Listings with the lowest unit price first
Default sorting is by the newest creation time first. | | isBrc20 | Boolean | No | Retrieve the list of BTC NFT or Brc20 listings, the default is ‘Yes’ |
### Response param An array of [Ordinals Order Model](./marketplace-ordinal-model.html#ordinals-order-model) | **Parameter** | **Type** | **Description** | |---------------|----------|---------------------| | inscriptionId | String | Inscription number | | listingTime | Long | Listing time | | listingUrl | String | Link to the page | | ownerAddress | String | Owner address | | price | String | Price of an order | | unitPrice | String | Order unit price, priced in BTC | | amount | String | Number of inscriptions in the order | | isBrc20 | Boolean | Used to distinguish Ordinals inscription types: Brc20 or BTC NFT |
### Request example ```shell curl -X POST "https://web3.okx.com/api/v5/mktplace/nft/ordinals/listings" \ -H 'OK-ACCESS-KEY: XXX' \ -H 'OK-ACCESS-TIMESTAMP: XXX' \ -H 'OK-ACCESS-PASSPHRASE: XXX' \ -H 'OK-ACCESS-SIGN: XXX' \ -d "slug=sats" \ -d "limit=1" \ -d "sort=unit_price_asc" ``` ### Response example ```json { "code": 0, "data": { "cursor": "MC4wOjMxNDIwNjY5MTE=", "data": [ { "amount": "100", "inscriptionId": "8c9c19c9c2f54a7c3f19848a79f360746431d80bc2fa376146ab61743e4a514ai0", "isBrc20": true, "listingTime": 1701075376, "listingUrl": "https://web3.okx.com/web3/marketplace/nft/asset/btc/8c9c19c9c2f54a7c3f19848a79f360746431d80bc2fa376146ab61743e4a514ai0", "ownerAddress": "bc1p8a0ndtmczmmyvjv52280hf7zpl3qzml427eyfw6cjdjhc7ys4yxsvder0w", "price": "0.002", "slug": "sats", "unitPrice": "0" } ] }, "msg": "" } ```
- [Retrieve Ordinals activities](https://web3.okx.com/onchainos/docs/waas/marketplace-retrieve-ordinal-activities.md) {/* api-page */} # Retrieve Ordinals activities This interface is used to return all transaction records under a specific collection, including details such as the From and To addresses for the transactions, the time of each transaction, and the transaction prices. By default, records are sorted in descending order by transaction time. ### Request address POST `https://web3.okx.com/api/v5/mktplace/nft/ordinals/trade-history` ### Request param | **Parameter** | **Type** | **Required** | **Description** | |---------------|----------|--------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | slug | String | Yes | The collection‘s slug, which is the unique identifier of the collection. | | cursor | String | No | For pagination. A cursor pointing to the page to retrieve. | | limit | String | No | For pagination. The maximum number of collections to return. The default value is 10, and the max is 100. | | sort | String | No | Trade history is sorted by default in descending order ```desc``` by time, with an option for ascending order ```asc```. | | isBrc20 | Boolean | No | Retrieve the list of BTC NFT or Brc20 trade activities, the default is Yes | | orderSourceList | Integer[] | No | Retrieve orders for certain platforms, please fill in the code, such as [34,54] (34-OKX 54-Magic Eden 55-OrdinalsWallet 57-Unisat). | | tradeWalletAddress | String | No | The wallet address involved in the transaction. | | type | String | No | Transaction type, multiple separated by commas (SALE, LIST, TRANSFER, CANCEL_LIST, UPDATE_PRICE). Default return Sale data. | ### Response param An array of [Ordinals Activities Model](./marketplace-ordinal-model.html#ordinals-activities-model) | **Parameter** | **Type** | **Description** | |---------------|----------|------------------------------------| | fromAddress | String | From address in the transaction | | inscriptionId | String | Inscription number | | price | String | Price of the transaction | | timestamp | Long | Transaction timestamp | | toAddress | String | To address in the transaction | | unitPrice | String | Order unit price, priced in BTC | | amount | String | Number of inscriptions in the order | | isBrc20 | Boolean | Used to distinguish Ordinals inscription types: Brc20 or BTC NFT | | orderSource | Integer | Order source | | orderSourceName | String | The name of the source of the order | | type | String | Transaction type | ### Request example ```shell curl -X POST "https://web3.okx.com/api/v5/mktplace/nft/ordinals/trade-history" \ -H 'OK-ACCESS-KEY: XXX' \ -H 'OK-ACCESS-TIMESTAMP: XXX' \ -H 'OK-ACCESS-PASSPHRASE: XXX' \ -H 'OK-ACCESS-SIGN: XXX' \ -d "slug=xxx" \ -d "limit=1" ``` ### Response example ```json { "code": 0, "data": { "cursor": "MTcwMTE1NTM5MDo5OTZkYzdmMjljMzM1ODJhZjEwNDhjN2ZlMDgyZTU4Y2NhMTQ0ZDA3MzY0YTdkODc4NjUyYjhkM2ZhNGI2MTc3LTAtMjMzNTc5NTYzMDUxOTUxMjI=", "data": [ { "amount": "10000000000", "fromAddress": "bc1q8nvhsrn7k7ltp2p4qm65wd7yxgypv0rvlam2h9", "inscriptionId": "0bd89dfef32761d8465055bbf4ccfcdac8bbd56d28032a01833c8b41ff3025b1i0", "isBrc20": true, "price": "0.03698", "slug": "sats", "timestamp": 1701155390, "toAddress": "bc1phlcxss2jumzm5rskhcfnzpxnsg8d7jn24h97umk7qceal55k600spaczp4", "unitPrice": "0.000000000003698", "orderSource": 34, "orderSourceName": "okx", "type": "SALE" } ] }, "msg": "" } ``` - [Ordinals related models](https://web3.okx.com/onchainos/docs/waas/marketplace-ordinal-model.md) # Ordinals related models ## Ordinals collection model | **Parameter** | **Type** | **Description** | |---------------------|----------|-------------------------------------------------------------------------| | slug | String | The collection’s slug, which is the unique identifier of the collection | | totalVolume | String | Total volume of a collection, priced in BTC | | floorPrice | String | Floor price of a collection, priced in BTC | | inscriptionNumRange | String | Range of inscription numbers for a collection | | volume24h | String | 24-hour trading volume of the collection, priced in BTC | | isBrc20 | Boolean | Used to distinguish Ordinals inscription types: Brc20 or BTC NFT | ## Ordinals order model | **Parameter** | **Type** | **Description** | |---------------|----------|------------------------------------------------------------------| | inscriptionId | String | Inscription number | | listingTime | Long | Listing time | | listingUrl | String | Link to the page | | ownerAddress | String | Owner address | | price | String | Price of an order | | unitPrice | String | Order unit price, priced in BTC | | amount | String | Number of inscriptions in the order | | isBrc20 | Boolean | Used to distinguish Ordinals inscription types: Brc20 or BTC NFT | ## Ordinals activities model | **Parameter** | **Type** | **Description** | |---------------|----------|------------------------------------------------------------------| | fromAddress | String | From address in the transaction | | inscriptionId | String | Inscription number | | price | String | Price of the transaction | | timestamp | Long | Transaction timestamp | | toAddress | String | To address in the transaction | | unitPrice | String | Order unit price, priced in BTC | | amount | String | Number of inscriptions in the order | | isBrc20 | Boolean | Used to distinguish Ordinals inscription types: Brc20 or BTC NFT | - [Fractal Ordinals API](https://web3.okx.com/onchainos/docs/waas/marketplace-fractal-ordinals-api.md) # Fractal Ordinals API - [Retrieve Fractal Ordinals collection](https://web3.okx.com/onchainos/docs/waas/marketplace-fractal-retrieve-ordinal-collection-list.md) {/* api-page */} # Retrieve Fractal Ordinals collection This interface is used to get the list of all Fractal NFT and Brc20 collections, including the unique identifier slug of each collection, the range of inscription numbers, the volume, and the floor price. ### Request address GET `https://web3.okx.com/api/v5/mktplace/nft/fractal-ordinals/collections` ### Request param | **Parameter** | **Type** | **Required** | **Description** | |---------------|----------|--------------|---------------------------------------------------------------------------------------------------------------------------------------------| | slug | String | No | The collection‘s slug, which is the unique identifier of the collection.It means retrieve a specific collection when the value is not empty | | cursor | String | No | For pagination. A cursor pointing to the page to retrieve. | | limit | String | No | For pagination. The maximum number of collections to return. The default value is 100, and the max is 300. | | isBrc20 | Boolean | No | Retrieve the list of all Fractal NFT and BRC-20 collections. The default value is true, and it will return the BRC-20 list. | ### Response param Array of objects of the [Ordinals collection model](./marketplace-ordinal-model.html#ordinals-collection-model) | **Parameter** | **Type** | **Description** | |---------------------|----------|--------------------------------------------------------------------------| | slug | String | The collection‘s slug, which is the unique identifier of the collection | | totalVolume | String | Total volume of a collection, priced in FB | | floorPrice | String | Floor price of a collection, priced in FB | | inscriptionNumRange | String | Range of inscription numbers for a collection | | volume24h | String | 24-hour trading volume of the collection, priced in FB | | isBrc20 | Boolean | Used to distinguish Ordinals inscription types: Brc20 or Fractal NFT | ### Request example ```shell curl -X GET "https://web3.okx.com/api/v5/mktplace/nft/fractal-ordinals/collections" \ -H 'OK-ACCESS-KEY: XXX' \ -H 'OK-ACCESS-TIMESTAMP: XXX' \ -H 'OK-ACCESS-PASSPHRASE: XXX' \ -H 'OK-ACCESS-SIGN: XXX' \ -d "limit=1" ``` ### Response example ```json { "code": 0, "data": { "cursor": "", "data": [ { "floorPrice": "0.84", "inscriptionNumRange": "#398426-#3488986", "isBrc20": false, "slug": "fractal-pepe-1", "totalVolume": "6.927321832273747", "volume24h": "0.026769803732172824" } ] }, "msg": "" } ``` - [Retrieve Fractal Ordinals activities](https://web3.okx.com/onchainos/docs/waas/marketplace-fractal-retrieve-ordinal-activities.md) {/* api-page */} # Retrieve Fractal Ordinals activities This interface is used to return all transaction records under a specific collection, including details such as the From and To addresses for the transactions, the time of each transaction, and the transaction prices. By default, records are sorted in descending order by transaction time. ### Request address POST `https://web3.okx.com/api/v5/mktplace/nft/fractal-ordinals/trade-history` ### Request param | **Parameter** | **Type** | **Required** | **Description** | |---------------|----------|--------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | slug | String | Yes | The collection‘s slug, which is the unique identifier of the collection. | | cursor | String | No | For pagination. A cursor pointing to the page to retrieve. | | limit | String | No | For pagination. The maximum number of collections to return. The default value is 10, and the max is 100. | | sort | String | No | Trade history is sorted by default in descending order ```desc``` by time, with an option for ascending order ```asc```. | | isBrc20 | Boolean | No | Retrieve the list of Fractal NFT or Brc20 trade activities, the default is Yes | | orderSourceList | Integer[] | No | Retrieve orders for certain platforms, please fill in the code, such as [34,54] (34-OKX 54-Magic Eden 55-OrdinalsWallet 57-Unisat). | | tradeWalletAddress | String | No | The wallet address involved in the transaction. | | type | String | No | Transaction type, multiple separated by commas (SALE, LIST, TRANSFER, CANCEL_LIST, UPDATE_PRICE). Default return Sale data. | ### Response param An array of [Ordinals Activities Model](./marketplace-ordinal-model.html#ordinals-activities-model) | **Parameter** | **Type** | **Description** | |---------------|----------|------------------------------------| | fromAddress | String | From address in the transaction | | inscriptionId | String | Inscription number | | price | String | Price of the transaction, priced in FB | | timestamp | Long | Transaction timestamp | | toAddress | String | To address in the transaction | | unitPrice | String | Order unit price, priced in FB | | amount | String | Number of inscriptions in the order | | isBrc20 | Boolean | Used to distinguish Ordinals inscription types: Brc20 or Fractal NFT | | orderSource | Integer | Order source | | orderSourceName | String | The name of the source of the order | | type | String | Transaction type | ### Request example ```shell curl -X POST "https://web3.okx.com/api/v5/mktplace/nft/fractal-ordinals/trade-history" \ -H 'OK-ACCESS-KEY: XXX' \ -H 'OK-ACCESS-TIMESTAMP: XXX' \ -H 'OK-ACCESS-PASSPHRASE: XXX' \ -H 'OK-ACCESS-SIGN: XXX' \ -d "slug=xxx" \ -d "limit=1" ``` ### Response example ```json { "code": 0, "data": { "cursor": "MTcwMTE1NTM5MDo5OTZkYzdmMjljMzM1ODJhZjEwNDhjN2ZlMDgyZTU4Y2NhMTQ0ZDA3MzY0YTdkODc4NjUyYjhkM2ZhNGI2MTc3LTAtMjMzNTc5NTYzMDUxOTUxMjI=", "data": [ { "amount": "3096", "fromAddress": "bc1pgnwyzfjl0fmw4n87tr4stv8hyeed3fc2qnavrpkgv2cqv4vywfjsm69w7n", "inscriptionId": "b4f9d43757afdc94b04738577cf4d8a6f1262cff4c6f489b641c614539d285bdi0", "inscriptionNumber": "119738160", "isBrc20": true, "price": "6.192", "slug": "people", "timestamp": 1728991566, "toAddress": "bc1p9xuw2vdtk0z5m3nv3x6ljr32m4eu30u69472x6yy4rj9zsyguy0qwdu8p7", "unitPrice": "2000000", "orderSource": 84, "orderSourceName": "okx", "type": "SALE" } ] }, "msg": "" } ``` - [Retrieve valid inscriptions](https://web3.okx.com/onchainos/docs/waas/marketplace-fractal-ordinals-get-inscriptions.md) {/* api-page */} # Retrieve valid inscriptions This interface is used to get the valid inscription data respectively to the given wallet address. ### Request address POST `https://web3.okx.com/api/v5/mktplace/nft/fractal-ordinals/get-valid-inscriptions` ### Request param | **Parameter** | **Type** | **Required** | **Description** | |----------------|----------|--------|-----------------------------------------| |slug | String | Yes | The collection’s slug, which is the unique identifier of the collection | | cursor | String | No | For pagination. A cursor pointing to the page to retrieve | | limit | String | Yes | For pagination. The maximum number of collections to return. The default value is 10, and the max is 100 | | sort | String | No | Order sorting rules: ‘listing_time_desc’ means sorting in descending order based on the order creation time, while ‘listing_time_asc’ means sorting in ascending order based on the order update time, ‘price_desc’ means default sorting of order prices from high to low, ‘price_asc’ means default sorting of order prices from low to high; ‘unitprice_desc’ means default sorting of order unit prices from low to high, and ‘unitprice_asc’ means default sorting of order unit prices from high to low. The default sorting rule is to sort in descending order by time | | isBrc20 | Boolean | No | Retrieve the list of Fractal NFT or BRC 20 listings, the default is ‘Yes’ | | walletAddress | String | Yes | The wallet address which querying for the valid inscriptions | ### Response param An array of ordinals inscription information. | **Parameter** | **Type** | **Description** | |---------------|------------|-----------------------------------------| | inscriptionId | String | Inscription ID | | cursor | String | To retrieve next page on the request, add this cursor value into the next request | | nftId | String | NFT ID for that inscription | | ticker | String | Ticker for the BRC-20 token | | tickerId | String | ID for that ticker | | amount | String | Number of inscriptions in the order| ### Code request example ```shell curl --location 'https://web3.okx.com/api/v5/mktplace/nft/fractal-ordinals/get-valid-inscriptions' \ --header 'OK-ACCESS-KEY: your API key' \ --header 'OK-ACCESS-PASSPHRASE: your passphrase' \ --header 'Content-Type: application/json' \ --data '{ "slug": "Fractal Ordinals", "walletAddress": "bc1qek.....27zgdgqfawx", "limit": "10", "isBrc20": false }' ``` ### Response example ```json { "code": 0, "data": { "cursor": "MTY5N.......WZhd3g=", "inscriptionInfos": [ { "amount": "1", "inscriptionId": "ad14bd7fa6afee2bc37681f6...9b949746d258e0c8133c259a94198febf66bi0", "nftId": "17407619...517490", "ticker": "", "tickerId": "" }, { "amount": "1", "inscriptionId": "6f776f43d119094...37ce8abab7aea902a4455fc7b8b319122880f71a1ci0", "nftId": "16635...80929138", "ticker": "", "tickerId": "" }, { "amount": "1", "inscriptionId": "e0ae7e1ee159...d836fe692b1fb6b25911f9f6edec666da9fb090fdffe4i0", "nftId": "166355152...29586", "ticker": "", "tickerId": "" } ] }, "msg": "" } ``` - [Error codes](https://web3.okx.com/onchainos/docs/waas/marketplace-error-code.md) # Error codes | Code | HTTP status | Message | | ----- | ----------- | ---------------------------------------------------------------------------------------- | | 0 | 200 | Succeeded | | 50011 | 429 | Rate limit reached; please refer to API documentation and throttle requests accordingly | | 50014 | 400 | Parameter param0 cannot be empty | | 50026 | 500 | System error; try again later | | 50103 | 401 | Request header "OK-ACCESS-KEY" cannot be empty | | 50104 | 401 | Request header "OK-ACCESS-PASSPHRASE" cannot be empty. | | 50105 | 401 | Request header "OK-ACCESS-PASSPHRASE" incorrect | | 50106 | 401 | Request header "OK-ACCESS-SIGN" cannot be empty | | 50107 | 401 | Request header "OK-ACCESS-TIMESTAMP" cannot be empty | | 50111 | 401 | Invalid OK-ACCESS-KEY | | 50112 | 401 | Invalid OK-ACCESS-TIMESTAMP | | 50113 | 401 | Invalid signature | | 83000 | 200 | Data not found | | 83001 | 200 | Wrong parameters | | 83002 | 200 | Chain not supported | | 83003 | 200 | Time range contains a conflict between optional exclusive peers [createTime, updateTime] | - [Introduction](https://web3.okx.com/onchainos/docs/waas/defi-introduction.md) # Introduction OKX Web3 DeFi is the only all-in-one DeFi investment solution on the market. Our multichain DeFi aggregator provides users with a comprehensive platform for aggregating investment opportunities in DeFi, enabling them to quickly and easily locate investment products that meet their needs. OKX Web3 DeFi has accessed over 80 protocols like Aave, Compound, Curve, Yearn, and Uniswap. We also provide support for over 15 networks, such as Arbitrum, Ethereum, and Polygon. Integrating OKX Web3 DeFi Open API into your application will enable users to easily and quickly access all DeFi protocols and enjoy the benefits when investing in DeFi. - [Quickstart](https://web3.okx.com/onchainos/docs/waas/defi-quickstart.md) # Quickstart - [Overview](https://web3.okx.com/onchainos/docs/waas/defi-quickstart-overview.md) # Overview This page explains the data interaction process of the OKX Web3 DeFi investment. ## Interaction process 1. Subscription process. 2. Redemption process. 3. Reward claiming process. ![image](../images/defi-quickstart-overview-en.png) - [Subscription process](https://web3.okx.com/onchainos/docs/waas/defi-quickstart-subscription-flow.md) # Subscription process For the subscription process, please refer to the subscription flow section in the [overview](defi-quickstart-overview). ## 1. Set up your environment Set up your environment. For details, please refer to the [Importing Necessary Node.js Libraries](./nodejs-environment#1.-import-the-necessary-node.js-libraries). ## 2. Search for platform information and get investment product details ### 2.1 Search for summary information of investment products under a protocol Here is an example of a Node.js request. For interface information, refer to [here](defi-api-reference-explore-protocol-list). #### **Step 1: Define parameters** Next, define the parameters for querying the summary information of investment products. ```js const getProtocolListParam = { platformName: '', platformId: '' }; ``` #### **Step 2: Define helper function** Define a helper function to interact with the DeFi API. ```js const getProtocolListRequestUrl = (api, queryParams) => { const path = api + '?' + new URLSearchParams(queryParams).toString(); return { apiRequestUrl: exploreBaseUrl + path, path: exploreBasePath + path, }; }; const getProtocolListData = async () => { const { apiRequestUrl, path } = getProtocolListRequestUrl( '/protocol/list', getProtocolListParam ); return fetch(apiRequestUrl, { method: 'GET', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` #### **Step 3: Get the result** Get the result. If you need to navigate to the investment product details webpage, use the value of investmentPageUrlPattern in the result and fill in the placeholder with the corresponding investmentId value to form the URL. If you want to query the investment product details API, concatenate the value of investmentApiUrlPattern with the corresponding investmentId value to form the URL. ```js async function someFunction() { const { data: protocolListData } = await getProtocolListData(); console.log(JSON.stringify(protocolListData)); } someFunction(); ``` After sending the transaction, you will receive the following response: ```json { "code": 0, "msg": "", "data": [ { "platformId": 294, "platformName": "SpaceFi", "platformWebSite": "https://spacefi.io/", "investmentApiUrlPattern": "https://web3.okx.com/api/v5/defi/explore/product/detail?investmentId=", "investmentPageUrlPattern": "https://web3.okx.com/cn/web3/defi/detail/${investmentId}", "platformMinInfos": [ { "investmentId": "21010", "protocolId": "207", "network": "ZKSYNC", "chainId": "1" }, { "investmentId": "21011", "protocolId": "207", "network": "ZKSYNC", "chainId": "1" } ] } ] } ``` ### 2.2 Search for investment product details You can use the investmentApiUrlPattern and investmentId attributes obtained in the previous step to form the URL for investment product details. Refer to the interface information [here](defi-api-reference-explore-product-details). #### **Step 1: Define parameters** Define the parameters for querying the investment product details. ```js const getProductDetailParam = { investmentId: '21010', investmentCategory: '' }; ``` #### **Step 2: Define helper function** Define a helper function to interact with the DeFi API. ```js const getProductDetailRequestUrl = (api, queryParams) => { const path = api + '?' + new URLSearchParams(queryParams).toString(); return { apiRequestUrl: exploreBaseUrl + path, path: exploreBasePath + path, }; }; const getProductDetailData = async () => { const { apiRequestUrl, path } = getProductDetailRequestUrl( '/product/detail', getProductDetailParam ); return fetch(apiRequestUrl, { method: 'GET', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` #### **Step 3: Get the result** ```js async function someFunction() { const { data: productDetailData } = await getProductDetailData(); console.log(JSON.stringify(productDetailData)); } someFunction(); ``` After sending the transaction, you will receive the following response: ```json { "code": 0, "msg": "", "data": { "investmentId": "21010", "investmentName": "USDC-ETH", "chainId": "324", "rate": "0.06340", "investType": "2", "platformName": "SpaceFi", "platformId": "491", "analysisPlatformId": "294", "poolVersion": "1", "rateType": "1", "tvl": "4464444.45647", "underlyingToken": [ { "tokenSymbol": "USDC", "tokenAddress": "0x3355df6d4c9c3035724fd0e3914de96a5a83aaf4", "isBaseToken": false }, { "tokenSymbol": "ERA_ETH", "tokenAddress": "0x0000000000000000000000000000000000000000", "isBaseToken": true } ], "isInvestable": true, "earnedToken": [ { "tokenSymbol": "USDC", "tokenAddress": "0x3355df6d4c9c3035724fd0e3914de96a5a83aaf4", "isBaseToken": false }, { "tokenSymbol": "ERA_ETH", "tokenAddress": "0x0000000000000000000000000000000000000000", "isBaseToken": true } ], "lpToken": [ { "tokenSymbol": "SLP", "tokenAddress": "0xd0ce094412898760c2a5e37abec39b0e785b45ae", "isBaseToken": false } ], "subscriptionMethod": "2", "redeemMethod": "2" } } ``` ## 3. Query investment estimated earnings calculation Retrieve valid data for an investment product. You can input the desired investment amount to obtain the estimated investment earnings information. Refer to the interface details [here](defi-api-reference-calculation-query-info-for-investment). #### **Step 1: Define parameters** Next, define the parameters for calculating investment subscription earnings. ```js const getSubscribeInfoBody = { inputAmount: "1", inputTokenAddress: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", investmentId: "21200", address: "0x7f****da", investmentType: "0", tokenDecimal: "18", isSingle: false }; ``` #### **Step 2: Define helper function** Define a helper function to interact with the DeFi API. ```js const getSubscribeInfoData = async () => { return fetch(calculatorBaseUrl + '/subscribe-info', { method: 'POST', headers: headersParams, body: JSON.stringify(getSubscribeInfoBody), }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` #### **Step 3: Get the result** ```js async function someFunction() { const { data: subscribeInfoData } = await getSubscribeInfoData(); console.log(subscribeInfoData); } someFunction(); ``` After sending the transaction, you will receive the following response: ```json { "code": 0, "msg": "", "data": { "investWithTokenList": [ { "tokenSymbol": "CORE", "tokenName": "Core", "tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "network": "CORE", "chainId": "1116", "tokenPrecision": "18", "isBaseToken": true, "coinAmount": "1", "currencyAmount": "0.4918" } ], "gainsTokenList": [ { "tokenSymbol": "CORE", "tokenName": "Core", "tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "network": "CORE", "tokenPrecision": "18", "coinAmount": "0.00069321843585011", "dataType": "0" } ], "approveStatusList": [ { "tokenSymbol": "CORE", "tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "network": "CORE", "chainId": "1116", "tokenPrecision": "18", "isNeedApprove": false, "approveAddress": "0x0000000000000000000000000000000000001007", "orderType": "3" } ], "isSwapInvest": false, "estimateGasFee": "99343", "isAllowSubscribe": true, "validatorName": "OKXEarn" } } ``` ## 4. Generate call data for subscription transaction The subscription process consists of the following steps: ### 4.1 Subscription authorization Here is an example of a Node.js request. Refer to the interface details [here](defi-api-reference-transaction-calldata-for-authorization). #### **Step 1: Define parameters** Define the parameters for authorizing the subscription amount. ```js const userInputList = [ { "chainId": "56", "coinAmount": "10", "tokenAddress": "0x526a913a7a4518aa2abc3dcd3c46a9c73f40f94a" } ]; const getTransactionAuthorizationBody = { address: '0x7f****da', type: '3', investmentId: '6925', userInputList: userInputList }; ``` #### **Step 2: Define helper function** Define a helper function to interact with the DeFi API. ```js const getTransactionAuthorizationData = async () => { return fetch(transactionBaseUrl + '/authorization', { method: 'POST', headers: headersParams, body: JSON.stringify(getTransactionAuthorizationBody), }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` #### **Step 3: Get the result** ```js async function someFunction() { const { data: transactionAuthorizationData } = await getTransactionAuthorizationData(); console.log(transactionAuthorizationData); } someFunction(); ``` After sending the transaction, you will receive the following response: ```json { "code": 0, "msg": "", "data": { "dataList": [ { "from": "0x7f4****da", "to": "0x52****4a", "value": "0x0", "serializedData": "0x095ea7b30000000000000000000000002c34a2fb1d0b4f55de51e1d0bdefaddce6b7cdd60000000000000000000000000000000000000000000000008ac7230489e80000", "originalData": "{\"methodDefine\":\"approve(address,uint256)\",\"methodId\":\"0x095ea7b3\",\"methodType\":\"METHOD_ID\",\"params\":{\"params\":[\"0x2c34a2fb1d0b4f55de51e1d0bdefaddce6b7cdd6\",\"10000000000000000000\"]},\"useAdapter\":false}", "signatureData": "1bca0efbd1c809de94cdd8c924329c7ac79a4d346742de61925e8494f2c84c446bd3cf42b56d690c85ff513beadf46cd18f4e3e74845a92c48451584615f749d1c" } ] } } ``` ### 4.2 Subscription transaction Here is an example of a Node.js request. For detailed information about the API, refer to [here](defi-api-reference-transaction-calldata-for-subscription). #### **Step 1: Define parameters** Define the parameters for querying subscription investments. ```js const userInputList = [ { "coinAmount": "0.6" } ]; const expectOutputList = [ { "coinAmount": "0.6" } ]; const getTransactionSubscriptionBody = { address: '0x7f****da', investmentId: '6925', userInputList: userInputList, expectOutputList: expectOutputList }; ``` #### **Step 2: Define helper function** Define a helper function to interact with the DeFi API. ```js const getTransactionSubscriptionData = async () => { return fetch(transactionBaseUrl+'/subscription', { method: 'post', headers: headersParams, body: JSON.stringify(getTransactionSubscriptionBody), }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` #### **Step 3: Get the result** ```js async function someFunction() { const { data: transactionSubscriptionData } = await getTransactionSubscriptionData(); console.log(transactionSubscriptionData); } someFunction(); ``` After sending the transaction, you will receive the following response: ```json { "code": 0, "msg": "", "data": { "dataList": [ { "from": "0x7f****da", "to": "0x72****d2", "value": "0x0", "serializedData": "0x016cba5f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000526a913a7a4518aa2abc3dcd3c46a9c73f40f94a0000000000000000000000000000000000000000000000000853a0d2313c00000000000000000000000000005569e13b1ec4336d17e8f24d892a4a915fc5da9400000000000000000000000000000000000000000000000000000000000000010000000000000000000000004e38a4ad4f210ad5abb2c8f2598706ae8b4a1ce600000000000000000000000000000000000000000000000006f05b59d3b20000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000005569e13b1ec4336d17e8f24d892a4a915fc5da94000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e4c41a3be800000000000000000000000000000000000000000000000000000000000000000000000000000000000000004e38a4ad4f210ad5abb2c8f2598706ae8b4a1ce60000000000000000000000007f429edeff8afc7bb3a2cf7db832fc86f6fa99da00000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000026f700000000000000000000000000000000000000000000000000000000", "originalDataClass": "OriginalDataEntrance", "originalData": "{\"hexCallData\":\"0x016cba5f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000526a913a7a4518aa2abc3dcd3c46a9c73f40f94a0000000000000000000000000000000000000000000000000853a0d2313c00000000000000000000000000005569e13b1ec4336d17e8f24d892a4a915fc5da9400000000000000000000000000000000000000000000000000000000000000010000000000000000000000004e38a4ad4f210ad5abb2c8f2598706ae8b4a1ce600000000000000000000000000000000000000000000000006f05b59d3b20000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000005569e13b1ec4336d17e8f24d892a4a915fc5da94000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e4c41a3be800000000000000000000000000000000000000000000000000000000000000000000000000000000000000004e38a4ad4f210ad5abb2c8f2598706ae8b4a1ce60000000000000000000000007f429edeff8afc7bb3a2cf7db832fc86f6fa99da00000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000026f700000000000000000000000000000000000000000000000000000000\",\"methodDefine\":\"{\\n\\t\\\"inputs\\\": [{\\n\\t\\t\\\"components\\\": [{\\n\\t\\t\\t\\\"internalType\\\": \\\"struct TokenInInfo\\\",\\n\\t\\t\\t\\\"name\\\": \\\"tokenIn\\\",\\n\\t\\t\\t\\\"type\\\": \\\"tuple[]\\\",\\n\\t\\t\\t\\\"components\\\": [{\\n\\t\\t\\t\\t\\\"internalType\\\": \\\"address\\\",\\n\\t\\t\\t\\t\\\"name\\\": \\\"token\\\",\\n\\t\\t\\t\\t\\\"type\\\": \\\"address\\\"\\n\\t\\t\\t}, {\\n\\t\\t\\t\\t\\\"internalType\\\": \\\"uint256\\\",\\n\\t\\t\\t\\t\\\"name\\\": \\\"amount\\\",\\n\\t\\t\\t\\t\\\"type\\\": \\\"uint256\\\"\\n\\t\\t\\t}, {\\n\\t\\t\\t\\t\\\"internalType\\\": \\\"address\\\",\\n\\t\\t\\t\\t\\\"name\\\": \\\"to\\\",\\n\\t\\t\\t\\t\\\"type\\\": \\\"address\\\"\\n\\t\\t\\t}]\\n\\t\\t}, {\\n\\t\\t\\t\\\"internalType\\\": \\\"struct TokenAmount\\\",\\n\\t\\t\\t\\\"name\\\": \\\"tokenOut\\\",\\n\\t\\t\\t\\\"type\\\": \\\"tuple[]\\\",\\n\\t\\t\\t\\\"components\\\": [{\\n\\t\\t\\t\\t\\\"internalType\\\": \\\"address\\\",\\n\\t\\t\\t\\t\\\"name\\\": \\\"token\\\",\\n\\t\\t\\t\\t\\\"type\\\": \\\"address\\\"\\n\\t\\t\\t}, {\\n\\t\\t\\t\\t\\\"internalType\\\": \\\"uint256\\\",\\n\\t\\t\\t\\t\\\"name\\\": \\\"amount\\\",\\n\\t\\t\\t\\t\\\"type\\\": \\\"uint256\\\"\\n\\t\\t\\t}]\\n\\t\\t}],\\n\\t\\t\\\"internalType\\\": \\\"struct BaseRequest\\\",\\n\\t\\t\\\"name\\\": \\\"request\\\",\\n\\t\\t\\\"type\\\": \\\"tuple\\\"\\n\\t}, {\\n\\t\\t\\\"components\\\": [{\\n\\t\\t\\t\\\"internalType\\\": \\\"address\\\",\\n\\t\\t\\t\\\"name\\\": \\\"target\\\",\\n\\t\\t\\t\\\"type\\\": \\\"address\\\"\\n\\t\\t}, {\\n\\t\\t\\t\\\"internalType\\\": \\\"bytes\\\",\\n\\t\\t\\t\\\"name\\\": \\\"callData\\\",\\n\\t\\t\\t\\\"type\\\": \\\"bytes\\\"\\n\\t\\t}],\\n\\t\\t\\\"internalType\\\": \\\"struct Call\\\",\\n\\t\\t\\\"name\\\": \\\"calls\\\",\\n\\t\\t\\\"type\\\": \\\"tuple[]\\\"\\n\\t}],\\n\\t\\\"name\\\": \\\"execute\\\",\\n\\t\\\"stateMutability\\\": \\\"payable\\\",\\n\\t\\\"type\\\": \\\"function\\\"\\n}\",\"methodId\":\"\",\"methodType\":\"ABI\",\"params\":{\"baseRequest\":{\"tokenIn\":[{\"amount\":600000000000000000,\"to\":\"0x5569e13b1ec4336d17e8f24d892a4a915fc5da94\",\"token\":\"0x526a913a7a4518aa2abc3dcd3c46a9c73f40f94a\"}],\"tokenOut\":[{\"amount\":500000000000000000,\"token\":\"0x4e38a4ad4f210ad5abb2c8f2598706ae8b4a1ce6\"}]},\"operatorDataList\":[{\"adapterOperate\":true,\"call\":{\"calls\":\"xBo76AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATjikrU8hCtWrssjyWYcGrotKHOYAAAAAAAAAAAAAAAB/Qp7e/4r8e7Oiz324MvyG9vqZ2gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwW1nTsgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACb3\",\"callsAsString\":\"0xc41a3be800000000000000000000000000000000000000000000000000000000000000000000000000000000000000004e38a4ad4f210ad5abb2c8f2598706ae8b4a1ce60000000000000000000000007f429edeff8afc7bb3a2cf7db832fc86f6fa99da00000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000026f7\",\"target\":\"0x5569e13b1ec4336d17e8f24d892a4a915fc5da94\"},\"hexCallData\":\"0xc41a3be800000000000000000000000000000000000000000000000000000000000000000000000000000000000000004e38a4ad4f210ad5abb2c8f2598706ae8b4a1ce60000000000000000000000007f429edeff8afc7bb3a2cf7db832fc86f6fa99da00000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000026f7\",\"operateType\":\"DEPOSIT\",\"operatorMethodInfo\":{\"methodDefine\":\"{\\n\\t\\\"inputs\\\": [{\\n\\t\\t\\\"internalType\\\": \\\"address\\\",\\n\\t\\t\\\"name\\\": \\\"pool\\\",\\n\\t\\t\\\"type\\\": \\\"address\\\"\\n\\t}, {\\n\\t\\t\\\"internalType\\\": \\\"struct TokenOutInfo\\\",\\n\\t\\t\\\"name\\\": \\\"tokenOut\\\",\\n\\t\\t\\\"type\\\": \\\"tuple\\\",\\n\\t\\t\\\"components\\\": [{\\n\\t\\t\\t\\t\\\"internalType\\\": \\\"address\\\",\\n\\t\\t\\t\\t\\\"name\\\": \\\"token\\\",\\n\\t\\t\\t\\t\\\"type\\\": \\\"address\\\"\\n\\t\\t\\t}, {\\n\\t\\t\\t\\t\\\"internalType\\\": \\\"address\\\",\\n\\t\\t\\t\\t\\\"name\\\": \\\"toAddress\\\",\\n\\t\\t\\t\\t\\\"type\\\": \\\"address\\\"\\n\\t\\t\\t},\\n\\t\\t\\t{\\n\\t\\t\\t\\t\\\"internalType\\\": \\\"uint256\\\",\\n\\t\\t\\t\\t\\\"name\\\": \\\"minAmount\\\",\\n\\t\\t\\t\\t\\\"type\\\": \\\"uint256\\\"\\n\\t\\t\\t}\\n\\t\\t]\\n\\t}, {\\n\\t\\t\\\"internalType\\\": \\\"bytes\\\",\\n\\t\\t\\\"name\\\": \\\"data\\\",\\n\\t\\t\\\"type\\\": \\\"bytes\\\"\\n\\n\\t}],\\n\\t\\\"name\\\": \\\"deposit\\\",\\n\\t\\\"stateMutability\\\": \\\"payable\\\",\\n\\t\\\"type\\\": \\\"function\\\"\\n}\",\"params\":{\"data\":\"00000000000000000000000000000000000000000000000000000000000026f7\",\"pool\":\"0x0000000000000000000000000000000000000000\",\"tokenOut\":{\"amount\":500000000000000000,\"toAddress\":\"0x7f429edeff8afc7bb3a2cf7db832fc86f6fa99da\",\"token\":\"0x4e38a4ad4f210ad5abb2c8f2598706ae8b4a1ce6\"}}},\"target\":\"0x5569e13b1ec4336d17e8f24d892a4a915fc5da94\"}]},\"useAdapter\":true}", "signatureData": "dbfe682a491b31141c99800913c9a052ee8dee122854cb0c459af85fff9f5d571aaf217b3bbbe10b141247bc0327357c3dde2874333f8a4c031d84d31a41ffec1c" } ] } } ``` ## 5. Signature and broadcasting During the signing process, you can directly use the serializedData obtained in step 3 as call data, or you can let users assemble callData using originalData for signing and broadcasting. For EVM-based investments, you can refer to the signature [example](./walletapi-quickstart-multi-chain#第三步:构建并发送交易). - [Redemption process](https://web3.okx.com/onchainos/docs/waas/defi-quickstart-redemption-flow.md) # Redemption process For the redemption process, refer to the redemption process section in the [overview](defi-quickstart-overview). ## 1. Set up your environment Set up your environment. For details, please refer to the [Importing Necessary Node.js Libraries](./nodejs-environment#1.-import-the-necessary-node.js-libraries. ## 2. Search for user positions [Here](defi-api-reference-personal-query-position) is an example of a Node.js request. Refer to the API reference for detailed information. #### **Step 1: Define parameters** Next, define the parameters for querying user positions. ```js const domain = 'https://web3.okx.com'; const exploreBasePath = '/api/v5/defi/explore'; const transactionBasePath = '/api/v5/defi/transaction'; const userBasePath = '/api/v5/defi/user'; const calculatorBasePath = '/api/v5/defi/calculator'; const exploreBaseUrl = domain + exploreBasePath; // Explore API base url const transactionBaseUrl = domain + transactionBasePath; // Transaction API base url const userBaseUrl = domain + userBasePath; // User API base url const calculatorBaseUrl = domain + calculatorBasePath; // Calculator API base url const getUserAssetBody = { "address":"0x7f****da", "investmentId":"15299", "chainId":"137" }; ``` #### **Step 2: Define helper function** Define a helper function to interact with the DeFi API. ```js const getUserAssetData = async () => { return fetch(calculatorBaseUrl + '/asset-detail', { method: 'POST', headers: headersParams, body: JSON.stringify(getUserAssetBody), }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` #### **Step 3: Get the result** ```js async function someFunction() { const { data: userAssetData } = await getUserAssetData(); console.log(userAssetData); } someFunction(); ``` After sending the transaction, you will receive the following response: ```json { "code": 0, "msg": "", "data": [ { "investmentName": "MATIC earn MATIC", "investmentId": "15299", "investType": "5", "investName": "Stake", "assetsTokenList": [ { "tokenSymbol": "MATIC", "tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "network": "MATIC", "tokenPrecision": "18", "coinAmount": "0E-18", "currencyAmount": "0" } ], "rewardDefiTokenInfo": [ { "baseDefiTokenInfos": [ { "tokenSymbol": "MATIC", "tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "network": "MATIC", "tokenPrecision": "18", "coinAmount": "10.907755587159277921", "currencyAmount": "8.3804286176144732267043", "buttonType": "3" } ], "buttonType": "0", "claimMode": "1", "rewardType": "1" } ], "totalValue": "8.3804286176144732267043" } ] } ``` ## 3. Search platform information and get investment product details Here is an example of a Node.js request. For detailed information about the API, please refer to [here](defi-api-reference-explore-product-details). #### **Step 1: Define parameters** Next, define the parameters for querying investment product details. ```js const getProductDetailParam = { investmentId: '21010', investmentCategory: '' }; ``` #### **Step 2: Define helper function** Define a helper function to interact with the DeFi API. ```js const getProductDetailRequestUrl = (api, queryParams) => { const path = api + '?' + new URLSearchParams(queryParams).toString(); return { apiRequestUrl: exploreBaseUrl + path, path: exploreBasePath + path, }; }; const getProductDetailData = async () => { const { apiRequestUrl, path } = getProductDetailRequestUrl( '/product/detail', getProductDetailParam ); return fetch(apiRequestUrl, { method: 'GET', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` #### **Step 3: Get the result** ```js async function someFunction() { const { data: productDetailData } = await getProductDetailData(); console.log(productDetailData); } someFunction(); ``` After sending the transaction, you will receive the following response: ```json { "code": 0, "msg": "", "data": { "investmentId": "21010", "investmentName": "USDC-ETH", "chainId": "324", "rate": "0.06340", "investType": "2", "platformName": "SpaceFi", "platformId": "491", "analysisPlatformId": "294", "poolVersion": "1", "rateType": "1", "tvl": "4464444.45647", "underlyingToken": [ { "tokenSymbol": "USDC", "tokenAddress": "0x3355df6d4c9c3035724fd0e3914de96a5a83aaf4", "isBaseToken": false }, { "tokenSymbol": "ERA_ETH", "tokenAddress": "0x0000000000000000000000000000000000000000", "isBaseToken": true } ], "isInvestable": true, "earnedToken": [ { "tokenSymbol": "USDC", "tokenAddress": "0x3355df6d4c9c3035724fd0e3914de96a5a83aaf4", "isBaseToken": false }, { "tokenSymbol": "ERA_ETH", "tokenAddress": "0x0000000000000000000000000000000000000000", "isBaseToken": true } ], "lpToken": [ { "tokenSymbol": "SLP", "tokenAddress": "0xd0ce094412898760c2a5e37abec39b0e785b45ae", "isBaseToken": false } ], "subscriptionMethod": "2", "redeemMethod": "2" } } ``` ## 4. Redemption estimate calculation You can obtain an estimated redemption information based on the input redemption amount. Here is an example of a Node.js request. For detailed information about the API, please refer to [here](defi-api-reference-calculation-query-info-for-redemption). #### **Step 1: Define parameters** Next, define the parameters for calculating the estimated redemption information. ```js const getRedeemInfoBody = { address: "0x7f****da", inputTokenAmount: "1.000000146425127036", investmentCategory: "0", investmentId: "21033", isSingle: false, outputTokenAddress: "0x6b175474e89094c44da98b954eedeac495271d0f", outputTokenDecimal: "18", slippage: "" }; ``` #### **Step 2: Define helper function** Define a helper function to interact with the DeFi API. ```js const getRedeemInfoData = async () => { return fetch(calculatorBaseUrl + '/redeem-info', { method: 'POST', headers: headersParams, body: JSON.stringify(getRedeemInfoBody), }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` #### **Step 3: Get the result** ```js async function someFunction() { const { data: redeemInfoData } = await getRedeemInfoData(); console.log(redeemInfoData); } someFunction(); ``` After sending the transaction, you will receive the following response: ```json { "code": 0, "msg": "", "data": { "investWithTokenList": [ { "tokenSymbol": "CORE", "tokenName": "Core", "tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "network": "CORE", "chainId": "1116", "tokenPrecision": "18", "isBaseToken": true, "coinAmount": "1", "currencyAmount": "0.4918" } ], "gainsTokenList": [ { "tokenSymbol": "CORE", "tokenName": "Core", "tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "network": "CORE", "tokenPrecision": "18", "coinAmount": "0.00069321843585011", "dataType": "0" } ], "approveStatusList": [ { "tokenSymbol": "CORE", "tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "network": "CORE", "chainId": "1116", "tokenPrecision": "18", "isNeedApprove": false, "approveAddress": "0x0000000000000000000000000000000000001007", "orderType": "3" } ], "isSwapInvest": false, "estimateGasFee": "99343", "isAllowSubscribe": true, "validatorName": "OKXEarn" } } ``` ## 5. Generate invocation data for redemption transaction The subscription process for redemption involves the following steps: ### 5.1 Redemption authorization Here is an example of a Node.js request. For detailed information about the API, please refer to [here](defi-api-reference-transaction-calldata-for-authorization). #### **Step 1: Define parameters** Next, define the parameters for calculating the investment redemption authorization amount. ```js const userInputList = [ { "chainId": "56", "coinAmount": "10", "tokenAddress": "0x526a913a7a4518aa2abc3dcd3c46a9c73f40f94a" } ]; const getTransactionAuthorizationBody = { address: '0x7f****da', type: '4', investmentId: '6925', userInputList: userInputList }; ``` #### **Step 2: Define helper function** Define a helper function to interact with the DeFi API. ```js const getTransactionAuthorizationData = async () => { return fetch(transactionBaseUrl + '/authorization', { method: 'POST', headers: headersParams, body: JSON.stringify(getTransactionAuthorizationBody), }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` #### **Step 3: Get the result** ```js async function someFunction() { const { data: transactionAuthorizationData } = await getTransactionAuthorizationData(); console.log(transactionAuthorizationData); } someFunction(); ``` After sending the transaction, you will receive the following response: ```json { "code": 0, "msg": "", "data": { "dataList": [ { "from": "0x7f****da", "to": "0x52****4a", "value": "0x0", "serializedData": "0x095ea7b30000000000000000000000002c34a2fb1d0b4f55de51e1d0bdefaddce6b7cdd60000000000000000000000000000000000000000000000008ac7230489e80000", "originalData": "{\"methodDefine\":\"approve(address,uint256)\",\"methodId\":\"0x095ea7b3\",\"methodType\":\"METHOD_ID\",\"params\":{\"params\":[\"0x2c34a2fb1d0b4f55de51e1d0bdefaddce6b7cdd6\",\"10000000000000000000\"]},\"useAdapter\":false}", "signatureData": "1bca0efbd1c809de94cdd8c924329c7ac79a4d346742de61925e8494f2c84c446bd3cf42b56d690c85ff513beadf46cd18f4e3e74845a92c48451584615f749d1c" } ] } } ``` ### 5.2 Redemption transaction Here is an example of a Node.js request. For detailed information about the API, please refer to [here](defi-api-reference-transaction-calldata-for-redemption). #### **Step 1: Define parameters** Next, define the parameters for querying the investment product for redemption. ```js const userInputList = [ { "coinAmount": "0.6" } ]; const getTransactionRedemptionBody = { address: '0x7f****da', investmentId: '6925', userInputList: userInputList, extra: "{\"redeemAll\":1}" }; ``` #### **Step 2: Define helper function** Define a helper function to interact with the DeFi API. ```js const getTransactionRedemptionData = async () => { return fetch(transactionBaseUrl+'/redemption', { method: 'POST', headers: headersParams, body: JSON.stringify(getTransactionRedemptionBody), }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` #### **Step 3: Get the result** ```js async function someFunction() { const { data: transactionRedemptionData } = await getTransactionRedemptionData(); console.log(transactionRedemptionData); } someFunction(); ``` After sending the transaction, you will receive the following response: ```json { "code": 0, "msg": "", "data": { "dataList": [ { "callDataType": "WITHDRAW", "from": "0x7f****da", "to": "0x83****ea", "value": "0x0", "serializedData": "0xba08765200000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f429edeff8afc7bb3a2cf7db832fc86f6fa99da0000000000000000000000007f429edeff8afc7bb3a2cf7db832fc86f6fa99da", "originalData": "{\"callDataType\":\"WITHDRAW\",\"methodDefine\":\"redeem(uint256,address,address)\",\"methodId\":\"0xba087652\",\"methodType\":\"METHOD_ID\",\"params\":{\"params\":[\"0\",\"0x7f429edeff8afc7bb3a2cf7db832fc86f6fa99da\",\"0x7f429edeff8afc7bb3a2cf7db832fc86f6fa99da\"]},\"useAdapter\":false}", "signatureData": "e6beeb6f9df6ecb7eb7791e57226f9eca1d7c3efa869172bb5021b9c827ad21b46e3dc4566608af727555e0a47aa90cf261331f4e1691b0201aa0b8a00ea685b1b" } ] } } ``` ## 6. Signing and broadcasting During the signing process, you can directly use the serializedData obtained in step 3 as callData, or you can assemble your own callData using the originalData and sign and broadcast it. For EVM-based investment products, you can refer to the signature [example](./walletapi-quickstart-multi-chain#第三步:构建并发送交易). - [Reward claiming process](https://web3.okx.com/onchainos/docs/waas/defi-quickstart-bonus-flow.md) # Reward claiming process For the reward claiming process, please refer to the reward claiming process section in the [overview](defi-quickstart-overview). ## 1. Set up your environment Set up your environment. For details, please refer to the [Importing Necessary Node.js Libraries](./nodejs-environment#1.-import-the-necessary-node.js-libraries). ## 2. Search user positions [Here](defi-api-reference-personal-query-position) is an example of a Node.js request. #### **Step 1: Define parameters** Next, define the request parameters to retrieve user positions. ```js const domain = 'https://web3.okx.com'; const exploreBasePath = '/api/v5/defi/explore'; const transactionBasePath = '/api/v5/defi/transaction'; const userBasePath = '/api/v5/defi/user'; const calculatorBasePath = '/api/v5/defi/calculator'; const exploreBaseUrl = domain + exploreBasePath; // Explore API base url const transactionBaseUrl = domain + transactionBasePath; // Transaction API base url const userBaseUrl = domain + userBasePath; // User API base url const calculatorBaseUrl = domain + calculatorBasePath; // Calculator API base url const getUserAssetBody = { "address":"0x7f****da", "investmentId":"15299", "chainId":"137" }; ``` #### **Step 2: Define helper function** Define a helper function to interact with the DeFi API. ```js const getUserAssetData = async () => { return fetch(calculatorBaseUrl + '/asset-detail', { method: 'POST', headers: headersParams, body: JSON.stringify(getUserAssetBody), }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` #### **Step 3: Get the result** ```js async function someFunction() { const { data: userAssetData } = await getUserAssetData(); console.log(userAssetData); } someFunction(); ``` After sending the request, you will receive the following response: ```json { "code": 0, "msg": "", "data": [ { "investmentName": "MATIC earn MATIC", "investmentId": "15299", "investType": "5", "investName": "Stake", "assetsTokenList": [ { "tokenSymbol": "MATIC", "tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "network": "MATIC", "tokenPrecision": "18", "coinAmount": "0E-18", "currencyAmount": "0" } ], "rewardDefiTokenInfo": [ { "baseDefiTokenInfos": [ { "tokenSymbol": "MATIC", "tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "network": "MATIC", "tokenPrecision": "18", "coinAmount": "10.907755587159277921", "currencyAmount": "8.3804286176144732267043", "buttonType": "3" } ], "buttonType": "0", "claimMode": "1", "rewardType": "1" } ], "totalValue": "8.3804286176144732267043" } ] } ``` ## 3. Search platform information and retrieve investment product details [Here](defi-api-reference-explore-product-details) is an example of a Node.js request. #### **Step 1: Define parameters** Define the parameters to query investment product details. ```js const getProductDetailParam = { investmentId: '21010', investmentCategory: '' }; ``` #### **Step 2: Define helper function** Define a helper function to interact with the DeFi API. ```js const getProductDetailRequestUrl = (api, queryParams) => { const path = api + '?' + new URLSearchParams(queryParams).toString(); return { apiRequestUrl: exploreBaseUrl + path, path: exploreBasePath + path, }; }; const getProductDetailData = async () => { const { apiRequestUrl, path } = getProductDetailRequestUrl( '/product/detail', getProductDetailParam ); return fetch(apiRequestUrl, { method: 'GET', headers: headersParams, }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` #### **Step 3: Get the result** ```js async function someFunction() { const { data: productDetailData } = await getProductDetailData(); console.log(productDetailData); } someFunction(); ``` After sending the request, you will receive the following response: ```json { "code": 0, "msg": "", "data": { "investmentId": "21010", "investmentName": "USDC-ETH", "chainId": "324", "rate": "0.06340", "investType": "2", "platformName": "SpaceFi", "platformId": "491", "analysisPlatformId": "294", "poolVersion": "1", "rateType": "1", "tvl": "4464444.45647", "underlyingToken": [ { "tokenSymbol": "USDC", "tokenAddress": "0x3355df6d4c9c3035724fd0e3914de96a5a83aaf4", "isBaseToken": false }, { "tokenSymbol": "ERA_ETH", "tokenAddress": "0x0000000000000000000000000000000000000000", "isBaseToken": true } ], "isInvestable": true, "earnedToken": [ { "tokenSymbol": "USDC", "tokenAddress": "0x3355df6d4c9c3035724fd0e3914de96a5a83aaf4", "isBaseToken": false }, { "tokenSymbol": "ERA_ETH", "tokenAddress": "0x0000000000000000000000000000000000000000", "isBaseToken": true } ], "lpToken": [ { "tokenSymbol": "SLP", "tokenAddress": "0xd0ce094412898760c2a5e37abec39b0e785b45ae", "isBaseToken": false } ], "subscriptionMethod": "2", "redeemMethod": "2" } } ``` ## 4. Generating invocation data for claiming bonus rewards [Here](defi-api-reference-transaction-calldata-for-bonus) is an example of a Node.js request for generating invocation data. For detailed information about the API, refer to the documentation. #### **Step 1: Define parameters** Define the parameters required for claiming bonus rewards. ```js const expectOutputList = [ { "chainId": "56", "coinAmount": "10", "tokenAddress": "0x526a913a7a4518aa2abc3dcd3c46a9c73f40f94a" } ]; const getTransactionBonusBody = { address: "0x7f****da", expectOutputList: expectOutputList, investmentId: "21670", extra: "{\"callDataExtJson\":\"\",\"redeemCalldataExtInfo\":[],\"rewardAddress\":\"\"}" }; ``` #### **Step 2: Define helper function** Define a helper function for interacting with the DeFi API. ```js const getTransactionBonusData = async () => { return fetch(transactionBaseUrl + '/bonus', { method: 'POST', headers: headersParams, body: JSON.stringify(getTransactionBonusBody), }) .then((res) => res.json()) .then((res) => { return res; }); }; ``` #### **Step 3: Get the result** ```js async function someFunction() { const { data: transactionBonusData } = await getTransactionBonusData(); console.log(transactionBonusData); } someFunction(); ``` After sending the transaction, you will receive the following response: ```json { "code": 0, "msg": "", "data": { "dataList": [ { "callDataType": "CLAIM", "from": "0x7f****da", "to": "0xed****bd", "value": "0x3fdc04eea0dcf6", "serializedData": "0x9e4bdf3a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000", "originalData": "{\"callDataType\":\"CLAIM\",\"methodDefine\":\"getReward(address, bytes)\",\"methodId\":\"0x9e4bdf3a\",\"methodType\":\"METHOD_ID\",\"params\":{\"params\":[\"0x0000000000000000000000000000000000000000\",\"org.web3j.abi.datatypes.DynamicBytes@59dc08a\"]},\"useAdapter\":false}", "signatureData": "b19f75a8c211c752ff5c82aa130eccee229d16dd05d56874c7a9fd876c5d6d61500dc326ff0aa65b747bca2a2b5cd111e93b53deda73491d8eca97acf8cceb521c" } ] } } ``` ## 5. Signing and broadcasting When signing, you can directly use the serializedData obtained in step 3 as callData. Alternatively, users can manually assemble callData using originalData for signing and broadcasting. For an example of signing EVM-based investment products, you can refer to the signature [example](./walletapi-quickstart-multi-chain#第三步:构建并发送交易). - [API reference](https://web3.okx.com/onchainos/docs/waas/defi-api-reference.md) # API reference - [Introduction](https://web3.okx.com/onchainos/docs/waas/defi-api-reference-introduction.md) # Introduction Welcome to the OKX Web3 DeFi API developer guide. Our API provides a range of data interface services specifically designed for DeFi scenarios, aiming to provide developers with a user-friendly experience in creating projects. ## Supported networks chainId: A unique identifier custom-defined by OKX Web3 DeFi, which may differ from the chainId specified in EIP-155. realChainId: The chainId specified in EIP-155. |Blockchain network |chainId|realChainId|Support| |-------|-------------|-------------|--------| |Bitcoin Mainnet |0 ||Supported| |Ethereum Mainnet|1|1|Supported| |OP Mainnet|10|10|Supported| |BNB Smart Chain Mainnet|56||Supported| |OKT Chain|66|66|Supported| |Gnosis|100|100|Supported| |Polygon Mainnet|137|137|Supported| |Manta Pacific Mainnet|169|169|Supported| |opBNB Mainnet|204|204|Supported| |Fantom Opera|250|250|Supported| |zkSync Era Mainnet|324|324|Supported| |Polygon zkEVM|1101|1101|Supported| |Core Blockchain Mainnet|1116|1116|Supported| |Mantle|5000|5000|Supported| |Base|8453|8453|Supported| |Arbitrum One|42161|42161|Supported| |Avalanche C-Chain|43114|43114|Supported| |Tron|195||Coming soon| |Solana|501||Coming soon| |Sui|784||Coming soon| |Stacks|5757||Coming soon| |Scroll|534352|534352|Coming soon| - [Query information](https://web3.okx.com/onchainos/docs/waas/defi-api-reference-explore.md) # Query information - [Query protocol list](https://web3.okx.com/onchainos/docs/waas/defi-api-reference-explore-protocol-list.md) {/* api-page */} # Query protocol list Description: This API provides brief information about protocols and investment products for further details on investment products. If the parameters do not exist, it will list information about all protocols. ### Request URL GET **`https://web3.okx.com/api/v5/defi/explore/protocol/list`** ### Request parameters | Parameter name | Description | Location | Required | Data type | | -------------- | -------------------- | -------- | -------- | --------- | | platformId | Platform ID | Query | No | String | | platformName | Platform official name | Query | No | String | ### Response parameters | Parameter name | Description | Data type | | ------------------------ | --------------------------- | --------------- | | platformId | Platform ID | String | | platformName | Platform official name | String | | platformWebSite | Platform official website | String | | investmentApiUrlPattern | URL address for investment details (non-UI) | String | | investmentPageUrlPattern | URL address for investment details on OKX official website UI | String | | platformMinInfos | Platform information | Array[Struct] | | >investmentId | Investment product ID | String | | >protocolId | Protocol ID | String | | >network | Investment product network | String | | >chainId | Investment product chain ID | String | ### Request example ```shell curl --location 'https://web3.okx.com/api/v5/defi/explore/protocol/list' \ --header 'OK-ACCESS-KEY: 4b****53' \ --header 'OK-ACCESS-PASSPHRASE: p****d' ``` ### Response example ```json { "code": 0, "msg": "", "data": [ { "platformId": 149, "platformName": "MorphoCompound", "platformWebSite": "https://compound.morpho.xyz/?network=mainnet", "investmentApiUrlPattern": "", "investmentPageUrlPattern": "", "platformMinInfos": [ { "investmentId": "20926", "protocolId": "194", "network": "OP" }, { "investmentId": "20949", "protocolId": "195", "network": "OP" } ] }, { "platformId": 144, "platformName": "Compound V3", "platformWebSite": "https://app.compound.finance", "investmentUrlPattern": "", "platformMinInfos": [ { "investmentId": "8973", "protocolId": "75", "network": "OP" } ] } ] } ``` - [Query token list](https://web3.okx.com/onchainos/docs/waas/defi-api-reference-explore-token-list.md) {/* api-page */} # Query token list Description: This API provides information about specific tokens if the tokenAddress and chainId parameters are accurate. If the parameters do not exist, it will list information about all tokens. ### Request URL GET **`https://web3.okx.com/api/v5/defi/explore/token/list`** ### Request parameters | Parameter name | Description | Location | Required | Data type | | -------------- | ----------- | -------- | -------- | --------- | | tokenAddress | Token contract address | Query | No | String | | chainId | Token blockchain ID | Query | No | String | ### Response parameters | Parameter name | Description | Data type | | -------------- | --------------- | --------------- | | symbol | Platform ID | String | | tokenInfos | Token information | Array[Struct] | | >tokenId | Token ID | String | | >tokenSymbol | Token symbol | String | | >network | Token network name | String | | >logoUrl | Token logo URL | String | | >tokenAddress | Token contract address | String | ### Request example ```shell curl --location 'https://web3.okx.com/api/v5/defi/explore/token/list' \ --header 'OK-ACCESS-KEY: 24b****53' \ --header 'OK-ACCESS-PASSPHRASE: p****d' \ ``` ### Response example ```json { "code": 0, "msg": "", "data": [ { "symbol": "oSQTH", "tokenInfos": [ { "tokenId": "7042", "tokenSymbol": "oSQTH", "network": "ETH", "logoUrl": "https://static.coinall.ltd/cdn/wallet/logo/icon_unknow.png", "tokenAddress": "0xf1b99e3e573a1a9c5e6b2ce818b617f0e664e86b" } ] }, { "symbol": "DFI", "tokenInfos": [ { "tokenId": "3533", "tokenSymbol": "DFI", "network": "ETH", "logoUrl": "https://static.coinall.ltd/cdn/wallet/logo/icon_custom_default_D.png", "tokenAddress": "0x8fc8f8269ebca376d046ce292dc7eac40c8d358a" }, { "tokenId": "8645", "tokenSymbol": "DFI", "network": "BSC", "logoUrl": "https://static.coinall.ltd/cdn/wallet/logo/icon_custom_default_D.png", "tokenAddress": "0x361c60b7c2828fcab80988d00d1d542c83387b50" } ] } ] } ``` - [Query product list](https://web3.okx.com/onchainos/docs/waas/defi-api-reference-explore-product-list.md) {/* api-page */} # Query product list Description: This API allows you to query a paginated list of investment products based on specified criteria. ### Request URL POST **`https://web3.okx.com/api/v5/defi/explore/product/list`** ### Request parameters | Parameter | Description | Location | Required | Data type | | --- |----------------------------------------------------------| --- | --- | --- | | simplifyInvestType | Query investment product types (100: Stablecoin, 101: Single, 102: Multi, 103: Vaults) | Request body | Yes | String | | network | Query network name (refer to [here](defi-api-reference-explore-network-list)) | Request body | Yes | String | | poolVersion | Pool version (default to V2, distinguishing between V2 and V3) | Request body | No | String | | platformIds | Platform ID list (refer to [here](defi-api-reference-explore-protocol-list)) | Request body | No | Array[String] | | sort | Sorting criteria | Request body | No | Struct | | >orders | Order-based sorting criteria | Request body | No | Array[Struct] | | >>direction | Sorting direction: (ascending - ASC, descending - DESC) | Request body | No | String | | >>property | Property name for sorting results (sortable fields: Total Value Locked - TVL, APY Rate - RATE) | Request body | No | String | | tokenIds | Token ID list (refer to [here](defi-api-reference-explore-token-list)) | Request body | No | Array[String] | | offset | Paginated offset | Request body | No | String | | limit | Paginated limit | Request body | Yes | String | ### Response Parameters | Parameter | Description | Data type | | --- | --- | --- | | investmentId | Investment product ID | String | | investmentName | Investment product name | String | | chainId | Blockchain ID | String | | rate | Yield rate | String | | investType | Investment product type: 1. Saving; 2. Liquidity Pool; 3. Farming; 4. Vaults; 5. Staking | String | | platformName | Platform name | String | | platformId | Platform ID | String | | rateType | Yield rate calculation type: 0: APY; 1: APR | String | | tvl | Total Value Locked | String | | underlyingToken | Underlying token for staking | Struct | | >isBaseToken | Whether the underlying token is the base token of the network | Boolean | | >tokenContract | Smart contract address of the underlying token | String | | >tokenSymbol | Symbol of the underlying token | String | | total | Total count based on the query criteria | String | ### Request example ```shell curl --location 'https://web3.okx.com/api/v5/defi/explore/product/list' \ --header 'OK-ACCESS-KEY: 4b****53' \ --header 'OK-ACCESS-PASSPHRASE: p****d' \ --header 'Content-Type: application/json' \ --data '{ "network":"ETH", "offset":"0", "limit":"10", "sort": { "orders":[ { "direction":"DESC", "property":"TVL" } ] }, "platformIds": ["89"] }' ``` ### Response example ```json { "code": 0, "msg": "", "data": { "investments": [ { "investmentId": "21033", "investmentName": "DAI", "chainId": "1", "rate": "0.04879", "investType": "4", "platformName": "MakerDAO", "platformId": "89", "poolVersion": "1", "rateType": "0", "tvl": "1211124903.92264", "underlyingToken": [ { "tokenSymbol": "DAI", "tokenAddress": "0x6b175474e89094c44da98b954eedeac495271d0f", "isBaseToken": false } ] } ], "total": "1" } } ``` - [Query product details](https://web3.okx.com/onchainos/docs/waas/defi-api-reference-explore-product-details.md) {/* api-page */} # Query product details Description: This API provides the details of a specified investment product when you input the search criteria. ### Request URL GET **`https://web3.okx.com/api/v5/defi/explore/product/detail`** ### Request parameters | Parameter name | Description | Parameter type | Required | Data type | | --- | --- | --- | --- | --- | | investmentId | Investment ID | Query parameter | Yes | String | | investmentCategory | Subscription type: (e.g., 0: Default type; 1: BRC-20) | Query parameter | No | String | ### Response parameters | Parameter name | Description | Data type | | --- | --- | --- | | investmentId | Investment ID | String | | investmentName | Investment name | String | | chainId | Blockchain ID | String | | rate | Rate of return | String | | investType | Investment type: 1. Save; 2. Pool; 3. Farm; 4. Vaults; 5. Stake | String | | platformName | Platform name | String | | platformId | Platform ID | String | | analysisPlatformId | Platform ID for receiving reward bonus | String | | rateType | Rate of eeturn calculation type: 0: APY; 1: APR | String | | tvl | Total value locked | String | | underlyingToken | Staked token | Struct | | >isBaseToken | Whether the staked token is a base token on the mainnet | Boolean | | >tokenContract | Smart contract address of the staked token | String | | >tokenSymbol | Token symbol of the staked token | String | | isInvestable | Whether it is investable | String | | utilizationRate | Utilization rate | String | | earnedToken | Earned tokens | Struct | | >isBaseToken | Whether the earned token is a base token on the mainnet | Boolean | | >tokenContract | Smart contract address of the earned token | String | | >tokenSymbol | Token symbol of the earned token | String | | lpToken | LP token | Struct | | >isBaseToken | Whether the LP token is a base token on the mainnet | Boolean | | >tokenContract | Smart contract address of the LP token | String | | >tokenSymbol | Token symbol of the LP token | String | ### Request example ```shell curl --location 'https://web3.okx.com/api/v5/defi/explore/product/detail?investmentId=21010' \ --header 'OK-ACCESS-KEY: 4b****53' \ --header 'OK-ACCESS-PASSPHRASE: p****d' ``` ### Response example ```json { "code": 0, "msg": "", "data": { "investmentId": "120", "investmentName": "jEUR", "chainId": "137", "rate": "0.01129", "investType": "1", "platformName": "Aave V3", "platformId": "24", "analysisPlatformId": "10", "rateType": "0", "tvl": "51350.92499", "underlyingToken": [ { "tokenSymbol": "jEUR", "tokenAddress": "0x4e3decbb3645551b8a19f0ea1678079fcb33fb4c", "isBaseToken": false } ], "isInvestable": false, "earnedToken": [ { "tokenSymbol": "jEUR", "tokenAddress": "0x4e3decbb3645551b8a19f0ea1678079fcb33fb4c", "isBaseToken": false } ], "lpToken": [ { "tokenSymbol": "aPolJEUR", "tokenAddress": "0x6533afac2e7bccb20dca161449a13a32d391fb00", "isBaseToken": false } ], "utilizationRate": "0.76862" } } ``` - [Query network list](https://web3.okx.com/onchainos/docs/waas/defi-api-reference-explore-network-list.md) {/* api-page */} # Query network list Description: This API provides information about a specified network or chain ID if the network or chainId information is accurate. If the parameters are not provided, it will list information for all supported networks. ### Request URL GET **`https://web3.okx.com/api/v5/defi/explore/network-list`** ### Request parameters | Parameter name | Description | Parameter type | Required | Data type | | --- | --- | --- | --- | --- | | network | Network name | Query parameter | No | String | | chainId | Chain ID | Query parameter | No | String | ### Response parameters | Parameter name | Description | Parameter type | | --- | --- | --- | | symbol | Network name | String | | chainId | Chain ID | String | ### Request example ```shell curl --location 'https://web3.okx.com/api/v5/defi/explore/network-list' \ --header 'OK-ACCESS-KEY: 89****53' \ --header 'OK-ACCESS-PASSPHRASE: p****d' \ ``` ### Response example ```json { "code": 0, "msg": "", "data": [ { "symbol": "Ethereum", "chainId": "1" }, { "symbol": "OKTC", "chainId": "66" }, { "symbol": "BNB Chain", "chainId": "56" }, { "symbol": "Polygon", "chainId": "137" }, { "symbol": "Avalanche C", "chainId": "43114" }, { "symbol": "TRON", "chainId": "195" }, { "symbol": "Solana", "chainId": "501" }, { "symbol": "Arbitrum", "chainId": "42161" }, { "symbol": "Optimism", "chainId": "10" }, { "symbol": "Fantom", "chainId": "250" }, { "symbol": "Conflux", "chainId": "1030" }, { "symbol": "Sui", "chainId": "784" }, { "symbol": "zkSync Era", "chainId": "324" }, { "symbol": "Stacks", "chainId": "5757" }, { "symbol": "BTC", "chainId": "0" }, { "symbol": "Core", "chainId": "1116" }, { "symbol": "Mantle", "chainId": "5000" }, { "symbol": "Base", "chainId": "8453" }, { "symbol": "Polygon zkEVM", "chainId": "1101" } ] } ``` - [Calculation](https://web3.okx.com/onchainos/docs/waas/defi-api-reference-calculation.md) # Calculation - [Query estimated calculation information for subscription](https://web3.okx.com/onchainos/docs/waas/defi-api-reference-calculation-query-info-for-investment.md) {/* api-page */} # Query estimated calculation information for subscription Description: This API provides you with estimated subscription earnings details for a specific investment. The content includes: - Super node name and estimated gas fees. - List of received tokens, details of voucher tokens, details of earnings tokens, and token authorization status (including whether authorization is required). - Subscribable amount, minimum subscription amount, maximum subscription amount, currency exchange rates, etc. ### Request URl POST **`https://web3.okx.com/api/v5/defi/calculator/subscribe-info`** ### Request parameter | Parameter name | Description | Data type | Required | Data type | | -------------- | ----------- | --------- | -------- | --------- | | address | User wallet address | Request body | No | String | | inputAmount | Subscription token quantity | Request body | Yes | String | | investmentCategory | Subscription category: 0: Default category; 1: BRC-20 | Request body | No | String | | investmentId | Investment ID (refer to [here](defi-api-reference-explore-protocol-list)) | Request body | Yes | String | | inputTokenAddress | Smart contract address of the subscription token (refer to [here](defi-api-reference-explore-product-details)) | Request body | Yes | String | | isSingle | Determine if it’s a single token investment: Yes: Single token; No: Multiple | Request body | No | Boolean | | slippage | Slippage: default is 1% | Request body | No | String | ### Response parameters | Parameter name | Description | Data type | | -------------- | ----------- | --------- | | validatorName | Super node name | String | | isAllowSubscribe | Whether subscription is allowed | Boolean | | estimateGasFee | Type of earnings calculation: 0: APY; 1: APR | String | | isSwapInvest | Whether it is a swap investment | Boolean | | exchangeRate | Currency exchange rate | String | | investWithTokenList | Pledged tokens | Array[Struct] | | > coinAmount | Token quantity | String | | > currencyAmount | Token value in USD | String | | > tokenSymbol | Token symbol | String | | > tokenName | Token name | String | | > tokenAddress | Token smart contract address | String | | > tokenPrecision | Token decimal precision | String | | > isBaseToken | Whether the pledging token is the mainnet base token | Boolean | | > network | Token network | String | | > chainId | Token chain ID | String | | > dataType | 0: Interest earnings; 1: Mining earnings; 2: Transaction fees; 3: Bonus | String | | gainsTokenList | List of earning tokens: same structure as investWithTokenList | Array[Struct] | | receiveTokenInfo | Voucher tokens received from the investment: same structure as investWithTokenList | Array[Struct] | | approveStatusList | List of token authorization status | Array[Struct] | | > tokenSymbol | Token symbol | String | | > tokenAddress | Token smart contract address | String | | > tokenPrecision | Token decimal precision | String | | > isNeedApprove | Whether authorization is required | Boolean | | > approveAddress | Contract address requiring authorization | String | | > network | Token network | String | | > chainId | Token chain ID | String | | > orderType | Parameter passed to call data (3: buy authorization, 4: redemption authorization, 8: enter farm, 9: leave farm) | String | ### Request example ```shell curl --location 'https://web3.okx.com/api/v5/defi/calculator/subscribe-info' \ --header 'OK-ACCESS-KEY: 9c****77' \ --header 'OK-ACCESS-PASSPHRASE: p****d' \ --header 'Content-Type: application/json' \ --data '{ "inputAmount": "1", "inputTokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "isSingle": false, "tokenDecimal": "18", "investmentId": "21915", "address": "0x7f****da", "investmentType": 0 }' ``` ### Response example ```json { "code": 0, "msg": "", "data": { "investWithTokenList": [ { "tokenSymbol": "CORE", "tokenName": "Core", "tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "network": "CORE", "chainId": "1116", "tokenPrecision": "18", "isBaseToken": true, "coinAmount": "1", "currencyAmount": "0.5035" } ], "gainsTokenList": [ { "tokenSymbol": "CORE", "tokenName": "Core", "tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "network": "CORE", "tokenPrecision": "18", "coinAmount": "0.000742226856350101", "dataType": "0" } ], "approveStatusList": [ { "tokenSymbol": "CORE", "tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "network": "CORE", "chainId": "1116", "tokenPrecision": "18", "isNeedApprove": false, "approveAddress": "0x0000000000000000000000000000000000001007", "orderType": "3" } ], "isSwapInvest": false, "estimateGasFee": "99343", "isAllowSubscribe": true, "validatorName": "OKXEarn" } } ``` - [Query estimated calculation information for redemption](https://web3.okx.com/onchainos/docs/waas/defi-api-reference-calculation-query-info-for-redemption.md) {/* api-page */} # Query estimated calculation information for redemption Description: This API provides you with estimated redemption details for a specific investment. The content includes: - Super node name and estimated gas fees. - List of received tokens, details of token exchange, and token authorization status (including whether authorization is required). - Redeemable amount, minimum redemption amount, maximum redemption amount, etc. ### Request URL POST **`https://web3.okx.com/api/v5/defi/calculator/redeem-info`** ### Request parameter | Parameter name | Description | Parameter type | Required | Data type | | -------------- | ----------- | -------------- | -------- | --------- | | address | User wallet address | Request body | No | String | | inputTokenAmount | Subscription token quantity | Request body | Yes | String | | investmentCategory | Subscription category: (e.g., 0: Default category; 1: BRC-20) | Request body | No | String | | investmentId | Investment ID (refer to [here](defi-api-reference-explore-protocol-list)) | Request body | Yes | String | | isSingle | Determine if it's a single token investment: Yes: Single; No: Multiple | Request body | No | Boolean | | outputTokenAddress | Token smart contract address (refer to [here](defi-api-reference-personal-query-position)) | Request body | Yes | String | | slippage | Slippage | Request body | No | String | ### Response parameters | Parameter name | Description | Data type | | -------------- | ----------- | --------- | | isAllowRedeem | Whether redemption is allowed | Boolean | | estimateGasFee | Estimated gas limit | String | | isSwapInvest | Whether it is a swap investment | Boolean | | inputCurrencyAmount | Input currency value in USD | String | | receiveTokenList | List of received token information | Array[Struct] | | > coinAmount | Token quantity | String | | > currencyAmount | Token value in USD | String | | > tokenSymbol | Token symbol | String | | > tokenName | Token name | String | | > tokenAddress | Token smart contract address | String | | > tokenPrecision | Token decimal precision | String | | > isBaseToken | Whether the pledging token is the mainnet base token | Boolean | | > network | Token network | String | | > chainId | Token chain ID | String | | > dataType | 0: principle 1: rewards 2: tradingFee 3: Bonus | String | | swapFromTokenList | Token list during redemption: same structure as investWithTokenList | Array[Struct] | | mySupply | Redeemable amount: same structure as investWithTokenList | Struct | | approveStatusList | List of token authorization status | Array[Struct] | | > tokenSymbol | Token symbol | String | | > tokenAddress | Token smart contract address | String | | > tokenPrecision | Token decimal precision | String | | > isNeedApprove | Whether authorization is required | Boolean | | > approveAddress | Contract address requiring authorization | String | | > network | Token network | String | | > chainId | Token chain ID | String | | > orderType | Parameter passed to call data (3: buy authorization, 4: redemption authorization, 8: enter farm, 9: leave farm) | String | ### Request example ```shell curl --location 'https://web3.okx.com/api/v5/defi/calculator/redeem-info' \ --header 'OK-ACCESS-KEY: 9c****77' \ --header 'OK-ACCESS-PASSPHRASE: p****d' \ --header 'Content-Type: application/json' \ --data '{ "address": "0x7f****da", "inputTokenAmount": "1.000000146425127036", "investmentCategory": "0", "investmentId": "21033", "isSingle": false, "outputTokenAddress": "0x6b175474e89094c44da98b954eedeac495271d0f", "outputTokenDecimal": "18", "redeemId": "", "slippage": "" }' ``` ### Response example ```json { "code": 0, "msg": "", "data": { "receiveTokenList": [ { "tokenSymbol": "DAI", "tokenName": "Dai Stablecoin", "tokenAddress": "0x6b****0f", "network": "ETH", "chainId": "1", "tokenPrecision": "18", "isBaseToken": false, "coinAmount": "1.000000146425127036", "currencyAmount": "0.9993097704396316094231068522159962", "dataType": "0" } ], "swapFromTokenList": [ { "tokenSymbol": "DAI", "tokenName": "Dai Stablecoin", "tokenAddress": "0x6b****0f", "network": "ETH", "chainId": "1", "tokenPrecision": "18", "isBaseToken": false, "coinAmount": "1.000000146425127036", "currencyAmount": "0.9993097704396316094231068522159962" } ], "isSwapInvest": false, "estimateGasFee": "276614", "isAllowRedeem": true, "mySupply": { "tokenSymbol": "DAI", "tokenName": "Dai Stablecoin", "tokenAddress": "0x6b****0f", "network": "ETH", "chainId": "1", "tokenPrecision": "18", "isBaseToken": false, "coinAmount": "0", "currencyAmount": "0" }, "inputCurrencyAmount": "0.9993097704396316094231068522159962" } } ``` - [Transaction](https://web3.okx.com/onchainos/docs/waas/defi-api-reference-transaction.md) # Transaction Description: This API provides call data for transactions when you start using it. - [Generate call data for transaction authorization](https://web3.okx.com/onchainos/docs/waas/defi-api-reference-transaction-calldata-for-authorization.md) {/* api-page */} # Generate call data for transaction authorization Description: This API provides you with call data for various authorizations before making a transaction. ### Requset URL POST **`https://web3.okx.com/api/v5/defi/transaction/authorization`** ### Request parameter | Parameter name | Description | Location | Required | Data type | | -------------- | ----------- | -------- | -------- | --------- | | address | User wallet address | Request body | Yes | String | | investmentId | Investment ID | Request body | Yes | String | | type | Transaction type (e.g., 3: Subscription authorization; 4: Redemption authorization; 5: Claim authorization) | Request body | Yes | int | | userInputList | User input token information | Request body | Yes | Array[Struct] | | > chainId | Blockchain ID | Request body | No | String | | > coinAmount | Subscription amount | Request body | Yes | String | | > tokenAddress | Smart contract address of the subscription token | Request body | No | String | | expectOutputList | User expected profit information | Request body | No | Array[Struct] | | > chainId | Blockchain ID | Request body | No | String | | > coinAmount | Subscription amount | Request body | No | String | | > tokenAddress | Smart contract address of the subscription token | Request body | No | String | ### Response parameters | Parameter name | Description | Data type | | -------------- | ----------- | --------- | | dataList | Call data information | Array[Struct] | | > from | From (user address) | String | | > to | To (target contract address) | String | | > value | Transfer amount (native token quantity, default is an empty string) | String | | > serializedData | Call data | String | | > originalData | Original data (JSON) | JSON String | | > callDataType | Operation type (authorization, subscription, redemption, claim) | String | ### Request example ```shell curl --location 'https://web3.okx.com/api/v5/defi/transaction/authorization' \ --header 'OK-ACCESS-KEY: 9c****77' \ --header 'OK-ACCESS-PASSPHRASE: p****d' \ --header 'Content-Type: application/json' \ --data '{ "address": "0x7f****da", "userInputList": [ { "chainId": 56, "coinAmount": "10", "tokenAddress": "0x526a913a7a4518aa2abc3dcd3c46a9c73f40f94a" } ], "investmentId": "6925", "type": 3 }' ``` ### Response example ```json { "code": 0, "msg": "", "data": { "dataList": [ { "from": "0x7f****da", "to": "0x52****4a", "value": "0x0", "serializedData": "0x095ea7b30000000000000000000000002c34a2fb1d0b4f55de51e1d0bdefaddce6b7cdd60000000000000000000000000000000000000000000000008ac7230489e80000", "originalDataClass": "OriginalDataApprove", "originalData": "{\"methodDefine\":\"approve(address,uint256)\",\"methodId\":\"0x095ea7b3\",\"methodType\":\"METHOD_ID\",\"params\":{\"params\":[\"0x2c34a2fb1d0b4f55de51e1d0bdefaddce6b7cdd6\",\"10000000000000000000\"]},\"useAdapter\":false}", "signatureData": "1bca0efbd1c809de94cdd8c924329c7ac79a4d346742de61925e8494f2c84c446bd3cf42b56d690c85ff513beadf46cd18f4e3e74845a92c48451584615f749d1c" } ] } } ``` - [Generate call data for subscription transactions](https://web3.okx.com/onchainos/docs/waas/defi-api-reference-transaction-calldata-for-subscription.md) {/* api-page */} # Generate call data for subscription transactions Description: This API provides call data for subscription transactions. ### Request URL POST **`https://web3.okx.com/api/v5/defi/transaction/subscription`** ### Request parameters | Parameter name | Description | Parameter type | Required | Data type | | ---------------- | ------------------------------------------------ | -------------- | -------- | ----------- | | address | User wallet address | Request body | Yes | String | | investmentId | Investment product ID | Request body | Yes | String | | userInputList | User input token information | Request body | Yes | Array[Struct] | | >chainId | Blockchain ID (default: investment product network) | Request body | No | String | | >coinAmount | Subscription quantity | Request body | Yes | String | | >tokenAddress | Smart contract address of subscription token (default: investment product token address) | Request body | No | String | | expectOutputList | User expected profit information | Request body | Yes | Array[Struct] | | >chainId | Blockchain ID | Request body | No | String | | >coinAmount | Subscription quantity | Request body | Yes | String | | >tokenAddress | Smart contract address of subscription token | Request body | No | String | | extra | See remarks for specific usage | Request body | No | String | ### Remarks: Usage of extra Subscription key: rewardAddress (String) Meaning: For Stake-type investment products, the user’s personal BTC reward wallet address. ### Response parameters | Parameter name | Description | Data type | | -------------- | ----------- | --------- | | dataList | Call data information | Array[Struct] | | >from | From (user address) | String | | >to | To (target contract address) | String | | >value | Transfer amount (native token quantity, default is an empty string) | String | | >serializedData | Call data data | String | | >originalData | Original data (JSON) | JSON String | | >callDataType | Operation type (authorization, subscription, redemption, claim) | String | | >signatureData | Signature call data information, can be used to verify data generated by OKX | String | ### Remarks: Verification method: 1. Calculate r, s, and v using the signatureData signature information. 2. Calculate the verification hash using the string concatenated from to + serializedData + originalData. 3. Verify the recovered public key. The integration client can choose whether to verify the signature. If the verification is successful, it indicates that the data is generated by OKX. ## Subscription example ### Request example ```shell curl --location 'https://web3.okx.com/api/v5/defi/transaction/subscription' \ --header 'OK-ACCESS-KEY: 9c****77' \ --header 'OK-ACCESS-PASSPHRASE: p****d' \ --header 'Content-Type: application/json' \ --data '{ "address": "0x7f429edeff8afc7bb3a2cf7db832fc86f6fa99da", "userInputList": [ { "coinAmount": "0.6" } ], "expectOutputList": [ { "coinAmount": "0.5" } ], "investmentId": "6925" }' ``` ### Response example ```json { "code": 0, "msg": "", "data": { "dataList": [ { "from": "0x7f****da", "to": "0x72****d2", "value": "0x0", "serializedData": "0x016cba5f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000526a913a7a4518aa2abc3dcd3c46a9c73f40f94a0000000000000000000000000000000000000000000000000853a0d2313c00000000000000000000000000005569e13b1ec4336d17e8f24d892a4a915fc5da9400000000000000000000000000000000000000000000000000000000000000010000000000000000000000004e38a4ad4f210ad5abb2c8f2598706ae8b4a1ce600000000000000000000000000000000000000000000000006f05b59d3b20000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000005569e13b1ec4336d17e8f24d892a4a915fc5da94000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e4c41a3be800000000000000000000000000000000000000000000000000000000000000000000000000000000000000004e38a4ad4f210ad5abb2c8f2598706ae8b4a1ce60000000000000000000000007f429edeff8afc7bb3a2cf7db832fc86f6fa99da00000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000026f700000000000000000000000000000000000000000000000000000000", "originalData": "{\"hexCallData\":\"0x016cba5f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000526a913a7a4518aa2abc3dcd3c46a9c73f40f94a0000000000000000000000000000000000000000000000000853a0d2313c00000000000000000000000000005569e13b1ec4336d17e8f24d892a4a915fc5da9400000000000000000000000000000000000000000000000000000000000000010000000000000000000000004e38a4ad4f210ad5abb2c8f2598706ae8b4a1ce600000000000000000000000000000000000000000000000006f05b59d3b20000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000005569e13b1ec4336d17e8f24d892a4a915fc5da94000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e4c41a3be800000000000000000000000000000000000000000000000000000000000000000000000000000000000000004e38a4ad4f210ad5abb2c8f2598706ae8b4a1ce60000000000000000000000007f429edeff8afc7bb3a2cf7db832fc86f6fa99da00000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000026f700000000000000000000000000000000000000000000000000000000\",\"methodDefine\":\"{\\n\\t\\\"inputs\\\": [{\\n\\t\\t\\\"components\\\": [{\\n\\t\\t\\t\\\"internalType\\\": \\\"struct TokenInInfo\\\",\\n\\t\\t\\t\\\"name\\\": \\\"tokenIn\\\",\\n\\t\\t\\t\\\"type\\\": \\\"tuple[]\\\",\\n\\t\\t\\t\\\"components\\\": [{\\n\\t\\t\\t\\t\\\"internalType\\\": \\\"address\\\",\\n\\t\\t\\t\\t\\\"name\\\": \\\"token\\\",\\n\\t\\t\\t\\t\\\"type\\\": \\\"address\\\"\\n\\t\\t\\t}, {\\n\\t\\t\\t\\t\\\"internalType\\\": \\\"uint256\\\",\\n\\t\\t\\t\\t\\\"name\\\": \\\"amount\\\",\\n\\t\\t\\t\\t\\\"type\\\": \\\"uint256\\\"\\n\\t\\t\\t}, {\\n\\t\\t\\t\\t\\\"internalType\\\": \\\"address\\\",\\n\\t\\t\\t\\t\\\"name\\\": \\\"to\\\",\\n\\t\\t\\t\\t\\\"type\\\": \\\"address\\\"\\n\\t\\t\\t}]\\n\\t\\t}, {\\n\\t\\t\\t\\\"internalType\\\": \\\"struct TokenAmount\\\",\\n\\t\\t\\t\\\"name\\\": \\\"tokenOut\\\",\\n\\t\\t\\t\\\"type\\\": \\\"tuple[]\\\",\\n\\t\\t\\t\\\"components\\\": [{\\n\\t\\t\\t\\t\\\"internalType\\\": \\\"address\\\",\\n\\t\\t\\t\\t\\\"name\\\": \\\"token\\\",\\n\\t\\t\\t\\t\\\"type\\\": \\\"address\\\"\\n\\t\\t\\t}, {\\n\\t\\t\\t\\t\\\"internalType\\\": \\\"uint256\\\",\\n\\t\\t\\t\\t\\\"name\\\": \\\"amount\\\",\\n\\t\\t\\t\\t\\\"type\\\": \\\"uint256\\\"\\n\\t\\t\\t}]\\n\\t\\t}],\\n\\t\\t\\\"internalType\\\": \\\"struct BaseRequest\\\",\\n\\t\\t\\\"name\\\": \\\"request\\\",\\n\\t\\t\\\"type\\\": \\\"tuple\\\"\\n\\t}, {\\n\\t\\t\\\"components\\\": [{\\n\\t\\t\\t\\\"internalType\\\": \\\"address\\\",\\n\\t\\t\\t\\\"name\\\": \\\"target\\\",\\n\\t\\t\\t\\\"type\\\": \\\"address\\\"\\n\\t\\t}, {\\n\\t\\t\\t\\\"internalType\\\": \\\"bytes\\\",\\n\\t\\t\\t\\\"name\\\": \\\"callData\\\",\\n\\t\\t\\t\\\"type\\\": \\\"bytes\\\"\\n\\t\\t}],\\n\\t\\t\\\"internalType\\\": \\\"struct Call\\\",\\n\\t\\t\\\"name\\\": \\\"calls\\\",\\n\\t\\t\\\"type\\\": \\\"tuple[]\\\"\\n\\t}],\\n\\t\\\"name\\\": \\\"execute\\\",\\n\\t\\\"stateMutability\\\": \\\"payable\\\",\\n\\t\\\"type\\\": \\\"function\\\"\\n}\",\"methodId\":\"\",\"methodType\":\"ABI\",\"params\":{\"baseRequest\":{\"tokenIn\":[{\"amount\":600000000000000000,\"to\":\"0x5569e13b1ec4336d17e8f24d892a4a915fc5da94\",\"token\":\"0x526a913a7a4518aa2abc3dcd3c46a9c73f40f94a\"}],\"tokenOut\":[{\"amount\":500000000000000000,\"token\":\"0x4e38a4ad4f210ad5abb2c8f2598706ae8b4a1ce6\"}]},\"operatorDataList\":[{\"adapterOperate\":true,\"call\":{\"calls\":\"xBo76AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATjikrU8hCtWrssjyWYcGrotKHOYAAAAAAAAAAAAAAAB/Qp7e/4r8e7Oiz324MvyG9vqZ2gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwW1nTsgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACb3\",\"callsAsString\":\"0xc41a3be800000000000000000000000000000000000000000000000000000000000000000000000000000000000000004e38a4ad4f210ad5abb2c8f2598706ae8b4a1ce60000000000000000000000007f429edeff8afc7bb3a2cf7db832fc86f6fa99da00000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000026f7\",\"target\":\"0x5569e13b1ec4336d17e8f24d892a4a915fc5da94\"},\"hexCallData\":\"0xc41a3be800000000000000000000000000000000000000000000000000000000000000000000000000000000000000004e38a4ad4f210ad5abb2c8f2598706ae8b4a1ce60000000000000000000000007f429edeff8afc7bb3a2cf7db832fc86f6fa99da00000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000026f7\",\"operateType\":\"DEPOSIT\",\"operatorMethodInfo\":{\"methodDefine\":\"{\\n\\t\\\"inputs\\\": [{\\n\\t\\t\\\"internalType\\\": \\\"address\\\",\\n\\t\\t\\\"name\\\": \\\"pool\\\",\\n\\t\\t\\\"type\\\": \\\"address\\\"\\n\\t}, {\\n\\t\\t\\\"internalType\\\": \\\"struct TokenOutInfo\\\",\\n\\t\\t\\\"name\\\": \\\"tokenOut\\\",\\n\\t\\t\\\"type\\\": \\\"tuple\\\",\\n\\t\\t\\\"components\\\": [{\\n\\t\\t\\t\\t\\\"internalType\\\": \\\"address\\\",\\n\\t\\t\\t\\t\\\"name\\\": \\\"token\\\",\\n\\t\\t\\t\\t\\\"type\\\": \\\"address\\\"\\n\\t\\t\\t}, {\\n\\t\\t\\t\\t\\\"internalType\\\": \\\"address\\\",\\n\\t\\t\\t\\t\\\"name\\\": \\\"toAddress\\\",\\n\\t\\t\\t\\t\\\"type\\\": \\\"address\\\"\\n\\t\\t\\t},\\n\\t\\t\\t{\\n\\t\\t\\t\\t\\\"internalType\\\": \\\"uint256\\\",\\n\\t\\t\\t\\t\\\"name\\\": \\\"minAmount\\\",\\n\\t\\t\\t\\t\\\"type\\\": \\\"uint256\\\"\\n\\t\\t\\t}\\n\\t\\t]\\n\\t}, {\\n\\t\\t\\\"internalType\\\": \\\"bytes\\\",\\n\\t\\t\\\"name\\\": \\\"data\\\",\\n\\t\\t\\\"type\\\": \\\"bytes\\\"\\n\\n\\t}],\\n\\t\\\"name\\\": \\\"deposit\\\",\\n\\t\\\"stateMutability\\\": \\\"payable\\\",\\n\\t\\\"type\\\": \\\"function\\\"\\n}\",\"params\":{\"data\":\"00000000000000000000000000000000000000000000000000000000000026f7\",\"pool\":\"0x0000000000000000000000000000000000000000\",\"tokenOut\":{\"amount\":500000000000000000,\"toAddress\":\"0x7f429edeff8afc7bb3a2cf7db832fc86f6fa99da\",\"token\":\"0x4e38a4ad4f210ad5abb2c8f2598706ae8b4a1ce6\"}}},\"target\":\"0x5569e13b1ec4336d17e8f24d892a4a915fc5da94\"}]},\"useAdapter\":true}", "signatureData": "dbfe682a491b31141c99800913c9a052ee8dee122854cb0c459af85fff9f5d571aaf217b3bbbe10b141247bc0327357c3dde2874333f8a4c031d84d31a41ffec1c" } ] } } ``` - [Generate redemption transaction call data](https://web3.okx.com/onchainos/docs/waas/defi-api-reference-transaction-calldata-for-redemption.md) {/* api-page */} # Generate redemption transaction call data Description: This API provides the call data for a redemption transaction. ### Request URL POST **`https://web3.okx.com/api/v5/defi/transaction/redemption`** ### Request parameters | Parameter name | Description | Parameter type | Required | Data type | | --- | --- | --- | --- | --- | | address | User wallet address | Request body | Yes | String | | investmentId | Investment product ID | Request body | Yes | String | | userInputList | User input token information | Request body | Yes | Array[Struct] | | >chainId | Blockchain ID (Default: Investment product network) | Request body | No | String | | >coinAmount | Subscription quantity | Request body | Yes | String | | >tokenAddress | Smart contract address of the subscription token (Default: Investment product token address) | Request body | No | String | | expectOutputList | User expected profit information | Request body | Yes | Array[Struct] | | >chainId | Blockchain ID | Request body | No | String | | >coinAmount | Subscription quantity | Request body | Yes | String | | >tokenAddress | Smart contract address of the subscription token | Request body | No | String | | extra | See remarks for details | Request body | No | String | ### Remarks: Usage of extra redeemCalldataExtInfo - SUI Staking: [SUI staking investment](https://web3.okx.com/cn/web3/defi/detail/20801#source=search&orderToolType=redeem) - SOL Staking: [SOL staking investment](https://web3.okx.com/cn/web3/defi/detail/21530#source=search&orderToolType=redeem) [Here](defi-api-reference-calculation-query-info-for-redemption) provides the investOrderList field, which represents each user’s subscription. The investOrderList.redeemExtra field represents the data required for the call data Extra. ```json {"extra": "{\"redeemCalldataExtInfo\":[{\"unstakeIndex\":\"0xbc5118e65240dd5702218b37fd8d965d6eb4400474f34b6fe4a8f7805fc09405\"}]}"} ``` ### Response parameters | Parameter name | Description | Data type | | --- | --- | --- | | dataList | call data information | Array[Struct] | | >from | From (user address) | String | | >to | To (target contract address) | String | | >value | Transfer amount (native token quantity, default is an empty string) | String | | >serializedData | call data | String | | >originalData | Original data (JSON) | JSON String | | >callDataType | Operation type (authorization, subscription, redemption, claim) | String | | >signatureData | Signed call data information, can be used to verify data generated by OKX | String | ### Remarks: Signature verification method: 1. Calculate r, s, v using the signatureData signature information. 2. Calculate the verification hash by concatenating the string formed by to + serializedData + originalData. 3. Perform public key recovery verification. The client can choose whether to perform signature verification. If the verification is successful, it indicates that the data was signed by OKX. ## Redemption example ### Request example ```shell curl --location 'https://web3.okx.com/api/v5/defi/transaction/redemption' \ --header 'OK-ACCESS-KEY: 9c****77' \ --header 'OK-ACCESS-PASSPHRASE: p****d' \ --header 'Content-Type: application/json' \ --data '{ "address": "0x7f****da", "investmentId": "21033", "userInputList": [ { "chainId": 1, "coinAmount": "1", "tokenAddress": "0x6b175474e89094c44da98b954eedeac495271d0f" } ], "extra": "{\"redeemAll\":1}" }' ``` ### Response example ```json { "code": 0, "msg": "", "data": { "dataList": [ { "callDataType": "WITHDRAW", "from": "0x7f****da", "to": "0x83****ea", "value": "0x0", "serializedData": "0xba0876520000000000000000000000000000000000000000000000000cbb507c8eb3879f0000000000000000000000007f429edeff8afc7bb3a2cf7db832fc86f6fa99da0000000000000000000000007f429edeff8afc7bb3a2cf7db832fc86f6fa99da", "originalData": "{\"callDataType\":\"WITHDRAW\",\"methodDefine\":\"redeem(uint256,address,address)\",\"methodId\":\"0xba087652\",\"methodType\":\"METHOD_ID\",\"params\":{\"params\":[\"917415445000325023\",\"0x7f429edeff8afc7bb3a2cf7db832fc86f6fa99da\",\"0x7f429edeff8afc7bb3a2cf7db832fc86f6fa99da\"]},\"useAdapter\":false}", "signatureData": "e6beeb6f9df6ecb7eb7791e57226f9eca1d7c3efa869172bb5021b9c827ad21b46e3dc4566608af727555e0a47aa90cf261331f4e1691b0201aa0b8a00ea685b1b" } ] } } ``` - [Generate call data for claiming bonus rewards](https://web3.okx.com/onchainos/docs/waas/defi-api-reference-transaction-calldata-for-bonus.md) {/* api-page */} # Generate call data for claiming bonus rewards Description: This API provides the call data for claiming bonus rewards. ### Request URL POST **`https://web3.okx.com/api/v5/defi/transaction/bonus`** ### Request parameter | Parameter name | Description | Parameter type | Required | Data type | | --- | --- | --- | --- | --- | | address | User wallet address | Request body | Yes | String | | investmentId | Investment product ID | Request body | Yes | String | | userInputList | User input token information | Request body | Yes | Array[Struct] | | >chainId | Blockchain ID (default: investment product network) | Request body | No | String | | >coinAmount | Subscription quantity | Request body | Yes | String | | >tokenAddress | Smart contract address of the subscription token (default: investment product token address) | Request body | No | String | | expectOutputLIst | User expected profit information | Request body | Yes | Array[Struct] | | >chainId | Blockchain ID | Request body | No | String | | >coinAmount | Subscription quantity | Request body | Yes | String | | >tokenAddress | Smart contract address of the subscription token | Request body | No | String | | extra | See remarks for specific meaning | Request body | No | String | ### Remarks: Usage of extra claiming bonus rewards - a. key: claimIndex (number), meaning: ID of the reward to be claimed. Click [here](defi-api-reference-personal-invest-unstake-list) to obtain supporting protocols, such as: Ankr, Benqi, Stader, Lido. The [interface](defi-api-reference-personal-query-position) can retrieve the user’s positions if the returned result field is present. rewardDefiTokenInfo.claimMode is 1. It means there is a secondary page. You can click [here](defi-api-reference-personal-invest-unstake-list) to get the reward list. To claim a specific reward, you need to pay attention to several fields: - canClaimAll:Indicates whether all rewards can be claimed. - rewardTokenInfos.claimIndex:Identifies the ID of a specific reward. - callDataRewardType: 1-claimable reward, 2-expired reward, 3-unclaimable reward. Call data Extra field parameters: 1. If canClaimAll = true (currently only for Benqi/Tranchess) - If the length of claimIndex is 1, it will claim 1 reward. ```json {"extra" : "{\"claimIndex\":[\"2\"]}" } ``` - If the length of claimIndex is greater than 1, it will claim all claimable rewards. ```json {"extra" : "{\"claimIndex\":[\"2\",\"3\"]}" } ``` 2. If canClaimAll = false, not all rewards can be claimed, and the length of claimIndex can only be 1. ```json {"extra" : "{\"claimIndex\":[\"2\"]}" } ``` 3. If callDataRewardType = 2 and a reward needs to be claimed (only for Benqi), claimOverdue = true. This means that it can be claimed even if it has expired, but it will claim a different currency. The default value is false, which means it will not claim the expired reward and will claim the specified currency reward in the next claiming cycle. ```json {"extra": "{\"claimOverdue\":1,\"claimIndex\":[\"2\"]}"} ``` - b. key: analysisPlatformId (Number), meaning: Claim rewards for the entire platform. Click [here](defi-api-reference-explore-product-details) to obtain supporting platforms, such as: Compound, Aave V2, WePiggy, Venus, Aave V3, Benqi, Radiant, Geist finance, Tender, Compound V3, SonneFinance, Clearpool. ### Response parameters | Parameter name | Description | Data type | | --- | --- | --- | | dataList | Call data information | Array[Struct] | | >from | From (user address) | String | | >to | To (target contract address) | String | | >value | Transfer amount (native token quantity, default is an empty string) | String | | >serializedData | Call data data | String | | >originalData | Original data (JSON) | JSON String | | >callDataType | Operation type (authorization, subscription, redemption, claiming) | String | | >signatureData | Signed Call data information, can be used to verify data generated by OKX | String | ### Remarks: Signature verification method: 1. Calculate the values of r, s, and v using the signatureData. 2. Concatenate the string formed by to + serializedData + originalData and calculate the verification hash. 3. Perform public key recovery verification. The decision to perform signature verification can be made by the integrating client. If the verification is successful, it indicates that the data was generated by OKX. ## Example of claiming protocol rewards ### Request example ```shell curl --location 'https://web3.okx.com/api/v5/defi/transaction/bonus' \ --header 'OK-ACCESS-KEY: 9c****77' \ --header 'OK-ACCESS-PASSPHRASE: p****d' \ --header 'Content-Type: application/json' \ --data '{ "address": "0x7f****da", "expectOutputList": [ { "chainId": 1, "coinAmount": "1065142752604499571", "tokenAddress": "0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0" } ], "investmentId": "10003", "extra": "{\"claimOverdue\":0,\"claimIndex\":[\"1286\"],\"callDataExtJson\":\"\",\"redeemCalldataExtInfo\":[],\"rewardAddress\":\"\"}" }' ``` ### Response example ```json { "code": 0, "msg": "", "data": { "dataList": [ { "callDataType": "CLAIM", "from": "0x7f****da", "to": "0x9e****99", "value": "0x0", "serializedData": "0x46e04a2f000000000000000000000000000000000000000000000000000000000000042a", "originalData": "{\"callDataType\":\"CLAIM\",\"methodDefine\":\"claimTokens(uint256)\",\"methodId\":\"0x46e04a2f\",\"methodType\":\"METHOD_ID\",\"params\":{\"params\":[\"1066\"]},\"useAdapter\":false}", "signatureData": "e35e234d1568e13f5b7a9bd175ae947268dc3e817973120381fc8eecda78f71633ff67564c6460e388a2ca60daab62ce68f8952387e48ce63c19cad38f332c941b" } ] } } ``` - [User](https://web3.okx.com/onchainos/docs/waas/defi-api-reference-personal.md) # User - [Query user's position list](https://web3.okx.com/onchainos/docs/waas/defi-api-reference-personal-asset-platform-list.md) {/* api-page */} # Query user's position list Description: This API provides the user's asset position list. ### Request URL POST **`https://web3.okx.com/api/v5/defi/user/asset/platform/list`** ### Request parameter | Parameter name | Description | Parameter type | Required | Data type | | -------------- | ----------- | -------------- | -------- | --------- | | walletAddressList | user wallet address list | Request body | Yes | Array | | >chainId | public chain ID | Request body | Yes | String | | >walletAddress | user wallet address | Request body | Yes | String | ### Response parameters | Parameter name | Description | Data type | |---------------------|---------------------------------------------------------|---------------| | walletIdPlatformList | positions from address list | Array | | >platformList | positions from a specific address | String | | >platformName | platform name | String | | >analysisPlatformId | protocol ID | String | | >platformLogo | platform logo | String | | >currencyAmount | position value in USD | String | | >isSupportInvest | if supported by Okx DeFi | String | | >platformUrl | platform Url | String | | >networkBalanceVoList | positions from multiple network | Array | | >>network | network name | String | | >>networkLogo | network logo | String | | >>chainId | pulich chain ID | String | | >>currencyAmount | position value in USD | String | | >investmentCount | number of positions | String | ### Request example ```shell curl --location 'https://web3.okx.com/api/v5/defi/user/asset/platform/list' \ --header 'OK-ACCESS-KEY: 9c****77' \ --header 'OK-ACCESS-PASSPHRASE: p****d' \ --header 'Content-Type: application/json' \ --data '{ "walletAddressList": [ { "chainId": 1, "walletAddress": "0x655b35f11006617696a4b31978ba4c078b6b7145" } ] }' ``` ### Response example ```json { "code": 0, "msg": "", "error_code": "0", "error_message": "", "detailMsg": "", "data": { "walletIdPlatformList": [ { "platformList": [ { "platformName": "Ethena", "analysisPlatformId": 118265, "platformLogo": "https://static.coinall.ltd/cdn/web3/protocol/logo/1702889213278.png/type=png_350_0", "platformColor": "", "currencyAmount": "10076.999426431322729394061370751783986", "isSupportInvest": true, "bonusTag": 0, "platformUrl": "https://app.ethena.fi", "networkBalanceVoList": [ { "network": "ETH", "networkLogo": "https://static.coinall.ltd/cdn/wallet/logo/ETH-20220328.png", "chainId": 1, "currencyAmount": "10076.999426431322729394061370751783986" } ], "investmentCount": 1 }, { "platformName": "Pendle V2", "analysisPlatformId": 258, "platformLogo": "https://static.coinall.ltd/cdn/web3/protocol/logo/pendle-v2.png/type=png_350_0", "platformColor": "", "currencyAmount": "161.9345234089089141378517476223121560", "isSupportInvest": true, "bonusTag": 0, "platformUrl": "https://www.pendle.finance/", "networkBalanceVoList": [ { "network": "ETH", "networkLogo": "https://static.coinall.ltd/cdn/wallet/logo/ETH-20220328.png", "chainId": 1, "currencyAmount": "161.9345234089089141378517476223121560" } ], "investmentCount": 2 }, { "platformName": "Zircuit", "analysisPlatformId": 119424, "platformLogo": "https://static.coinall.ltd/cdn/web3/protocol/logo/zircuit.png/type=png_350_0", "platformColor": "", "currencyAmount": "156.9108954533033331829362703655488", "isSupportInvest": true, "bonusTag": 0, "platformUrl": "https://stake.zircuit.com/", "networkBalanceVoList": [ { "network": "ETH", "networkLogo": "https://static.coinall.ltd/cdn/wallet/logo/ETH-20220328.png", "chainId": 1, "currencyAmount": "156.9108954533033331829362703655488" } ], "investmentCount": 1 } ], "walletId": "8f4d93d7-275e-45dd-a0ce-2014d82d4baf", "totalAssets": "10395.8448452935349767148493887396449420" } ], "lpTokenAddressList": [ { "chainId": 1, "tokenAddress": "0xdc02b77a3986da62c7a78fed73949c9767850809" } ], "updateAt": 1727083602000, "assetStatus": 1 } } ``` - [Query user's position list based on protocol](https://web3.okx.com/onchainos/docs/waas/defi-api-reference-personal-asset-platform-detail.md) {/* api-page */} # Query user's position list based on protocol Description: This API provides the user's asset position list based on a specific protocol. ### Request URL POST **`https://web3.okx.com/api/v5/defi/user/asset/platform/detail`** ### Request parameter | Parameter name | Description | Parameter type | Required | Data type | | --- | --- | --- | --- | --- | | analysisPlatformId | protocol ID | Request body | Yes | String | | walletAddressList | user address list | Request body | Yes | Array | | >chainId | public chain ID | Request body | Yes | String | | >walletAddress | user wallet address | Request body | Yes | String | ### Response parameters | Parameter name | Description | Data type | |---------------------|---------------------------------------------------------|---------------| | networkHoldVoList | user positions under a specific network | Array | | >network | network name | String | | >chainId | public chain ID | String | | >investTokenBalanceVoList | position list | Array | | >>investType | investment type: 1. Save; 2. Pool; 3. Farm; 4. Vaults; 5. Stake | String | | >>>tokenSymbol | asset name | String | | >>>tokenLogo | asset logo | String | | >>>coinAmount | invested asset amount | String | | >>>currencyAmount | invested amount in USD | String | | >>>tokenPrecision | token precision | String | | >>>tokenAddress | token address | String | | >>>network | network | String | | >>totalValue | total position value in USD | String | | >platformName | protocol name | String | | >analysisPlatformId | protocol ID | String | | >platformLogo | protocol logo | String | | >platformUrl | protocol Url | String | ### Request example ```shell curl --location 'https://web3.okx.com/api/v5/defi/user/asset/platform/detail' \ --header 'OK-ACCESS-KEY: 9c****77' \ --header 'OK-ACCESS-PASSPHRASE: p****d' \ --header 'Content-Type: application/json' \ --data '{ "analysisPlatformId": 260, "accountIdInfoList": [ { "walletAddressList": [ { "chainId": 42161, "walletAddress": "0x7f429edeff8afc7bb3a2cf7db832fc86f6fa99da" } ] } ] }' ``` ### Response example ```json { "code": 0, "msg": "", "error_code": "0", "error_message": "", "detailMsg": "", "data": { "walletIdPlatformDetailList": [ { "networkHoldVoList": [ { "network": "Arbitrum One", "chainId": 42161, "investTokenBalanceVoList": [ { "investType": 5, "assetsTokenList": [ { "tokenSymbol": "ETH", "tokenLogo": "https://static.coinall.ltd/cdn/wallet/logo/ETH-20220328.png", "coinAmount": "0.000044133940644863", "currencyAmount": "0.11722724912266575471", "tokenPrecision": 18, "tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "network": "ARB" } ], "rewardDefiTokenInfo": [], "totalValue": "0.11722724912266575471" } ], "availableRewards": [], "airDropRewardInfo": [] } ], "accountId": "278c58bb-5958-4301-a5b6-d670e1d9837f" } ], "platformName": "ether.fi", "analysisPlatformId": 260, "platformLogo": "https://static.coinall.ltd/cdn/invest/platform/EtherFi.png", "platformUrl": "https://www.ether.fi/" } } ``` - [Query user's position list based on product](https://web3.okx.com/onchainos/docs/waas/defi-api-reference-personal-query-position.md) {/* api-page */} # Query user's position list based on product Description: This API provides the user's asset position list for a specific investment product. ### Request URL POST **`https://web3.okx.com/api/v5/defi/user/investment/asset-detail`** ### Request parameter | Parameter name | Description | Parameter type | Required | Data type | | -------------- | ----------- | -------------- | -------- | --------- | | address | User wallet address | Request body | Yes | String | | chainId | Public chain ID | Reques | No | String | | investmentId | Investment ID (investmentId and poolId cannot be empty at the same time), refer to [here](defi-api-reference-explore-protocol-list) | Request body | Yes | String | | poolId | ID required for BRC-20 type investment (investmentId and poolId cannot be empty at the same time) | Request body | No | String | | farmInvestmentId | ID of Farm-type investment to check if it can be used for mining (only required for Uni-V3 type investments) | Request body | No | String | ### Response parameters | Parameter name | Description | Data type | |---------------------|------------------------------------------------------------|---------------| | investmentName | Investment name | String | | investmentId | Investment ID | String | | sourceInvestmentId | Source investment ID | String | | investType | Investment type: (1: Save; 2: Pool; 3: Farm; 4: Vaults; 5: Stake) | String | | investName | Investment category name: (1: Save; 2: Pool; 3: Farm; 4: Vaults; 5: Stake) | String | | assetsTokenList | List of asset tokens | Array[Struct] | | >tokenSymbol | Token symbol | String | | >tokenAddress | Token contract address | String | | >tokenPrecision | Token precision | String | | >coinAmount | Token quantity | String | | >currencyAmount | Token value in USD | String | | rewardDefiTokenInfo | Comprehensive redemption list | Array[Struct] | | >baseDefiTokenInfos | Information of base tokens | Array[Struct] | | >>tokenSymbol | Token symbol | String | | >>tokenAddress | Token contract address | String | | >>tokenPrecision | Token precision | String | | >>coinAmount | Token quantity | String | | >>currencyAmount | Token value in USD | String | | >>network | Token network | String | | >rewardType | Redemption type: (1: Public; 2: Redeemable; 3: Airdrop; 4: Bonus) | String | | totalValue | Value in USD | String | ### Request example ```shell curl --location 'https://web3.okx.com/api/v5/defi/user/investment/asset-detail' \ --header 'OK-ACCESS-KEY: 9c****77' \ --header 'OK-ACCESS-PASSPHRASE: p****d' \ --header 'Content-Type: application/json' \ --data '{ "address":"0x7f****da", "investmentId":"15299", "chainId":"137" }' ``` ### Response example ```json { "code": 0, "msg": "", "data": [ { "investmentName": "Curve LP peUSD-USDC.e", "investmentId": "21670", "sourceInvestmentId": "21668", "investType": "3", "investName": "Farm", "assetsTokenList": [ { "tokenSymbol": "peUSDUSDC-f", "tokenAddress": "0x1e2ebe2fffa7c9fa83486188f7c19f9acd1bb990", "tokenPrecision": "18", "coinAmount": "2.691174106339194701", "currencyAmount": "2.61869989433167351725360102089837" } ], "rewardDefiTokenInfo": [ { "baseDefiTokenInfos": [ { "tokenSymbol": "esLBR", "tokenAddress": "0x73b1988a3336208e55275c52fac7f5d3a7dfb89f", "network": "ARB", "tokenPrecision": "18", "coinAmount": "0.002555136460646101", "currencyAmount": "0.00307009284288151737625793354325", "buttonType": "0" } ], "buttonType": "3", "rewardType": "1" } ], "totalValue": "2.62176998717455503462985895444162" } ] } ``` - [Query user’s balance list](https://web3.okx.com/onchainos/docs/waas/defi-api-reference-personal-query-balance.md) {/* api-page */} # Query user’s balance list Description: This API provides the user’s balance list. ### Request URL POST **`https://web3.okx.com/api/v5/defi/user/balance-list`** ### Request Parameter | Parameter name | Description | Parameter type | Required | Data type | | ---------------- | ------------------------------------------ | -------------- | -------- | ---------------- | | chainId | Public chain ID | Request body | Yes | String | | address | User wallet address | Request body | Yes | String | | tokenAddressList | List of token smart contracts | Request body | Yes | Array[String] | ### Response parameter | Parameter name | Description | Data type | | --------------- | ------------------------------------------ | ----------- | | tokenSymbol | Token symbol | String | | tokenName | Token name | String | | tokenLogo | Token logo URL | String | | tokenAddress | Token contract address | String | | network | Token network | String | | chainId | Chain ID | String | | tokenPrecision | Token precision | String | | isBaseToken | Whether it is a base token | Boolean | | coinAmount | Token quantity | String | | currencyAmount | Token value in USD | String | | browserUrl | Token OKlink URL | String | ### Request example ```shell curl --location 'https://web3.okx.com/api/v5/defi/user/balance-list' \ --header 'OK-ACCESS-KEY: 9c****77' \ --header 'OK-ACCESS-PASSPHRASE: p****d' \ --header 'Content-Type: application/json' \ --data '{ "chainId": "1", "address": "0xa0****48", "tokenAddressList": [ "0x6b175474e89094c44da98b954eedeac495271d0f", "0xdac17f958d2ee523a2206206994597c13d831ec7" ] }' ``` ### Response example ```json { "code": 0, "msg": "", "data": [ { "tokenSymbol": "DAI", "tokenName": "Dai Stablecoin", "tokenLogo": "https://static.coinall.ltd/cdn/wallet/logo/icon_custom_default_D.png", "tokenAddress": "0x6b175474e89094c44da98b954eedeac495271d0f", "network": "ETH", "chainId": "1", "tokenPrecision": "18", "isBaseToken": false, "coinAmount": "4.309755677978655097", "currencyAmount": "4.310735082243589184287938931547", "browserUrl": "https://www.oklink.com/eth/token/0x6b175474e89094c44da98b954eedeac495271d0f" }, { "tokenSymbol": "USDT", "tokenName": "Tether USD", "tokenLogo": "https://static.coinall.ltd/cdn/wallet/logo/icon_custom_default_U.png", "tokenAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7", "network": "ETH", "chainId": "1", "tokenPrecision": "6", "isBaseToken": false, "coinAmount": "43.628705", "currencyAmount": "43.644922800365259359125", "browserUrl": "https://www.oklink.com/eth/token/0xdac17f958d2ee523a2206206994597c13d831ec7" } ] } ``` - [Query user’s redemption application list](https://web3.okx.com/onchainos/docs/waas/defi-api-reference-personal-invest-unstake-list.md) {/* api-page */} # Query user’s redemption application list Description: This API provides a list of redemption applications made by the user for a specific investment product, including the principal and bonus that can be redeemed. Currently supported protocols include Ankr, Benqi, Stader, Lido, and Tranchess. ### Reauest URL GET **`https://web3.okx.com/api/v5/defi/user/investment/unstake-list`** ### Request parameter | Parameter name | Description | Parameter type | Required | Data type | | -------------- | ----------- | -------------- | -------- | --------- | | investmentId | Investment ID (refer to [here](defi-api-reference-explore-protocol-list)) | Request body | Yes | String | | userAddress | User wallet address | Request body | Yes | String | ### Response parameters | Parameter name | Description | Data type | | ------------------ | ----------- | --------- | | userAddress | User wallet address | String | | investmentId | Investment ID | String | | canClaimAll | Whether all can be claimed | Boolean | | coinAmount | Total coin amount | String | | currencyAmount | Total token value in USD | String | | rewardTokenInfos | Reward token information | Array[Struct] | | > rewardType | Reward type | String | | > claimIndex | Claim index | String | | > tokenSymbol | Token symbol | String | | > tokenLogo | Token logo URL | String | | > tokenAddress | Token contract address | String | | > network | Token network | String | | > tokenPrecision | Token precision | String | | > coinAmount | Token quantity | String | | > currencyAmount | Token value in USD | String | | > rewardDescription| Reward description | String | | > rewardTip | Reward tip | String | ### Request example ```shell curl --location 'http://web3.okx.com/api/v5/defi/user/investment/unstake-list?investmentId=10005&userAddress=0x7f****da' \ --header 'OK-ACCESS-KEY: 90****d6' \ --header 'OK-ACCESS-PASSPHRASE: p****d' \ ``` ### Response example ```json { "code": 0, "msg": "", "data": { "userAddress": "0x7f****da", "investmentId": 10005, "canClaimAll": false, "coinAmount": "3.545420552003607329", "currencyAmount": "1.574166725089601654076", "rewardTokenInfos": [ { "rewardType": 2, "claimIndex": "0", "tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "network": "AVAX", "tokenSymbol": "AVAX", "tokenLogo": "https://static.coinall.ltd/cdn/wallet/logo/AVAX.png", "tokenPrecision": "18", "coinAmount": "2.393874828838042349", "currencyAmount": "1.062880424004090802956", "buttonType": 3, "rewardDesc": "By tapping Claim, you’ll redeem sAVAX", "rewardTip": "This number refers to the amount of AVAX you can claim. According to the protocol, you’ll claim sAVAX as the claim time is overdue." }, { "rewardType": 2, "claimIndex": "1", "tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "network": "AVAX", "tokenSymbol": "AVAX", "tokenLogo": "https://static.coinall.ltd/cdn/wallet/logo/AVAX.png", "tokenPrecision": "18", "coinAmount": "1.004954892370271051", "currencyAmount": "0.446199972212400346644", "buttonType": 3, "rewardDesc": "By tapping Claim, you’ll redeem sAVAX", "rewardTip": "This number refers to the amount of AVAX you can claim. According to the protocol, you’ll claim sAVAX as the claim time is overdue." }, { "rewardType": 3, "claimIndex": "2", "tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "network": "AVAX", "tokenSymbol": "AVAX", "tokenLogo": "https://static.coinall.ltd/cdn/wallet/logo/AVAX.png", "tokenPrecision": "18", "coinAmount": "0.146590830795293929", "currencyAmount": "0.065086328873110504476", "buttonType": 2, "rewardDesc": "Est. claimable date: 07/12/23", "rewardTip": "This only refers to the estimated claimable time. The exact time is subject to your actual claim." } ] } } ``` - [Error code](https://web3.okx.com/onchainos/docs/waas/defi-error-code.md) # Error code |Code|HTTP status|Message (EN)|Message (CN)| |---|---|---|---| |0|200|Succeeded|操作成功| |50011|429|Rate limit reached. Please refer to API documentation and throttle requests accordingly. |用户请求频率过快,超过该接口允许的限额。请参考 API 文档并限制请求| |50014|400|Parameter {0} cannot be empty.|必填参数 {0} 不能为空| |50026|500|System error. Try again later.|系统错误,请稍后重试| |50103|401|Request header “OK-ACCESS-KEY” cannot be empty.|请求头“OK_ACCESS_KEY”不能为空| |50104|401|Request header “OK-ACCESS-PASSPHRASE” cannot be empty.|请求头“OK_ACCESS_PASSPHRASE”不能为空| |50105|401|Request header “OK-ACCESS-PASSPHRASE” is incorrect.|请求头“OK_ACCESS_PASSPHRASE”错误| |50106|401|Request header “OK-ACCESS-SIGN” cannot be empty.|请求头“OK_ACCESS_SIGN”不能为空| |50107|401|Request header “OK-ACCESS-TIMESTAMP” cannot be empty.|请求头“OK_ACCESS_TIMESTAMP”不能为空| |50111|401|Invalid OK-ACCESS-KEY|OK_ACCESS_KEY 无效| |50112|401|Invalid OK-ACCESS-TIMESTAMP|OK_ACCESS_TIMESTAMP 无效| |50113|401|Invalid signature|签名无效| |84000|400|Parameter error|参数错误| |84001|200|Platform not supported|不支持的平台| |84003|200|Protocol not supported|不支持的协议| |84007|200|Investment product not supported|不支持的投资品| |84010|200|Token not supported|不支持的币种| |84011|200|Platform logo is empty|平台 logo 为空| |84013|200|Swap not supported|不支持兑换| |84014|200|Balance validation unsuccessful|余额校验失败| |84016|200|Smart contract execution unsuccessful|合约方法执行失败| |84017|200|Staking rate validation unsuccessful|质押率校验失败| |84018|200|Balancing unsuccessful|配平失败| |84019|200|Address format unmatched|地址格式不匹配| |84021|200|Syncing assets|资产同步中| |84022|200|Authorization type not supported|不支持的交易授权| |84998|200|Investment error|投资异常| |84999|500|Default error|默认异常| - [General specification](https://web3.okx.com/onchainos/docs/waas/okx-waas-standard.md) # General specification ## Response structure **Success** ```json { "code": 0, // success code "msg": "success", // success message "data": [] } ``` **Failure** ```json { "code": 1, // error code "msg": "error", // error message } ``` - [Apply to display DApps](https://web3.okx.com/onchainos/docs/waas/walletapi-resources-dapp-application.md) # Apply to display DApps Many Web3 users find it a headache to search for their favorite DApps using tools like Google search engine, but fear not, OKX is here to offer a solution. We've integrated the most used DApps into our Web3 service. Users can enjoy a seamless experience with our latest built-in search tool. Jump into your favorite DApps and hit the ground running with Discover on OKX Web3, a service built to be your gateway to Web3. If you want to list your DApp on Discover, you need to fill in our form to [build with us](https://forms.gle/kLwVFevWXBjRa6WC6). For info on product promotions, please get in touch with [wallet@okx.com](mailto:wallet@okx.com) - [App Universal Link](https://web3.okx.com/onchainos/docs/waas/app-universal-link.md) # App Universal Link To enable users to easily interact with your DApp within a mobile app, you need to create a deep link in the mobile browser that directs them to the Discover page in the OKX App, where your DApp will be opened. This tutorial will guide you through the process using JavaScript. ### Step 1: Define the deep link parameters Open your JavaScript file or script, and define the URL you want to pass as a parameter in your deep link: ```javascript const dappUrl = "https://app.uniswap.org/"; ``` Replace `https://app.uniswap.org/` with the actual URL of your DApp. ### Step 2: Encode the deep link parameters Use `encodeURIComponent` to encode the `dappUrl`: ```javascript const encodedDappUrl = encodeURIComponent(dappUrl); ``` This ensures that special characters in the URL are properly handled for inclusion in a web link. ### Step 3: Construct the deep link Combine the encoded parameters to form the deep link: ```javascript const deepLink = "okx://wallet/dapp/url?dappUrl=" + encodedDappUrl; ``` This creates a deep link specific to your DApp on the OKX platform. ### Step 4: Encode entire URL Encode the entire URL, including the deep link, to ensure proper formatting for web applications: ```javascript const encodedUrl = "https://web3.okx.com/download?deeplink=" + encodeURIComponent(deepLink); ``` This results in the final encoded URL that users will interact with. ### Step 5: Output or use You can print the `encodedUrl` to the console or use it as needed in your application: ```javascript console.log(encodedUrl); ``` This line is for demonstration purposes; in your actual application, you would use the `encodedUrl` as required. ### Testing: This JavaScript code is a client-side script that checks the user's device and environment to determine whether the user is accessing a web page from a mobile device, specifically an iOS or Android device, or whether they are using the OKX app. ```javascript const ua = navigator.userAgent; const isIOS = /iphone|ipad|ipod|ios/i.test(ua); const isAndroid = /android|XiaoMi|MiuiBrowser/i.test(ua); const isMobile = isIOS || isAndroid; const isOKApp = /OKApp/i.test(ua); if (isMobile && !isOKApp){ const encodedUrl = "https://web3.okx.com/download?deeplink=" + encodeURIComponent("okx://wallet/dapp/url?dappUrl=" + encodeURIComponent(location.href)); window.location.href = encodedUrl; } else if (window.okxwallet) { const accounts = await window.okxwallet.request({ method: "eth_requestAccounts", }); } ``` ### Summary By following these steps, you have successfully created a deep link for your DApp within the Discover page of the OKX app. This link, when used, will seamlessly guide users to your DApp, opening up OKX Web3's millions of traffic to your DApp. - [Changelog](https://web3.okx.com/onchainos/docs/waas/changelog.md) # Changelog ### March 12, 2025 Update - Single-chain swaps now support the Sonic chain. ### March 6, 2025 Update - The single-chain swap interface now supports collecting positive slippage. You can enable this feature by setting the `enablePositiveSlippage` parameter. ### February 11, 2025 Update - The single-chain swap interface now supports the `/swap-instruction` endpoint on the Solana chain, allowing you to customize transaction instructions. ### January 23, 2025 Update - The single-chain swap API now supports specifying a single liquidity pool for swaps. You can achieve this by setting the `directRoute` parameter. - The single-chain swap API now supports the Transaction querying feature. ### December 26, 2024 Update - The single-chain swap API now supports an automatic slippage feature. ### November 25, 2024 Update - The single-chain swap API parameter `swapReceiverAddress` now supports the Solana chain. It is now possible to specify a different recipient address for a swap transaction on the Solana chain. ### November 12, 2024 Update - Added a new referral wallet address parameter for the single-chain swap API. Both Sol and SPL tokens now support direct use of wallet addresses for referral fee collection. - APIs for retrieving the single-chain liquidity list and the cross-chain bridge list now support protocol logos. - Single-chain quote and swap APIs now recognize and return risk tokens with honeypot mechanisms or tokens with 100% buy/sell tax. ### October 29, 2024 Update - Single-chain swaps now support the Sui chain. ### July 1, 2024 Update - The ETH dexRouter contract 0xf3de3c0d654fda23dad170f0f320a92172509127 will no longer function normally after August 1, 2024. Please switch to the latest version. ### June 19, 2024 Update - Swap API DEX Router eth contract address update ### May 7, 2024 Update - Solana mainnet supports commission-sharing ### April 19, 2024 Update - Cross-chain swap support SUI chain ### April 19, 2024 Update - Cross-chain swap support X Layer chain ### April 12, 2024 Update - Cross-chain slippage request parameter range adjusted to 0.002-0.5 - Cross-chain swap support Merlin chain ### April 12, 2024 Update - Added new response parameters (quoteCompareList) to DEX swap endpoint ### April 8, 2024 Update - Added new response parameters (toTokenReferrerAddress) to DEX swap endpoint ### April 2, 2024 Update - Updated DEX swap trading support Merlin Chain ### March 22, 2024 Update - Added new response parameters (callDataMemo) to DEX swap endpoint ### March 22, 2024 Update - Added new request parameters (sort) to cross-chain Get route information and Cross-chain swap endpoint - DEX XBridge contract address update ### March 13, 2024 Update - Added new response parameters (sourceChainGasfee, destinationChainGasfee, crossChainFee) to cross-chain Get transaction status endpoint - Added new request parameters (onlyBridge) and new response parameters (minmumReceive,maxPriorityFeePerGas) - Cross-chain API Smart contract part added cross-chain contract address (DEX XBridge contract address) - Cross-chain API added new Get the list of tokens supported by the cross-chain bridges endpoint ### March 07, 2024 Update - Added new request parameters (priceImpactProtectionPercentage) to Cross-chain & Single-chain swap endpoint ### February 29, 2024 Update - Added new response parameters (decimal) to DEX swap endpoint ### February 22, 2024 Update - Added new response parameters (maxPriorityFeePerGas) to DEX swap endpoint ### February 01, 2024 Update - Updated DEX swap trading support solana, added new request parameters (solTokenAccountAddress) - Added DEX swap trading support solana quick start ### January 17, 2024 Update - Added new request parameters (feePercent, referrerAddress) to Cross-chain swap endpoint ### January 11, 2024 Update - Cross-chain slippage range adjusted to 0.005-0.5 ### January 02, 2024 Update - Added new request parameters (receiveAddress) to Cross-chain swap endpoint - Added new request parameters (chainld) to cross-chain Get transaction status endpoint ### December 28, 2023 Update - Launched the first edition of OKX Web3 DeFi API documentation - Added functionality for investment, redemption, and reward claiming processes via DeFi API - Added methods for querying information, calculating estimated data, generating transaction data, and querying user information ### December 20, 2023 Update - Added new response parameters (crossChainFeeTokenAddress) to cross-chain Get route information endpoint and Cross-chain swap endpoint - Added new response parameters (status) to cross-chain Get transaction status endpoint ### December 14, 2023 Update - Added DEX Iframe ### December 14, 2023 Update - Added new optional parameter (swapReceiverAddress) to DEX swap interface ### December 08, 2023 Update - Added DEX limit order list query - Added DEX limit order get cancellation calldata ### December 06, 2023 Update - Added new response parameters (toDexRouterList) to cross-chain Get route information endpoint - Added new response parameters (toAmount, errorMsg) to cross-chain Get transaction status endpoint - Added cross-chain refund issues to cross-chain FAQ ### November 24, 2023 Update - The Order API has been expanded with a new listing module, enabling listings on OpenSea and OKX. - Added more detailed description to order structure ### November 23, 2023 Update - Added DEX cross-chain API quick start guidelines ### November 21, 2023 Update - Added DEX cross-chain API quick start guidelines ### November 15, 2023 Update - Added new response parameters (crossChainFee) to cross chain Get route information endpoint cross-chain/quote - Added new response parameters (crossChainFee) to cross chain Cross-chain swap endpoint cross-chain/quote ### November 10, 2023 Update - Added DEX API quick start guidelines ### November 7, 2023 Update - Added DEX cross-chain aggregator API ### October 31, 2023 Update - Added DEX limit order API ### October 23, 2023 Update - Added smart contract information, including contract addresses and ABI ### September 27, 2023 Update - Updated the content of integrating DApps with OKX Wallet on the mobile app - Added guide and sub pages for integrating DApps with OKX Wallet on the mobile app
### August 17, 2023 Update - Updated the API key authentication mechanism. Moving forward, all endpoints will require an API key generated from the Web3 developer portal. - Updated the URI of all endpoints to reflect the latest versioning - Updated error codes Update - Added API key authentication. Moving forward, all endpoints will require an API key generated from the Web3 developer portal - Updated error codes Update - Updated the API key authentication mechanism. Moving forward, all Web3 API endpoints will require an API key generated from the Web3 developer portal - Updated the URI of all endpoints to reflect the latest versioning
### May 29, 2023 Update - Added new BRC-20 endpoint: ``brc20/token-list`` - Added new response parameters (index, location) to BRC-20 endpoint ``brc20/transaction-list`` - Added new response parameters (location) to BRC-20 endpoint ``brc20/inscriptions-list``
- [OKX Web3 Build User Agreement](https://web3.okx.com/onchainos/docs/waas/legal.md) # OKX Web3 Build User Agreement Last updated: November 28, 2023 This [OKX Web3 Build User Agreement]((https://web3.okx.com/help/okx-web3-build-user-agreement)) (this “Agreement”) constitutes an agreement between you, as a developer (“Developer”,“User” or “you”) and the service provider, OKX Technology Services Pte. Ltd., a Singapore registered company (“we”, “us” or “our” or “OKX”), and any of our affiliates, regarding your access and/or use of the OKX Web3 Build Services (collectively, the “Services”). By using our Services, you confirm that you have read, understood and accepted this Agreement, our [OKX Web3 Ecosystem Terms of Service](https://web3.okx.com/help/okx-web3-ecosystem-terms-of-service) (the “Terms of Service”), our [OKX Web3 Ecosystem Privacy Notice Statement](https://web3.okx.com/help/okx-web3-ecosystem-privacy-policy), and any and all other rules or policies, and you shall be legally bound by any and all of these terms and conditions regardless of your location, nationality, and/or Service(s) used. If you do not agree to be bound by this Agreement, please do not access or use the Services. This Agreement shall supplement our Terms of Service. In the event of any conflict or inconsistency of any term or provision set forth in this Agreement, our Terms of Service, such conflict or inconsistency shall be resolved by giving precedence first to this Agreement. All other provisions of our OKX Terms of Service not modified by this Agreement shall remain in full force and effect. Separate user terms and licenses may be made available by OKX from time to time which may supplement this Agreement but as an integral part of this Agreement for the provision of the Services. 1. OUR SERVICES 1.1 Our Services. The Services provides various tools, products and services for Developers to build and create personalised Web3 Ecosystem, products and/or services. Users would be able to build their own decentralized applications and programs that exist and run on a blockchain technology or peer-to-peer network (“Dapps”) by connecting their digital wallets through Third Party Blockchains. The Services provides various features in relation to Web3 infrastructure for wallets, liquidity and on-chain data via application programming interfaces ("API"). Some of the Services may be provided in the form of a Software Development Kit ("SDK"). However, OKX merely provides an interface for Users to connect to the tools, and is not a party to any transactions made through the Services. Our Services provide Developers with a full-stack of Web3 infrastructure for wallets, liquidity and on-chain data, helping Developers to develop and build their Dapps and other products and services. The Services are solely provided to Developers for development use and they are not intended for re-distribution, re-sale or any other purposes outside the scope of this Agreement. 1.2 Service Details. The Services aggregates the following tools and solutions for Developers to access and build their Web3 ecosystem, products and services: Web3 Infrastructure Suite; Wallet as a Service (WaaS) Solution; Liquidity Solution; ZK-powered ETH L2; and/or other tools and solutions made available by OKX from time to time OKX provides an all-in-one developer portal serving as a streamlined API management and monitoring hub for seamless control and optimization. 1.3 API, SDK and Solutions. Each API, SDK and solutions provided under the Services shall be subject to separate API documentation, user terms and conditions, end user licenses, among other things, for access and use by Users which shall be made available by OKX from time to time. For accessing and using the API, the passphrase that you have created to generate and access your API key is confidential to you and not accessible by OKX. If you lose your passphrase, you will lose access to your API key. You shall agree and undertake to keep your passphrase, and API key strictly confidential and not share it with any third party. You agree that you will be solely liable and responsible for the use of your API key and the security of your passphrase. 1.4 Use of Digital Wallet Is Required. In order to use the Services, you may have to connect a digital wallet such as an OKX Web3 Wallet. You are solely responsible for any Losses that may arise from your use of your digital wallet through the course of the Services. Your digital wallet is not accessible to OKX, and we will not keep or maintain your files, passwords, Mnemonic Phrases, and/or Private Keys for your digital wallet. OKX is not responsible, and you are solely responsible, for any transactions executed by or involving your digital wallet, regardless of whether you have approved or authorised such transactions. 1.5 Purpose and Legality of Use. You agree that you shall use your Services for legitimate purposes only, and you shall not have the intention of using the Services as a medium of non-compliance to Applicable Laws. You agree that the Digital Assets deposited into your digital wallet did not arise from a violation of Applicable Laws. You also agree to abide by all rules, terms, and any other notices or relevant agreements published and updated by OKX from time to time, including announcements, procedural instructions, risk disclosures, and other rules and terms. 1.6 Password and Private Key. Our Services have various decentralized characteristics of blockchain technology. These decentralized services are different from banking financial institutions. You understand and accept that OKX is not responsible for the following: storage of your security Password (which is the Password you set when you created or imported your digital wallet); Private Key and Mnemonic Phrase; retrieval of your security Password, Private Key, or Mnemonic Phrase; freezing of your wallet; reports of lost wallet; restoration of your wallet or any other actions required to maintain or access your wallet. 1.7 Prototype. You agree and accept that the Service is an early version of the products and/or services, and not yet fully audited. OKX is not responsible for any Losses you may experience, nor is OKX under any obligation to compensate or indemnify any loss Digital Assets to you, in connection with use of any such prototype products or services. 2. SERVICE FEES 2.1 Gas Fees. During the course of your access and use of the Services, you may incur various gas fees. Gas fees generated on any Third Party Blockchains under these Services will be paid by you. 2.2 Third Party Protocol Fees. There may also be other Third Party Platform fees ("Third Party Fees") that arise during your access and use of the Services, including but not limited to transaction fees for transactions of Digital Assets, NFTs and/or other digital collectibles on Dapps and registration fees for Events. You are solely responsible for paying any and all of these Third Party Fees that may arise. 2.3 Service Fees. Please note that OKX does not currently charge any fees (“Service Fees”), but we reserve the right to charge you Service Fees in the future. OKX may charge you certain Service Fees for providing the Services to you. Any Service Fees schedule shall be published on OKX platform from time to time, and OKX reserves the rights to update such fee schedule, if any, in its sole discretion. 3. OWNERSHIP RIGHTS 3.1 General. The Services contain Information and links from Third Party Platforms that redirect Users to the webpages, web applications, mobile application, application program interface, or any associated site linking to web and mobile applications of Third Party Platform. 3.2 Limited Right to Use. OKX does not claim any ownership rights in any content that you provide to be made available through the Services (“User Content”). You agree that you own and have all rights, title and interest, including all intellectual property rights, in any User Content you provide to us. You hereby grant OKX a worldwide, royalty-free license to use, copy and display any User Content that you upload, submit, store and/or send on or through your access and use of the Services (which may include any rights regarding creation or use that you have agreed to). 3.3 Intellectual Property Rights. During the term of the provision of Services to you by OKX, you may have access to OKX's proprietary information and intellectual property rights through accessing the Services, and any materials that may contain copyrightable work, know-how, patentable information, confidential information, among other things, that may be specified by OKX for your use as a developer solely to create and use for your projects, products and services, in accordance with this Agreement and any other API documentation, user terms and conditions, end user licenses, and instructions as OKX may make available to you from time to time. You may not use such materials or information for re-distribution, re-sale or any other purposes without OKX’s prior written approval. 3.4 OKX Trade Marks and IPs. OKX’s trade marks (including, but not limited to the “OKX”, “OKX logo”, “X logo” trade marks), service marks, trade dress, logos and any other indicia of the source of OKX’s goods or services (“OKX Trade Marks”) and intellectual property rights are all the property of OKX and its affiliates. Your limited right to use the OKX Trade Marks in connection with the Services does not give you any right, title or ownership interest with respect to the OKX’s Trade Marks. All goodwill arising from your use of the OKX Trade Marks in connection with this Agreement will insure to the sole and exclusive benefit of OKX. OKX reserves the right to terminate your permission to use the OKX Trade Marks or any intellectual property rights at any time in its sole discretion. 4. ADDITIONAL RISK DISCLOSURES 4.1 No Guarantee of Specific Timing. You understand and agree that when a user redeem or access your Digital Assets, the time it actually takes to receive the Digital Assets into a digital wallet may vary, and the Digital Assets received and displayed on the digital wallet shall be final. OKX is not liable for any Losses as a result of the forementioned. 4.2 Limit of Aggregated Liability. You understand and agree that OKX’s aggregated liability shall not exceed the Service Fees OKX received from you. 4.3 Amendment of the Agreement. You understand and agree that OKX reserves the right to amend the content of this Agreement at any time in its sole discretion. OKX shall not be liable for any Losses arising from your misunderstanding of the Agreement or your delay of reading any amendments or updates to this Agreement. 4.4 Wrong Address. OKX is not responsible for any Losses resulting from sending Digital Assets to the wrong address(es). You shall ensure your deposit of your Digital Assets are to the right address designated by OKX to receive your Digital Assets to be transferred to the Third Party Blockchain through your use of the Services. You shall provide a correct address of your digital wallet that you use to receive your Digital Assets to be transferred from the Third Party Blockchain through use of the Service. OKX shall not be liable for any and all Losses resulting from your own fault or error, including but not limited to: you providing an incorrect address of your digital wallet or other address for receiving Digital Assets, or you transferring your assets to a wrong address instead of the address designated by OKX. 4.5 User Fault or Error. You agree that you shall bear any and all Losses resulting from your own fault or error, including but not limited to: not being in accordance with the transaction prompts operation, not conducting timely transactions via our Services, transferring your Digital Assets to a wrong Third Party Blockchain or wrong address, forgetting or leakage of Passwords and/or Private Keys, cracked Passwords, your computer being invaded or hacked by others, and/or entering into the wrong address to transfer or receive Digital Assets. 4.6 Third Party Content and Services. You understand and agree that when you use the Services, you may access and use Third Party Blockchains. OKX shall not be liable for any and all Losses caused by your use of or access to Third Party Blockchains. You understand and agree to OKX’s grant of access to any and all Third Party Blockchains. OKX merely provides project display, revenue distribution, and other related services. OKX shall not be liable for any Losses incurred as a result of contract vulnerabilities; hacking incidents; suspension, discontinuation, or termination of business; bankruptcy; abnormal suspension; or cessation of Third Party Blockchain operations or other potential risks. Furthermore, you agree to bear any and all Losses you may suffer as a result of the aforementioned risks. If you suffer any Losses as a result of the aforementioned risks, you understand and agree that any Digital Assets that may be stored on your digital wallet may be permanently lost. The Service may also contain links or functionality to access or use third-party websites (“Third-Party Websites”) and applications (“Third-Party Applications”), or otherwise display, include, or make available content, data, information, services, applications, or materials from third parties (“Third-Party Materials”). Any links of Third-Party Websites in the Services do not mean that OKX endorses any products, services, information and disclaimers provided therein, and OKX does not guarantee the accuracy of the information contained therein. When you click on a link to, or access and use, a Third-Party Website or Third-Party Application, though we may not warn you that you have left our Services, you are subject to the terms and conditions (including privacy policies) of another website or destination. Such Third-Party Websites, Third-Party Applications, and Third-Party Materials are not under the control of OKX, and may be “open” applications for which no recourse is possible. OKX is not responsible or liable for any Third-Party Websites, Third-Party Applications, and Third-Party Materials. OKX provides links to these Third-Party Websites and Third-Party Applications only as a convenience and does not review, approve, monitor, endorse, warrant, or make any representations with respect to Third-Party Websites or Third-Party Applications, or their products or services or associated Third-Party Materials. You use all links in Third-Party Websites, Third-Party Applications, and Third-Party Materials at your own risk. OKX shall not be liable for any Losses caused by your use of such third party products and services on Third-Party Websites and Third-Party Applications. OKX and each Third-Party Website and Third-Party Application are independent legal entities, and this Agreement shall not constitute any form of agency, partnership or cooperative relationship between the parties. OKX and each Third-Party Website and Third-Party Application shall be responsible for their respective claims, debts and disputes arising from the performance of their respective contracts and agreements. 4.7 Third Party Blockchain Malfunctions. You understand and agree that if OKX or any Third Party Blockchain(s) cannot function properly or the Services are interrupted because of the following conditions, and you are unable to use the Services or cannot make commands or perform related operations or transactions, including without limitation, failure, delay, interruption, system lack of response, delayed system response, or any other abnormal and/or unexpected circumstances, OKX shall not be liable for any Losses. These circumstances include but are not limited to: Third Party Blockchain(s) suspends, discontinues, and/or terminates its business, closes down, and/or abnormally suspends or terminates the Services; service suspension due to maintenance as announced by OKX or Third Party Blockchain; system fails to transmit data; Force Majeure event(s) that lead to the suspension of the third Party Blockchain; Third Party Blockchain’s service interruption or delay arising from hacking, computer viruses, technical adjustments or failure, website upgrades, banking issues, temporary closures arising from legal or government regulations; etc.; Third Party Blockchain’s service interruption or delay caused by its computer system being damaged, defective or unable to normally perform; Losses arising from technical problems that cannot be predicted or solved by existing technology in the industry; Losses you or other third parties suffer that arise from the fault or delay of the third party; Losses you or other third parties suffer that arise from changes in laws, regulations and/or government orders; Losses you or other third parties suffer that arise from Force Majeure events caused by unforeseeable, unavoidable, and/or unsolvable objective circumstances. You understand and agree that the forementioned reasons may lead to abnormal transactions, price fluctuation, market fluctuation, market interruptions, and other possible abnormal circumstances. You also appreciate that the risk disclosure statement herein is not and cannot be comprehensive or exhaustive. OKX may refuse to execute your commands based on the actual circumstances. Furthermore, you understand and agree that OKX shall not be liable for any Losses arising from or related to any of the forementioned circumstances. 4.8 Losses Based on Your Lack of Eligibility. You understand and accept that OKX shall not be liable for any Losses caused by any risks relating to your eligibility to access or use our Services. 5. PROHIBITED PRACTICES 5.1 No Unfair Trading Practices. You understand and agree that OKX strictly prohibits unfair trading practices. OKX reserves the right to refuse, suspend or terminate the provision of our Services to you, if you perform or are reasonably suspected to be performing the following actions when accessing or using our Services: market manipulation, price manipulation, insider dealing, market distortion or any other malicious wrongdoings or market behaviours; harming OKX or other Users through loopholes, unreasonable means, other types of flaws or vulnerabilities on our Services; violation or attempt to violate other User’s legal rights (including but not limited to their privacy and intellectual property rights); participation in any activities that OKX regards as harmful to the market, OKX and/or our Services; violation of any Applicable Laws. 5.2 OKX’s Rights. In order to minimize and/or eliminate any adverse effects on the overall market, OKX reserves the right to take the following measures at its sole discretion, including without limitation, suspending or closing down of your account, restricting or cancelling your commands, contacting and cooperating with relevant legal and/or regulatory authorities. You understand and agree that OKX shall not be liable for any Losses (including without limitation to any direct or indirect Losses, actual Losses or Losses of possible profits) that you may incur in connection with the above measures. 6. WARRANTIES 6.1 GENERAL. THE SERVICES ARE PROVIDED “AS IS.” TO THE EXTENT PROHIBITED BY APPLICABLE LAW, OR TO THE EXTENT ANY STATUTORY RIGHTS APPLY THAT CANNOT BE EXCLUDED, LIMITED OR WAIVED, OKX AND ITS AFFILIATES AND LICENSORS (A) MAKE NO REPRESENTATIONS OR WARRANTIES OF ANY KIND, WHETHER EXPRESS, IMPLIED, STATUTORY OR OTHERWISE REGARDING ANY SERVICE, OUR CONTENT, THE THIRD PARTY CONTENT, OR THE THIRD PARTY SERVICES, AND (B) DISCLAIM ALL WARRANTIES, INCLUDING ANY IMPLIED OR EXPRESS WARRANTIES (I) OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR QUIET ENJOYMENT, (II) ARISING OUT OF ANY COURSE OF DEALING OR USAGE OF TRADE, (III) THAT THE SERVICES, OUR CONTENT, THIRD PARTY CONTENT, OR THIRD PARTY SERVICE WILL BE UNINTERRUPTED, TIMELY, ERROR-FREE OR FREE OF HARMFUL COMPONENTS, AND (IV) THAT ANY CONTENT OR DIGITAL ASSET WILL BE SECURE OR NOT OTHERWISE LOST OR ALTERED. YOU ACKNOWLEDGE AND AGREE THAT YOU HAVE NOT RELIED AND ARE NOT RELYING UPON ANY REPRESENTATION OR WARRANTY FROM OKX THAT IS NOT IN THESE TERMS OR IN A SEPARATE WRITTEN AGREEMENT BETWEEN OKX AND YOU, AND YOU AGREE YOU WILL NOT TAKE A POSITION IN ANY PROCEEDING THAT IS INCONSISTENT WITH THIS CLAUSE. 7. LIMITATION OF LIABILITY AND INDEMNIFICATION You will indemnify, defend, and hold harmless OKX, our affiliates, and our and their respective officers, directors, employees, and agents from and against any Losses relating to or in connection with any third party claim relating to your use of the Services, your breach of this Agreement, or your User Content. OKX’s aggregated liability in connection with this Agreement shall not exceed the greater of (a) $100 US dollars or (b) the Service Fees OKX received from you in the past twelve months. NOTWITHSTANDING ANYTHING TO THE CONTRARY IN THESE AGREEMENT, OKX WILL NOT BE LIABLE FOR ANY INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, HOWEVER IT ARISES (INCLUDING ATTORNEYS’ FEES AND ALL RELATED COSTS AND EXPENSES OF LITIGATION AND ARBITRATION, OR AT TRIAL OR ON APPEAL, IF ANY, WHETHER OR NOT LITIGATION OR ARBITRATION IS INSTITUTED), WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, INCLUDING WITHOUT LIMITATION ANY CLAIM FOR PERSONAL INJURY OR PROPERTY DAMAGE, ARISING FROM THIS AGREEMENT OR ANY FEDERAL, STATE, OR LOCAL LAWS, STATUTES, RULES, OR REGULATIONS, EVEN IF OKX HAS BEEN PREVIOUSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF SUCH DAMAGES, SO THE PRIOR LIMITATION OR EXCLUSION MAY NOT APPLY TO YOU. 8. GOVERNING LAW 8.1 General. This Agreement, your use of the Services, any claim, counterclaim or dispute of any kind or nature whatsoever arising out of this Agreement (“Dispute”), directly or indirectly, shall be governed by, and construed in accordance with the laws of England and Wales without regard to the principles of conflicts of laws thereof. 9. JURISDICTION AND DISPUTE RESOLUTION 9.1 Dispute Resolution Method. You acknowledge and agree that in the event of any Dispute, the parties shall first refer the Dispute to proceedings at the Hong Kong International Arbitration Centre (“HKIAC”) in accordance with HKIAC’s Mediation Rules in force at that time. 9.2 Arbitration Rules and Jurisdiction. If the Dispute has not been settled upon the signing of a settlement agreement within ninety (90) days following the filing of a request for mediation set forth in Clause 9.1, such Dispute shall be referred to and finally resolved by arbitration administered by the HKIAC under the HKIAC Administered Arbitration Rules in force when the Notice of Arbitration is submitted. The law of this arbitration clause shall be the laws of the Hong Kong Special Administrative Region of the People’s Republic of China (“Hong Kong”). The location of any in-person arbitration hearing shall be Hong Kong, unless otherwise agreed to by the parties. 9.3 Arbitration Seats and Language. You agree that the seat of arbitration shall be Hong Kong. The number of arbitrators shall be three (3). OKX shall appoint one (1) arbitrator and you shall appoint one (1) arbitrator. The third arbitrator shall be appointed by the Chairman of the HKIAC. Such arbitrators shall be freely selected, and the parties shall not be limited in their selection to any prescribed list. Any arbitration proceedings shall be conducted in the English language. 9.4 Limited Discovery. You agree that OKX shall not be required to give general discovery of documents, but may be required only to produce specific, identified documents which are relevant and material to the outcome of the Dispute. 9.5 Final and Binding Nature. Any arbitral award shall be final and binding upon the parties hereto and shall be enforceable in any competent court which has jurisdiction. 9.6 No Class Action or Litigation. You agree to resolve any and all Disputes with OKX on an individual basis through arbitration instead of as part of any class action or representative litigation. 9.7 Confidentiality. The parties agree that the arbitration shall be kept confidential. The existence of the arbitration, any non public information provided in the arbitration, and any submissions, orders or awards made in the arbitration (together, the “Confidential Information”) shall not be disclosed to any non-party except the tribunal, the HKIAC, the parties, their counsel, experts, witnesses, accountants and auditors, insurers and reinsurers, and any other person necessary to the conduct of the arbitration. Notwithstanding the foregoing, a party may disclose Confidential Information to the extent that disclosure may be required to fulfil a legal duty, protect or pursue a legal right, or enforce or challenge an award in bona fide legal proceedings. This confidentiality provision shall survive termination of these Terms and of any arbitration brought pursuant to these Terms. 10. GENERAL PROVISIONS 10.1 Acceptance of All Terms and Conditions. By using the Services, you agree that you have read, understood and accepted this Agreement and all relevant transactions and operational rules in connection with the Services, and you agree to be legally bound by the terms and conditions hereof. OKX reserves the right to change or modify this Agreement at any time at its sole discretion and will provide notice of such changes by posting the revised Agreement on the Site and changing the “Last Updated” date herein. If you do not accept the revised Agreement, you will stop accessing or using the Services. Please also carefully read all terms of service, privacy policies, and relevant transactional and operational rules (as amended from time to time) published on the Third Party Platforms. Access and use of the Services is only allowed after you have read, understood, and agreed to all relevant rules and policies. 10.2 Language. If there is a conflict between the English version of this Agreement and the translated version in other languages, the English version shall prevail. OKX shall have the sole and final discretion to interpret this Agreement. ## OKX XLAYER Documentation - [X Layer overview](https://web3.okx.com/xlayer/docs/developer/build-on-xlayer/about-xlayer.md) # X Layer overview X Layer is an Ethereum Layer 2 (L2) network, built by OKX on an enhanced Optimism Stack, designed to provide developers with a superior environment for scaling applications. **Key Developer Advantages** - **Full EVM Equivalence:** Deploy your existing Ethereum applications without any code modifications. - **Exceptional Performance:** Achieve massive scalability with support for up to 5,000 TPS and negligible gas fees. - **Battle-Tested Security:** X Layer leverages the robust optimistic rollup architecture, inheriting the security guarantees of Ethereum, but with a simpler, more efficient operational model than ZK rollups. - **Enterprise-Grade Reliability:** Features like the Conductor high-availability cluster ensure sequencer redundancy, offering 99.9% uptime for your production-ready dapps. ## X Layer architecture The major components of X Layer are: - **Virtual Machine**: EVM‑equivalent - **Sequencer**: Trusted (implemented by op-node in sequencer mode, coordinating with op-geth via Engine API) - **Gas token**: OKB (fixed supply at 21M post-burns/upgrades; L1 OKB phased out) ## Background X Layer has evolved to adopt the Optimism Stack (OP Stack) framework, a battle-tested and widely adopted Layer 2 scaling solution. In this architecture, L2 operates with optimistic assumptions where transactions are considered valid by default, with a 7-day challenge period for fraud proofs. This provides a more efficient and cost-effective solution while maintaining Ethereum's security guarantees through cryptographic fraud proofs when needed. ## Architecture flow (OP Stack + AggLayer mode) **Phase 1: From L1 to L2** Process of bridging assets from ETH to X Layer | Step | Action | Description | |------|--------|-------------| | 1.1 | User Deposit | The user sends assets to the L1 bridge contract. | | 1.2 | Event Sync | The **Bridge Service** monitors (ingests) the L1 contract events. | | 1.3 | L2 Claim/Mint | The Bridge Service sends an L2 transaction (via RPCs) to claim/mint the asset on X Layer. | | 1.4 | Block Inclusion | The **Sequencer** includes this transaction in an L2 block. | | 1.5 | User Update | RPCs expose the updated balance/status to the user. | **Phase 2: Execution and withdrawal back to L1** Standard L2 operations and process of initiating withdrawal back to L1 | Step | Action | Description | |------|--------|-------------| | 2.1 | Withdrawal Tx | The user sends an L2 withdrawal transaction via RPCs. | | 2.2 | Block Generation | The Sequencer continues to generate blocks. | | 2.3 | Data Persistence | The `L2BridgeSyncer` and `L1InfoTreeSyncer` persist chain data and L1 info updates needed for the Pessimistic Proof (PP). | **Phase 3: Cross-Chain Settlement & Proof (AggLayer)** This phase involves proving and finalizing the withdrawal on L1 using the AggLayer. | Step | Action | Description | |------|--------|-------------| | 3.1 | Certificate Prep | The `aggsender` fetches blocks, stores certificate metadata, and performs double-checks. | | 3.2 | Certificate Submission | The `aggsender` submits the certificate to the **AggLayer**. | | 3.3 | ZK Proof Generation | The agglayer-prover generates the ZK proof; the AggLayer submits the certificate proof and public inputs to L1. | | 3.4 | L1 Finality | After **L1 verification**, withdrawals and messages achieve L1 finality (PP is verified). | **Phase 4: Continuous System Synchronization** | Step | Action | Description | |------|--------|-------------| | 4.1 - 4.2 | Continuous Sync | The Bridge Service continuously synchronizes both L2 and L1 contract events to maintain state consistency. | Outcome: Fast execution happens on L2 with 1-second block times. All L2 data is published to L1, ensuring the system is fully trustless and censorship-resistant. This flow ensures immediate transaction finality on L2 for most operations while providing cryptographic security for cross-chain operations through the optimistic rollup model. - [Network information](https://web3.okx.com/xlayer/docs/developer/build-on-xlayer/network-information.md) # Network information Welcome to X Layer developer documentation. ## Connecting to X Layer (Mainnet) You can add X Layer mainnet by inputting the following network info: |Properties|Network details| |:----|:----| |Network name|X Layer mainnet| |RPC URL|https://rpc.xlayer.tech, https://xlayerrpc.okx.com| |Chain ID|196| |Token symbol|OKB| |Block explorer URL|https://www.okx.com/web3/explorer/xlayer| ## Connecting to X Layer (Testnet) You can add X Layer testnet by inputting the following network info: |Properties|Network details| |:----|:----| |Network name|X Layer testnet| |RPC URL|https://testrpc.xlayer.tech/terigon, https://xlayertestrpc.okx.com/terigon| |Chain ID|1952| |Token symbol|OKB| |Block explorer URL|https://www.okx.com/web3/explorer/xlayer-test| - [Contracts](https://web3.okx.com/xlayer/docs/developer/build-on-xlayer/contracts.md) # Contracts ## X Layer contracts These smart contracts facilitate operation on Ethereum Mainnet and Sepolia Testnet. ### Ethereum Layer 1 |Name|Detail|Mainnet address|Testnet address| |:----|:--|:--|:--| |SystemConfig|Manages OP Stack network configuration, stores network parameters and other contract addresses|[0x5065809Af286321a05fBF85713B5D5De7C8f0433](https://etherscan.io/address/0x5065809Af286321a05fBF85713B5D5De7C8f0433)|[0x06BE4b4A9a28fF8EED6da09447Bc5DAA676efac3](https://sepolia.etherscan.io/address/0x06BE4b4A9a28fF8EED6da09447Bc5DAA676efac3)| |L1CrossDomainMessenger|High-level message passing interface between L1 and L2|[0xF94B553F3602a03931e5D10CaB343C0968D793e3](https://etherscan.io/address/0xF94B553F3602a03931e5D10CaB343C0968D793e3)|[0xEf40d5432D37B3935a11710c73F395e2c9921295](https://sepolia.etherscan.io/address/0xEf40d5432D37B3935a11710c73F395e2c9921295)| |OptimismPortal|Entry point for message passing|[0x64057ad1DdAc804d0D26A7275b193D9DACa19993](https://etherscan.io/address/0x64057ad1DdAc804d0D26A7275b193D9DACa19993)|[0x1529a34331D7d85C8868Fc88EC730aE56d3Ec9c0](https://sepolia.etherscan.io/address/0x1529a34331D7d85C8868Fc88EC730aE56d3Ec9c0)| |DisputeGameFactory|Deploys dispute game instances to resolve state disputes|[0x9D4c8FAEadDdDeeE1Ed0c92dAbAD815c2484f675](https://etherscan.io/address/0x9D4c8FAEadDdDeeE1Ed0c92dAbAD815c2484f675)|[0x80388586ab4580936BCb409Cc2dC6BC0221e1B6F](https://sepolia.etherscan.io/address/0x80388586ab4580936BCb409Cc2dC6BC0221e1B6F)| |FaultDisputeGame|Resolves disputes about L2 state through interactive fault proofs|Not deployed (0x0000...)|Not deployed (0x0000...)| |PermissionedDisputeGame|Dispute game with permission restrictions for authorized challengers|[0xEeDa796a23bc98726e47934ca9B54fDDa5a608e8](https://etherscan.io/address/0xEeDa796a23bc98726e47934ca9B54fDDa5a608e8)|[0x6d5610D86Dba85226146715B5c2b2addDAdE18c0](https://sepolia.etherscan.io/address/0x6d5610D86Dba85226146715B5c2b2addDAdE18c0)| |AnchorStateRegistry|Stores the latest anchored state for each dispute game type|[0x000590BB65ab1864a7AD46d6B957cC9a4F2C149d](https://etherscan.io/address/0x000590BB65ab1864a7AD46d6B957cC9a4F2C149d)|[0x1A8DFc1d6ccfB3bE886b2539823539a9DC0956a5](https://sepolia.etherscan.io/address/0x1A8DFc1d6ccfB3bE886b2539823539a9DC0956a5)| |DelayedWETH|Manages participant bonds during dispute periods with withdrawal delays|[0x1B8A252A71bC8997d3871aF420895B5845212fC6](https://etherscan.io/address/0x1B8A252A71bC8997d3871aF420895B5845212fC6)|[0xc8e876aD7E2e47017107D335132Bf7e3Efdd6B7b](https://sepolia.etherscan.io/address/0xc8e876aD7E2e47017107D335132Bf7e3Efdd6B7b)| |MIPS|MIPS32 virtual machine for executing fault proofs|[0x305D1C0EED9a0291686f3BfDf1F5E54aaeeF80e4](https://etherscan.io/address/0x305D1C0EED9a0291686f3BfDf1F5E54aaeeF80e4)|[0x4B55e1782E96762a457896Dff2B17Cd2477ab57c](https://sepolia.etherscan.io/address/0x4B55e1782E96762a457896Dff2B17Cd2477ab57c)| |PreimageOracle|Maps hashes to their corresponding preimages for fault proof verification|[0x1fb8cdFc6831fc866Ed9C51aF8817Da5c287aDD3](https://etherscan.io/address/0x1fb8cdFc6831fc866Ed9C51aF8817Da5c287aDD3)|[0xD59BB1D50DfeaDc2cC3a7BED43c3bc4065B0ed4B](https://sepolia.etherscan.io/address/0xD59BB1D50DfeaDc2cC3a7BED43c3bc4065B0ed4B)| |SuperchainConfig|Manages superchain global configuration values|[0x6a95D7aaC3d41761426761Af031C5034B7b347d4](https://etherscan.io/address/0x6a95D7aaC3d41761426761Af031C5034B7b347d4)|[0x307F426f725Dc6B2C49D489E1133aA5f5F400960](https://sepolia.etherscan.io/address/0x307F426f725Dc6B2C49D489E1133aA5f5F400960)| |ProtocolVersions|Manages superchain protocol version information|[0xC1Fb115d8249a7e6b27c8Bc6914Cab7eDF0b0F7E](https://etherscan.io/address/0xC1Fb115d8249a7e6b27c8Bc6914Cab7eDF0b0F7E)|[0x4e753a62Ad7Da17508DBC54A58E1e231C152baA2](https://sepolia.etherscan.io/address/0x4e753a62Ad7Da17508DBC54A58E1e231C152baA2)| |AddressManager|Legacy contract for managing string name to address registry, required by L1CrossDomainMessenger|[0xE88CfA9D4a4fae1413914baD9796A72D13d035b9](https://etherscan.io/address/0xE88CfA9D4a4fae1413914baD9796A72D13d035b9)|[0x6A09ED5B36dD48904551498f0020cD62cc315907](https://sepolia.etherscan.io/address/0x6A09ED5B36dD48904551498f0020cD62cc315907)| ### X Layer Layer 2 (Predeploys) |Name|Detail|L2 Address| |:----|:--|:--| |L2CrossDomainMessenger|L2 side cross-domain message passing interface|0x4200000000000000000000000000000000000007| |L2ToL1MessagePasser|Stores messages sent from L2 to L1 (with customGasToken support)|0x4200000000000000000000000000000000000016| |L1Block|Provides access to latest known L1 block information|0x4200000000000000000000000000000000000015| |GasPriceOracle|Provides L1 fee calculation and offline gas estimation|0x420000000000000000000000000000000000000F| |BeaconBlockRoot|Provides access to L1 beacon block roots (EIP-4788)|0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02| |SequencerFeeVault|Collects sequencer fees|0x4200000000000000000000000000000000000011| |BaseFeeVault|Collects L2 base fees|0x4200000000000000000000000000000000000019| |L1FeeVault|Collects L1 fee portion|0x420000000000000000000000000000000000001a| |SchemaRegistry|Global authentication schema for Ethereum Attestation Service|0x4200000000000000000000000000000000000020| |EAS|Ethereum Attestation Service|0x4200000000000000000000000000000000000021| |ProxyAdmin|Owner of all predeploy proxy contracts|0x4200000000000000000000000000000000000018| ### Token Addresses |Name|Detail|Mainnet address|Testnet address| |:----|:--|:--|:--| |[WOKB](https://www.okx.com/web3/explorer/xlayer/token/0xe538905cf8410324e03A5A23C1c177a474D59b2b "WOKB")|WOKB Token Address|[0xe538905cf8410324e03A5A23C1c177a474D59b2b](https://www.okx.com/web3/explorer/xlayer/token/0xe538905cf8410324e03A5A23C1c177a474D59b2b "0xe538905cf8410324e03A5A23C1c177a474D59b2b")|-| |[WETH](https://www.okx.com/web3/explorer/xlayer/token/0x5A77f1443D16ee5761d310e38b62f77f726bC71c "WETH")|WETH Token Address|[0x5A77f1443D16ee5761d310e38b62f77f726bC71c](https://www.okx.com/web3/explorer/xlayer/token/0x5A77f1443D16ee5761d310e38b62f77f726bC71c "0x5A77f1443D16ee5761d310e38b62f77f726bC71c")|[0xBec7859BC3d0603BeC454F7194173E36BF2Aa5C8](https://www.okx.com/web3/explorer/xlayer-test/token/0xBec7859BC3d0603BeC454F7194173E36BF2Aa5C8 "0xBec7859BC3d0603BeC454F7194173E36BF2Aa5C8")| |[USDT](https://www.okx.com/web3/explorer/xlayer/token/0x1E4a5963aBFD975d8c9021ce480b42188849D41d "USDT")|USDT Token Address|[0x1E4a5963aBFD975d8c9021ce480b42188849D41d](https://www.okx.com/web3/explorer/xlayer/token/0x1E4a5963aBFD975d8c9021ce480b42188849D41d "0x1E4a5963aBFD975d8c9021ce480b42188849D41d")|-| |[USDT0](https://www.okx.com/web3/explorer/xlayer/token/0x779Ded0c9e1022225f8E0630b35a9b54bE713736 "USDT0")|USDT0 Token Address|[0x779Ded0c9e1022225f8E0630b35a9b54bE713736](https://www.okx.com/web3/explorer/xlayer/token/0x779Ded0c9e1022225f8E0630b35a9b54bE713736 "0x779Ded0c9e1022225f8E0630b35a9b54bE713736")|-| |[USDC](https://www.okx.com/web3/explorer/xlayer/token/0x74b7F16337b8972027F6196A17a631aC6dE26d22 "USDC")|USDC Token Address|[0x74b7F16337b8972027F6196A17a631aC6dE26d22](https://www.okx.com/web3/explorer/xlayer/token/0x74b7F16337b8972027F6196A17a631aC6dE26d22 "0x74b7F16337b8972027F6196A17a631aC6dE26d22")|-| |[USDC.e](https://www.okx.com/web3/explorer/xlayer/token/0xA8CE8aee21bC2A48a5EF670afCc9274C7bbbC035 "USDC.e")|USDC.e Token Address|[0xA8CE8aee21bC2A48a5EF670afCc9274C7bbbC035](https://www.okx.com/web3/explorer/xlayer/token/0xA8CE8aee21bC2A48a5EF670afCc9274C7bbbC035 "0xA8CE8aee21bC2A48a5EF670afCc9274C7bbbC035")|-| |[WBTC](https://www.okx.com/web3/explorer/xlayer/token/0xEA034fb02eB1808C2cc3adbC15f447B93CbE08e1 "WBTC")|WBTC Token Address|[0xEA034fb02eB1808C2cc3adbC15f447B93CbE08e1](https://www.okx.com/web3/explorer/xlayer/token/0xEA034fb02eB1808C2cc3adbC15f447B93CbE08e1 "0xEA034fb02eB1808C2cc3adbC15f447B93CbE08e1")|-| |[DAI](https://www.okx.com/web3/explorer/xlayer/token/0xC5015b9d9161Dca7e18e32f6f25C4aD850731Fd4 "DAI")|DAI Token Address|[0xC5015b9d9161Dca7e18e32f6f25C4aD850731Fd4](https://www.okx.com/web3/explorer/xlayer/token/0xC5015b9d9161Dca7e18e32f6f25C4aD850731Fd4 "0xC5015b9d9161Dca7e18e32f6f25C4aD850731Fd4")|-| |[xBTC](https://www.okx.com/web3/explorer/xlayer/token/0xb7C00000bcDEeF966b20B3D884B98E64d2b06b4f "xBTC")|xBTC Token Address|[0xb7C00000bcDEeF966b20B3D884B98E64d2b06b4f](https://www.okx.com/web3/explorer/xlayer/token/0xb7C00000bcDEeF966b20B3D884B98E64d2b06b4f "0xb7C00000bcDEeF966b20B3D884B98E64d2b06b4f")|-| |[USDG](https://www.okx.com/web3/explorer/xlayer/token/0x4ae46a509F6b1D9056937BA4500cb143933D2dc8 "USDG")|USDG Token Address|[0x4ae46a509F6b1D9056937BA4500cb143933D2dc8](https://www.okx.com/web3/explorer/xlayer/token/0x4ae46a509F6b1D9056937BA4500cb143933D2dc8 "0x4ae46a509F6b1D9056937BA4500cb143933D2dc8")|-| - [Address Format](https://web3.okx.com/xlayer/docs/developer/build-on-xlayer/address-format.md) # Address Format X Layer is an EVM-compatible blockchain network that supports two address formats: Standard EVM Address Format and XKO Prefix Address Format. ## Supported Address Formats ### Standard EVM Address Format - **Format**: `0x` + 40 hexadecimal characters - **Example**: `0x70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625` - **Features**: - Complies with EIP-55 checksum standard (mixed case) - Fully compatible with all Ethereum tools and wallets ### XKO Prefix Address Format - **Format**: `XKO` + 40 hexadecimal characters - **Example**: `XKO70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625` - **Features**: - X Layer proprietary address format - Case-insensitive prefix (XKO, xko, Xko all valid) - Preserves EIP-55 checksum casing - Easy identification of X Layer ecosystem addresses ### Address Equivalence The same account can be represented in both formats, pointing to the same on-chain account: ``` Standard EVM: 0x70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625 XKO address: XKO70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625 xko70586beeb7b7aa2e7966df9c8493c6cbfd75c625 ✓ Valid Xko70586beeb7b7aa2e7966df9c8493c6cbfd75c625 ✓ Valid ``` **Invalid format examples**: ``` XKO0x70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625 ✗ Cannot have both XKO and 0x ``` --- ## XKO Prefix Address Design XKO address is essentially an alternative representation of a standard EVM address: 1. **Address Core**: 40 hexadecimal characters (same as EVM address) 2. **Prefix Replacement**: `XKO` replaces `0x` prefix 3. **Checksum Preservation**: Maintains Keccak-256 hash-based case checksum 4. **On-Chain Storage**: Stored as standard 20-byte address on-chain --- ## SDK Integration Guide X Layer provides multi-language SDKs for address format conversion, supporting: - JavaScript - TypeScript - Python - Go - Rust - Java ### Core APIs All SDKs provide two core functions: | Function | Purpose | Input | Output | |----------|---------|-------|--------| | `toEvmAddress` | Convert to standard EVM address | `0x...` / `XKO...` / bare address | `0x` + 40 chars (EIP-55 checksum) | | `fromEvmAddress` | Convert to XKO address | `0x...` / bare address | `XKO` + 40 chars (preserves checksum) | Some SDKs also provide utility functions: | Function | Purpose | Available In | |----------|---------|--------------| | `isXlayerAddress` | Check if address is XKO format | Java | --- ### JavaScript SDK **Installation**: ```bash npm install js-sha3 ``` **Usage Example**: ```javascript const { toEvmAddress, fromEvmAddress } = require('./multiAddress.js'); // XKO to standard EVM address const evmAddr = toEvmAddress('XKO70586beeb7b7aa2e7966df9c8493c6cbfd75c625'); console.log(evmAddr); // Output: 0x70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625 // Standard EVM to XKO address const xkoAddr = fromEvmAddress('0x70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625'); console.log(xkoAddr); // Output: XKO70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625 // Supports multiple input formats toEvmAddress('0x70586beeb7b7aa2e7966df9c8493c6cbfd75c625'); // ✓ toEvmAddress('70586beeb7b7aa2e7966df9c8493c6cbfd75c625'); // ✓ toEvmAddress('XKO70586beeb7b7aa2e7966df9c8493c6cbfd75c625'); // ✓ ``` **Error Handling**: ```javascript try { toEvmAddress('invalid'); } catch (error) { console.error(error.message); // Output: Invalid address length: expected 40 hex chars, got 7 } ``` --- ### TypeScript SDK **Installation**: ```bash npm install js-sha3 ``` **Usage Example**: ```typescript import { toEvmAddress, fromEvmAddress } from './multiAddress'; // Type-safe address conversion const evmAddr: string = toEvmAddress('XKO70586beeb7b7aa2e7966df9c8493c6cbfd75c625'); const xkoAddr: string = fromEvmAddress('0x70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625'); // Type checking toEvmAddress(123); // TypeScript compile error ``` --- ### Python SDK **Installation**: ```bash pip install eth-utils ``` **Usage Example**: ```python from multi_address import to_evm_address, from_evm_address # XKO to EVM evm_addr = to_evm_address('XKO70586beeb7b7aa2e7966df9c8493c6cbfd75c625') print(evm_addr) # Output: 0x70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625 # EVM to XKO xko_addr = from_evm_address('0x70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625') print(xko_addr) # Output: XKO70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625 # Error handling try: to_evm_address('invalid') except ValueError as e: print(e) # Output: Invalid address length: expected 40 hex chars, got 7 ``` --- ### Go SDK **Installation**: ```bash go get golang.org/x/crypto/sha3 ``` **Usage Example**: ```go package main import ( "fmt" "log" address "your-module/multi_address" ) func main() { // XKO to EVM evmAddr, err := address.ToEvmAddress("XKO70586beeb7b7aa2e7966df9c8493c6cbfd75c625") if err != nil { log.Fatal(err) } fmt.Println(evmAddr) // Output: 0x70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625 // EVM to XKO xkoAddr, err := address.FromEvmAddress("0x70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625") if err != nil { log.Fatal(err) } fmt.Println(xkoAddr) // Output: XKO70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625 } ``` --- ### Rust SDK **Add Dependency** (Cargo.toml): ```toml [dependencies] multi_address = { path = "path/to/address/rust" } ``` **Usage Example**: ```rust use multi_address::{to_evm_address, from_evm_address}; fn main() { // XKO to EVM match to_evm_address("XKO70586beeb7b7aa2e7966df9c8493c6cbfd75c625") { Ok(evm_addr) => println!("{}", evm_addr), // Output: 0x70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625 Err(e) => eprintln!("Error: {}", e), } // EVM to XKO match from_evm_address("0x70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625") { Ok(xko_addr) => println!("{}", xko_addr), // Output: XKO70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625 Err(e) => eprintln!("Error: {}", e), } } ``` --- ### Java SDK **Maven Dependency**: ```xml com.okcoin xlayer-sdk 0.2.1 ``` **Usage Example**: ```java import com.okcoin.MultiAddress; public class Example { public static void main(String[] args) { // XKO to EVM String evmAddr = MultiAddress.toEvmAddress("XKO70586beeb7b7aa2e7966df9c8493c6cbfd75c625"); System.out.println(evmAddr); // Output: 0x70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625 // EVM to XKO String xkoAddr = MultiAddress.fromEvmAddress("0x70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625"); System.out.println(xkoAddr); // Output: XKO70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625 // Check if XKO address boolean isXko = MultiAddress.isXlayerAddress("XKO70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625"); System.out.println(isXko); // true boolean isNotXko = MultiAddress.isXlayerAddress("0x70586BeEB7b7Aa2e7966DF9c8493C6CbFd75C625"); System.out.println(isNotXko); // false // Error handling try { MultiAddress.toEvmAddress("invalid"); } catch (IllegalArgumentException e) { System.err.println(e.getMessage()); // Output: Invalid address length: expected 40 hex chars, got 7 } } } ``` --- ## Security Considerations **Important**: XKO addresses are only for off-chain interactions (UI display, etc.) In transaction RLP encoding: - ❌ **Cannot** use XKO format addresses - ✅ **Must** use standard 20-byte address format - The chain automatically rejects transactions containing XKO format addresses SDKs handle this conversion automatically, but if manually constructing transactions, use the standard format. --- ## Frequently Asked Questions (FAQ) ### Q1: What's the difference between XKO and EVM addresses? A: They are completely equivalent on-chain, differing only in prefix. XKO addresses use `XKO` prefix, while EVM addresses use `0x` prefix. ### Q2: Can I use XKO addresses directly in transactions? A: No. When constructing RLP-encoded transactions, you must use the standard 20-byte address. XKO format is only for off-chain interactions (RPC queries, UI display). ### Q3: Is case sensitivity important? A: The XKO prefix is case-insensitive (XKO, xko, Xko all valid). However, the address body preserves EIP-55 checksum casing for error detection. ### Q4: How do I validate address format? A: Use the SDK conversion functions. They will throw exceptions if the address format is invalid. --- ## Resources - **GitHub Repository**: [xlayer-sdk](https://github.com/okx/xlayer-sdk) ## License This SDK is released under the MIT License. ## Support For issues and questions: - GitHub Issues: [Create an issue](https://github.com/okx/xlayer-sdk/issues) - [Deploying contract](https://web3.okx.com/xlayer/docs/developer/deploy-a-smart-contract/deploying-contract.md) # Deploying contract - [Deploying with Hardhat](https://web3.okx.com/xlayer/docs/developer/deploy-a-smart-contract/deploy-with-hardhat.md) # Deploying with Hardhat In this tutorial, we explain step-by-step how to create, compile and deploy a simple smart contract on the X Layer testnet using Hardhat. ## What is Hardhat Hardhat is a development environment to compile, deploy, test, and debug your smart contract. ## Setting up the development environment Prerequisites: - [Node.js v18+ LTS and npm](https://nodejs.org/en "Node.js v18+ LTS and npm") (comes with Node) - [Git](https://git-scm.com/ "Git") To install Hardhat, you need to create an npm project by going to an empty folder, running `npm init`, and following its instructions. You can use another package manager, like yarn, but we recommend you use npm 7 or later, as it makes installing Hardhat plugins simpler. Once your project is ready, you should run `npm install --save-dev hardhat` , install Hardhat toolbox `npm install @nomicfoundation/hardhat-toolbox` . In order to use your local installation of Hardhat, you need to use `npx` to run it (i.e., `npx hardhat`). ## Creating your contract To create the sample project, run `npx hardhat` in your project folder: ```shell $ npx hardhat 888 888 888 888 888 888 888 888 888 888 888 888 888 888 888 8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888 888 888 "88b 888P" d88" 888 888 "88b "88b 888 888 888 .d888888 888 888 888 888 888 .d888888 888 888 888 888 888 888 Y88b 888 888 888 888 888 Y88b. 888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888 👷 Welcome to Hardhat v2.9.9 👷 ? What do you want to do? … ❯ Create a JavaScript project Create a TypeScript project Create an empty hardhat.config.js Quit ``` ## Compiling your contract Next, if you take a look at the `contracts/` folder, you will see `Lock.sol`: ```shell // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9; // Uncomment this line to use console.log // import "hardhat/console.sol"; contract Lock { uint public unlockTime; address payable public owner; event Withdrawal(uint amount, uint when); constructor(uint _unlockTime) payable { require( block.timestamp < _unlockTime, "Unlock time should be in the future" ); unlockTime = _unlockTime; owner = payable(msg.sender); } function withdraw() public { // Uncomment this line, and the import of "hardhat/console.sol", to print a log in your terminal // console.log("Unlock time is %o and block timestamp is %o", unlockTime, block.timestamp); require(block.timestamp >= unlockTime, "You can't withdraw yet"); require(msg.sender == owner, "You aren't the owner"); emit Withdrawal(address(this).balance, block.timestamp); owner.transfer(address(this).balance); } } ``` To compile it, simply run `npx hardhat compile` ## Setting configuration file In order to connect to the X Layer network, we need to configure the corresponding network. To set up your config, you have to export an object from `hardhat.config.js`: ```javascript module.exports = { defaultNetwork: "hardhat", networks: { hardhat: { }, xlayer: { url: "https://testrpc.xlayer.tech/terigon", accounts: [privateKey1, privateKey2, ...] } } } ``` ## Deploying your contract Next, to deploy the contract, we will use a Hardhat script. Inside the `scripts/` folder you will find a file with the following code: ```javascript // We require the Hardhat Runtime Environment explicitly here. This is optional // but useful for running the script in a standalone fashion through `node