# OKX OnchainOS Developer Documentation
- [What is OnchainOS](https://web3.okx.com/onchainos/dev-docs/home/what-is-onchainos.md)
# What is OnchainOS
## Introduction
**Built for AI. Ready for Web3.**
OnchainOS is an onchain development platform built by OKX Wallet, with native AI Skills and MCP Server support. It enables developers and AI agents to seamlessly access onchain capabilities and build intelligent Web3 applications faster.
## Access via AI Skills, MCP & Open API
OnchainOS provides three flexible ways to integrate:
- **AI Skills** — Interact with onchain services through natural language — no complex API integration required.
- **MCP** — Connect OnchainOS to your AI agents and LLM applications seamlessly via Model Context Protocol.
- **Open API** — Full-featured RESTful APIs for direct programmatic access with fine-grained control.
## Core Capabilities
- **Wallet** — Query wallet balances, broadcast transactions, and retrieve transaction history.
- **Trade** — Smart routing to find the best quotes and optimal liquidity across pools.
- **Market** — Comprehensive multi-market and onchain data covering tokens, trades, transfers, and accounts.
- **Payments** — Built on the x402 protocol, supporting pay-per-use models, AI Agent friendly.
- **DApp Connect Wallet** — Quickly integrate "Connect OKX Wallet" into your DApp.
## Why OnchainOS
### Built for AI Agents
The only Web3 OS purpose-built for AI agents — with native MCP Server support, callable AI Skills, and structured instructions that let agents autonomously fetch onchain data and execute transactions.
### All-in-One Developer Workstation
AI toolkit, trade, market data, and payments — all unified in a single tech stack, deeply optimized for developers and AI agent workflows from prototype to production.
### Best Price on Every Trade
Smart routing across 500+ DEXs to maximize the received amount on every swap — low fees, fast quotes, no compromise on performance.
### Most Network Coverage
OKX Wallet supports 130+ networks, OnchainOS covers 20+ major chains with a multichain-native architecture, validated by millions of traders and developers.
### Enterprise-Grade Security
Every agent action is verified through intent validation and real-time monitoring, with built-in self-healing mechanisms and customizable risk controls — designed for autonomous operation scenarios.
- [Supported Networks](https://web3.okx.com/onchainos/dev-docs/home/supported-chain.md)
# Supported Networks
## Popular networks
| Chain | Wallet | 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 | 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 |
| Monad | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 143 |
| Optimism | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 10 |
| Plasma | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 9745 |
| 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 | 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 |
| Tron | [✓](../wallet/what-is-wallet) | [✓](../trade/dex-api-introduction) | [✓](../market/market-api-introduction) | - | [✓](../sdks/okx-wallet-integration-introduction) | 195 |
| 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 |
- [Authentication](https://web3.okx.com/onchainos/dev-docs/home/api-access-and-usage.md)
# Authentication
Before using the 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](./developer-portal).
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.

### Set headers
Under the **Headers** tab, add the following key-value pairs:
- `OK-ACCESS-KEY`
- `OK-ACCESS-PASSPHRASE`

### 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.

### 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) {
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) {
const hmac = crypto.createHmac('sha256', secret_key);
hmac.update(message);
return hmac.digest('base64');
}
function createSignature(method, request_path, params) {
const timestamp = new Date().toISOString().slice(0, -5) + 'Z';
const message = preHash(timestamp, method, request_path, params);
const signature = sign(message, api_config['secret_key']);
return { signature, timestamp };
}
function sendGetRequest(request_path, params) {
const { signature, timestamp } = createSignature("GET", request_path, params);
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) {
const { signature, timestamp } = createSignature("POST", request_path, params);
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/v6/dex/index/current-price';
const postParams = [{
chainIndex: "1",
tokenContractAddress: "0xc18360217d8f7ab5e7c516566761ea12ce7f9d72"
}];
sendPostRequest(postRequestPath, postParams);
```
- [Developer Dashboard](https://web3.okx.com/onchainos/dev-docs/home/developer-portal.md)
# Developer Dashboard
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 DEX API. 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
You have successfully linked your E-mail and phone number to your developer account. You can now immediately create DEX 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 "API keys" 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 Copy button on the right of the Secrete key column.
## General Terms
- API key: a unique identifier used to authenticate and authorize an application or user when making requests to OKX DEX 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.
- [Build for AI Agent](https://web3.okx.com/onchainos/dev-docs/home/develop-with-ai-overview.md)
# Build for AI Agent
**Every capability OKX Wallet has — your AI agent will have too.**
OKX Wallet serves millions of users across 130+ networks, routing trades through 500+ DEXs with 40ms average response time. OnchainOS opens all of it to your AI agent.
## Trade & Market for Agents
Trade MCP/Skills and Market MCP/Skills are live. Agents can swap tokens, fetch real-time prices, query onchain data, and stream market updates — all as native MCP tools.
## What's Next
Great infrastructure isn't rushed. A fundamentally new kind of Wallet and Payment MCP are on the way — not another fork of what exists, but a rethink of how agents hold, move, and spend value onchain.
- [Run Your First AI Agent](https://web3.okx.com/onchainos/dev-docs/home/run-your-first-ai-agent.md)
# Run Your First AI Agent
Give your AI agent onchain capabilities — check prices, query market data — through natural language.
## Preparation: Have an AI Agent
This guide uses [Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview), but OnchainOS supports all major agents. ([Cursor](https://docs.cursor.com/get-started/installation), [OpenClaw](https://docs.openclaw.ai/), etc.)
## Step 1: Set Your API Keys
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
## Step 2: Add OnchainOS to Your Agent
Choose one of the two integration methods:
### Option A: Skills (recommended)
Tell your agent:
```plain text
Install OnchainOS skills by running: npx skills add okx/onchainos-skills
```
Your agent will install the skills and remind you to restart afterwards. Click the [GitHub link](https://github.com/okx/onchainos-skills) for more information.
### Option B: MCP Server
Tell your agent:
```plain text
Add an MCP server called onchainos-mcp with:
URL https://web3.okx.com/api/v1/onchainos-mcp
Header OK-ACCESS-KEY: "here you should type your okx-api-key"
```
Or manually add to your config file:
```json
{
"mcpServers": {
"onchainos-mcp": {
"url": "https://web3.okx.com/api/v1/onchainos-mcp",
"headers": {
"OK-ACCESS-KEY": "your apiKey applyed on https://web3.okx.com/zh-hans/onchainos/dev-portal/project"
}
"type": "http"
}
}
}
```
Restart your client after updating
## Step 3: Try It Out!
Ask your agent:
```plain text
What is the current price of OKB?
```
Your agent will return something like:
```plain text
OKB is currently trading at $80.34.
```
Your agent is now onchain. Build from here!
- [Run your first DApp](https://web3.okx.com/onchainos/dev-docs/home/run-your-first-dapp.md)
# Run your first DApp
## API-First Approach
This approach demonstrates a token swap using the Trade 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;
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:[Discord](https://discord.gg/mUqMWaFGyW)
Business Support:dexapi@okx.com
- [Change log](https://web3.okx.com/onchainos/dev-docs/home/change-log.md)
# Change log
### March x, 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``
- [Wallet API](https://web3.okx.com/onchainos/dev-docs/wallet/what-is-wallet.md)
# Wallet API
The Wallet API equips AI agents, trading bots, and Web3 applications with full onchain asset intelligence and transaction power — query balances, execute transactions, and trace every move across chains through a single, unified interface.
- **Check Balance API** — Real-time visibility into any wallet. Query total portfolio value, cross-chain token balances, and specific holdings — giving your agents instant asset awareness.
- **Transaction API** — From simulation to settlement. Estimate gas, simulate execution, broadcast transactions, and track order status. Built for agent-driven automation, equally powerful for developers.
- **Transaction History API** — Every transaction, fully traceable. Retrieve complete history by address or drill into specific transaction details.
- [Supported Chains](https://web3.okx.com/onchainos/dev-docs/wallet/supported-networks.md)
# Supported Chains
## EVM-Compatible Networks
| Chain | Wallet | 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 | Wallet | ChainIndex |
| ------- | ------ | ---------- |
| Bitcoin | ✓ | 0 |
| Solana | ✓ | 501 |
| SUI | ✓ | 784 |
| Ton | ✓ | 607 |
| Tron | ✓ | 195 |
- [Introduction](https://web3.okx.com/onchainos/dev-docs/wallet/balance-api-overview.md)
# Introduction
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 |
- [Introduction](https://web3.okx.com/onchainos/dev-docs/wallet/onchain-gateway-api-overview.md)
# Introduction
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.
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/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 |
- [Introduction](https://web3.okx.com/onchainos/dev-docs/wallet/tx-history-api-overview.md)
# Introduction
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 |
- [Signing SDK](https://web3.okx.com/onchainos/dev-docs/wallet/signing-sdk.md)
# Signing SDK
- [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 OnchainOS 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 OnchainOS 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.**OnchainOS 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.
```markdown
skills: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:
```shell
# for cursor
{
"mcpServers": {
"onchainos-mcp": {
"url": "https://web3.okx.com/api/v1/onchainos-mcp",
"headers": {
"OK-ACCESS-KEY": "your apiKey applyed on https://web3.okx.com/zh-hans/onchainos/dev-portal/project"
}
}
}
}
# for Claude code
{
"mcpServers": {
"onchainos-mcp": {
"url": "https://web3.okx.com/api/v1/onchainos-mcp",
"headers": {
"OK-ACCESS-KEY": "your apiKey applyed on https://web3.okx.com/zh-hans/onchainos/dev-portal/project"
}
"type": "http"
}
}
}
```
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 OnchainOS 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
```markdown
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:
```markdown
What chains support DEX swaps?
# Call dex-aggregator-supported-chains
```
```markdown
Which DEXs are available on X-layer?
# Call dex-liquidity
```
```markdown
How much USDC will I get for 1 ETH on X-layer?
# Call dex-quote
```
```markdown
I need to approve USDT before swapping, generate the calldata
# Call dex-approve-transaction
```
```markdown
Build a swap transaction: 100 USDT → ETH, wallet 0xd8dA..., slippage 0.5%
# Call dex-swap
```
```markdown
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
```shell
# for Cursor
{
"mcpServers": {
"onchainos-mcp": {
"url": "https://web3.okx.com/api/v1/onchainos-mcp",
"headers": {
"OK-ACCESS-KEY": "your apiKey applyed on https://web3.okx.com/zh-hans/onchainos/dev-portal/project"
}
}
}
}
# for Claude code
{
"mcpServers": {
"onchainos-mcp": {
"url": "https://web3.okx.com/api/v1/onchainos-mcp",
"headers": {
"OK-ACCESS-KEY": "your apiKey applyed on https://web3.okx.com/zh-hans/onchainos/dev-portal/project"
}
"type": "http"
}
}
}
```
## Example interactions
Once the MCP Server is active, an Agent can respond to natural-language instructions like:
```markdown
What chains support DEX swaps?
# Call dex-aggregator-supported-chains
```
```markdown
Which DEXs are available on X-layer?
# Call dex-liquidity
```
```markdown
How much USDC will I get for 1 ETH on X-layer?
# Call dex-quote
```
```markdown
I need to approve USDT for swap
# Call dex-approve-transaction
```
```markdown
Swap 100 USDT to OKB
# Call dex-swap
```
```markdown
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
## OnchainOS 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)
## OnchainOS 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)
- [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|
|:-|
||
- 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 |
|:--------------------------------------------|
|  |
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. |
| 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. |
| 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. |
| 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 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: 40 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: '0x0Bdf246b4AEF9Cfe4DD6eEf153A1b645aC4BcBb6'
ARB: '0x1ef032a3c471a99cc31578c8007f256d95e89896'
Base: '0xed97b4331fff9dc8c40936532a04ac1400f273a5'
BSC: '0x9ff547bbb813a0e5d53742c7a5f7370dcea214a3'
Solana: 'RFQ1uATMXfRXemLnbYCF8JZhVfELp2K53jSEAGbsAKX'
};
```
## 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 |
## 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 |
## 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
}
```
## 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
"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
}
```
- [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 | 0x5E1f62Dac767b0491e3CE72469C217365D5B48cC |
| Solana | proVF4pMXVaYqmy4NjniPh4pqKNfMmsihgd4wdkCX3u |
| SUI | 0xfdba5cc063cbe60523712258f28372d4b5b184abc91be6752a7949c4c879fe2a extended: 0x5c49bc6413188c7a975d957956e646a76fc1c631775211eb322dd0935b6fe4fc For package ID, it ran into the Sui package size limit. We need to deploy an extended contract that supports liquidity integrations with Momentum, Scallop, Haedal, Alphafi, and others)|
| Sonic | 0x86F752f1F662f39BFbcBeF95EE56B6C20d178969 |
| Tron | TU7NYwqhPUMjBBYQYxQJVmnY7KuJCqMFuu |
| Ton | EQBjfOGw4Iq6FYZplhwZ5rRNb7Htac7WJh8g_eQcGTswxVqP |
| zkSync Era | 0x3163Ed233a3Cb5E6B7F10A6f02b01F15867a8779 |
| Optimism | 0x6733Eb2E75B1625F1Fe5f18aD2cB2BaBDA510d19 |
| Polygon | 0x057cfd839aa88994d1a8a8c6d336cf21550f05ef |
| BNB Chain | 0x3156020dfF8D99af1dDC523ebDfb1ad2018554a0 |
| Avalanche C | 0x8aDFb0D24cdb09c6eB6b001A41820eCe98831B91 |
| Fantom | 0xcF76984119C7f6ae56fAfE680d39C08278b7eCF4 |
| Arbitrum | 0x368E01160C2244B0363a35B3fF0A971E44a89284 |
| Linea | 0x9EaBF1D34819D9eC9Fe5fd3Db4e9DCD12Fa05284 |
| Conflux eSpace | 0x23e2f2fa1967faffde2e05fdecbb3fa787a5d3e5 |
| Base | 0x4409921ae43a39a11d90f7b7f96cfd0b8093d9fc |
| Mantle | 0xF5402CCC5fC3181B45D7571512999D3Eea0257B6 |
| Scroll | 0x6733Eb2E75B1625F1Fe5f18aD2cB2BaBDA510d19 |
| Manta | 0x8feB9E84b7E9DC86adc6cD6Eb554C5B4355c8405 |
| Metis | 0xDd5E9B947c99Aa60bab00ca4631Dce63b49983E7 |
| Blast | 0xc9da86c392101047188bae98ccc192271a136a13 |
| Zeta | 0x8feB9E84b7E9DC86adc6cD6Eb554C5B4355c8405 |
| Polygon zkEvm | 0x79f7C6C6dc16Ed3154E85A8ef9c1Ef31CEFaEB19 |
| Merlin | 0xd3b3e6433d6a7f94c28ce907311fb21b0f0b659e |
| X Layer | 0xD1b8997AaC08c619d40Be2e4284c9C72cAB33954 |
| UniChain | 0x23E2f2FA1967FAffde2e05fDecbb3fa787A5D3E5 |
| Cronos | 0xcF76984119C7f6ae56fAfE680d39C08278b7eCF4 |
| Plasma | 0x5c1c902e7e04de98b49acd3de68e12bee2d7908d |
| Monad | 0x6088d94C5a40CEcd3ae2D4e0710cA687b91c61d0 |
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.
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/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/
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
OnchainOS 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 OnchainOS 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.
```markdown
skills: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:
```shell
# for cursor
{
"mcpServers": {
"onchainos-mcp": {
"url": "https://web3.okx.com/api/v1/onchainos-mcp",
"headers": {
"OK-ACCESS-KEY": "your apiKey applyed on https://web3.okx.com/zh-hans/onchainos/dev-portal/project"
}
}
}
}
# for Claude code
{
"mcpServers": {
"onchainos-mcp": {
"url": "https://web3.okx.com/api/v1/onchainos-mcp",
"headers": {
"OK-ACCESS-KEY": "your apiKey applyed on https://web3.okx.com/zh-hans/onchainos/dev-portal/project"
}
"type": "http"
}
}
}
```
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 OnchainOS 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
```markdown
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 agents, an Agent can respond to natural-language queries like:
```markdown
What is the current price of OKB?
# Call index-current-price
```
```markdown
Show me OKB’s 4-hour candlesticks for the past week.
# Call market-candlesticks
```
```markdown
What is the hottest token on the X-layer chain right now?
# Call market-token-ranking
```
```markdown
Which address holds the most USDT on X-layer?
# Call market-token-holder
```
```markdown
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
```shell
# for Cursor
{
"mcpServers": {
"onchainos-mcp": {
"url": "https://web3.okx.com/api/v1/onchainos-mcp",
"headers": {
"OK-ACCESS-KEY": "your apiKey applyed on https://web3.okx.com/zh-hans/onchainos/dev-portal/project"
}
}
}
}
# for Claude code
{
"mcpServers": {
"onchainos-mcp": {
"url": "https://web3.okx.com/api/v1/onchainos-mcp",
"headers": {
"OK-ACCESS-KEY": "your apiKey applyed on https://web3.okx.com/zh-hans/onchainos/dev-portal/project"
}
"type": "http"
}
}
}
```
## Example interactions
Once the MCP Server is active, an Agent can respond to natural-language queries like:
```markdown
What is the current price of OKB?
# Call index-current-price
```
```markdown
Show me OKB’s 4-hour candlesticks for the past week.
# Call market-candlesticks
```
```markdown
What is the hottest token on the X-layer chain right now?
# Call market-token-ranking
```
```markdown
Which address holds the most USDT on X-layer?
# Call market-token-holder
```
```markdown
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
## OnchainOS 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.
## OnchainOS 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)
- [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 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 Trades](https://web3.okx.com/onchainos/dev-docs/market/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](../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. |
## 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":"",
}
```
- [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 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/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**
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](../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**
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](../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**
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](../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"
]
]
}
```
- [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**
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](../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"
}
]
}
```
- [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 |
## 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 |
| 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/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 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 Ranking List](https://web3.okx.com/onchainos/dev-docs/market/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](../home/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](../home/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.5746512075769158",
"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.5117849016896625",
"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.5010844496677946",
"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/market/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](../home/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/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 |
- [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 |
- [Payments API](https://web3.okx.com/onchainos/dev-docs/payments/x402-introduction.md)
# Payments API
## What is the OKX Payment API?
OKX Payment API is a Web3 payment solution built on the x402 protocol — an open standard designed around the HTTP 402 status code. It provides developer-friendly APIs and SDKs for pay-per-use billing, with payment settlement completed onchain.
### Why OKX Payment API?
* **Simple and frictionless**: Built on HTTP. No registration or OAuth required — pay directly via API using tokens.
* **Instant and low-cost**: A native internet payment protocol with a streamlined, standardized flow and fewer intermediaries.
* **AI-ready**: Supports pay-per-use billing, ideal for real-time AI calls and high-frequency microtransactions.
* **Open standard**: Compatible with major blockchains. Easy to integrate and extend.
### Key Services
* **Gas Subsidy**: Transfer and spend USDT and USDC on X Layer with zero gas fees.
* **Multi-Chain Support**: Currently supports X Layer, with more chains coming soon.
* **Multiple Stablecoins**: Currently supports USDG, USDC and USDT.
* **Compliance and Security**: Built-in KYT (Know Your Transaction) for onchain risk detection.
### Working principle

- [Supported networks and crypto](https://web3.okx.com/onchainos/dev-docs/payments/supported-networks.md)
# Supported networks and crypto
X Layer is now supported. Support for more networks is under development. Stay tuned.
| Network | x402 API | ChainIndex |
|----------------------------------|-----------------------------------------|---------------|
| X Layer | Supported | 196 |
| Base | Coming Soon | 8453 |
| Solana | Coming Soon | 501 |
| BNB Smart Chain Mainnet | Coming Soon | 56 |
Supported crypto:
| Crypto | Contract address |
|----------------------------------|--------------------------------------------------------|
| USDG | X Layer:0x4ae46a509f6b1d9056937ba4500cb143933d2dc8 |
| USDT | X Layer:0x779ded0c9e1022225f8e0630b35a9b54be713736 |
| USDC | X Layer:0x74b7f16337b8972027f6196a17a631ac6de26d22 |
- [Introduction](https://web3.okx.com/onchainos/dev-docs/payments/x402-api-introduction.md)
# Introduction
Payment API API is a Facilitator service provided by OKX Wallet based on the standard x402 protocol and includes the following capabilities:
* **Standard interface**: GET `/api/v6/wallet/payments/supported`; POST `/api/v6/wallet/payments/verify`; POST `/api/v6/wallet/payments/settle`. Semantically aligned with x402, it's easy to migrate and conduct joint debugging.
* **Multi-network support**: Use /supported to get real-time lists of available networks. This capability will be expanded following future releases. Refer to the actual interface returns.
* **Fast settlement**: Low-latency completion of onchain or ledger entry, with standardized receipt returns.
* **Monitoring and reconciliation**: The fine-state machine and receipt fields are unified to facilitate log collection, usage statistics, and financial reconciliation.
* **Security and risk control**: Signature verification; amount, asset, network consistency verification; anti-replay, traffic control, and exception hierarchical handling.
- [API reference](https://web3.okx.com/onchainos/dev-docs/payments/x402-api-reference.md)
# API reference
- [Get basic information](https://web3.okx.com/onchainos/dev-docs/payments/get-supported-schemes-and-networks.md)
{/* api-page */}
# Get basic information
Get the supported x402 protocol payment schemes and networks that the facilitator is able to verify and settle payments for.
## Request address
GET `https://web3.okx.com/api/v6/payments/supported/`
## Request parameters
No
## Response parameter
| Parameter | Type | Description |
|------------|--------|--------------------------------------------------------------------------------------------------------------|
| x402Version | String | The version of the x402 protocol (e.g. 1) |
| scheme | String | Settlement scheme, e.g. exact (one‑time fixed‑amount payment) |
| chainIndex | String | Unique chain identifier, e.g. 196 (X Layer) |
| chainName | String | Chain name, e.g. X Layer |
## Request example
```shell
curl --location --request GET 'https://web3.okx.com/api/v6/payments/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": [
{
"x402Version": 1,
"scheme": "exact",
"chainIndex": "196",
"chainName": "X Layer"
}
],
"msg": ""
}
```
- [Submit transaction](https://web3.okx.com/onchainos/dev-docs/payments/payment-settlement.md)
{/* api-page */}
# Submit transaction
Settle the submitted transaction on the blockchain.
## Request address
POST `https://web3.okx.com/api/v6/payments/settle`
## Request parameters
- Request body
| Parameter | Type | Required | Description |
|---------------------|--------|----------|-----------------------------------------------------------------------------------------------------------------|
| x402Version | String | Yes | Version of the x402 protocol (e.g. 1) |
| chainIndex | String | Yes | Unique identifier of the blockchain |
| paymentPayload | Object | Yes | The x402 payment payload carried by the client with the protected request |
| >x402Version | String | Yes | Version of the x402 protocol (e.g. 1) |
| >scheme | String | Yes | Settlement scheme defining how the payment is processed, e.g. exact (one‑time fixed‑amount payment) |
| >payload | Object | Yes | Object containing payment signature and authorization data |
| >>signature | String | Yes | Cryptographic signature |
| >>authorization | Object | Yes | Authorization information |
| >>>from | String | Yes | Payer address |
| >>>to | String | Yes | Payee address |
| >>>value | String | Yes | Payment amount (in smallest unit, with precision) |
| >>>validAfter | String | Yes | Effective time (Unix timestamp) |
| >>>validBefore | String | Yes | Expiration time (Unix timestamp) |
| >>>nonce | String | Yes | Random nonce to prevent replay attacks |
| paymentRequirements | Object | Yes | Information describing what resource the payment grants access to (including amount, network, asset, and payee) |
| >scheme | String | Yes | Defines how the payment is settled, e.g. exact (one‑time fixed‑amount payment) |
| >resource | String | No | Server URL of the resource |
| >description | String | No | Description of the resource API endpoint |
| >mimeType | String | No | MIME type of the resource provider’s response |
| >maxAmountRequired | String | Yes | Maximum payable amount (in smallest unit, with precision) |
| >maxTimeoutSeconds | Integer| No | Maximum waiting time in seconds after the authorization becomes valid |
| >payTo | String | Yes | Payee address |
| >asset | String | No | Asset identifier or contract address (depending on the network) |
| >outputSchema | Object | No | Expected JSON structure of the returned resource data |
| >extra | Object | No | Additional parameters, e.g. gasLimit |
## Response parameter
| Parameter | Type | Description |
|------------|---------|-----------------------------------------------------------------------------|
| chainIndex | String | Unique identifier of the blockchain, e.g. 196: X Layer |
| chainName | String | Name of the blockchain, e.g. X Layer |
| success | Boolean | Indicates whether the settlement was successful |
| payer | String | Address of the payer |
| txHash | String | Transaction hash of the settlement (EVM: 0x hash; Solana: Base58) |
| errorMsg | String | Error message, e.g. insufficient_funds, invalid_payload, etc |
## Request example
```shell
curl --location --request POST 'https://web3.okx.com/api/v6/payments/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": 1,
"paymentPayload": {
"x402Version": 1,
"scheme": "exact",
"chainIndex": "196",,
"payload": {
"signature": "0xf3746613c2d920b5fdabc0856f2aeb2d4f88ee6037b8cc5d04a71a4462f13480",
"authorization": {
"from": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"to": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"value": "1000000000000000000",
"validAfter": "1716150000",
"validBefore": "1716150000",
"nonce": "0x1234567890abcdef1234567890abcdef12345678"
}
}
},
"paymentRequirements": {
"scheme": "exact",
"chainIndex": "196",,
"maxAmountRequired": "1000000",
"resource": "https://api.example.com/premium/resource/123",
"description": "Premium API access for data analysis",
"mimeType": "application/json",
"outputSchema": {
"data": "string"
},
"payTo": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"maxTimeoutSeconds": 10,
"asset": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"extra": {
"gasLimit": "1000000"
}
}
}'
```
## Response example
```json
{
"code": "0",
"msg": "success",
"data": [
{
"success": true,
"errorReason": null,
"payer": "0xcb30ed083ad246b126a3aa1f414b44346e83e67d",
"txHash": "0x4f46ed8eac92ddbccfb56a88ff827db3616c7beb191adabbeeded901340bd7d5",
"chainIndex": "196",
"chainName": "X Layer"
}
]
}
```
- [Verify the transaction](https://web3.okx.com/onchainos/dev-docs/payments/payment-verification.md)
{/* api-page */}
# Verify the transaction
Verify the legitimacy of the transaction.
## Request address
POST `https://web3.okx.com/api/v6/payments/verify`
## Request parameters
| Parameter | Type | Required | Description |
|---------------------|--------|----------|--------------------------------------------------------------------------------------------------------------|
| x402Version | String | Yes | Version of the x402 protocol (e.g. 1) |
| chainIndex | String | Yes | Unique identifier of the blockchain |
| paymentPayload | Object | Yes | The x402 payment payload carried by the client with the protected request |
| >x402Version | String | Yes | Version of the x402 protocol (e.g. 1) |
| >scheme | String | Yes | Settlement scheme, e.g. exact (one‑time fixed‑amount payment) |
| >payload | Object | Yes | Object containing payment signature and authorization data |
| >>signature | String | Yes | Cryptographic signature |
| >>authorization | Object | Yes | Authorization information |
| >>>from | String | Yes | Payer address |
| >>>to | String | Yes | Payee address |
| >>>value | String | Yes | Payment amount (in smallest unit, with precision) |
| >>>validAfter | String | Yes | Effective time (Unix timestamp) |
| >>>validBefore | String | Yes | Expiration time (Unix timestamp) |
| >>>nonce | String | Yes | Random nonce to prevent replay attacks |
| paymentRequirements | Object | Yes | Information describing what resource the payment grants access to (amount, network, asset, payee, etc.) |
| >scheme | String | Yes | Defines how the payment is settled, e.g. exact (one‑time fixed‑amount payment) |
| >resource | String | No | Server URL of the resource |
| >description | String | No | Description of the resource API endpoint |
| >mimeType | String | No | MIME type of the resource provider’s response |
| >maxAmountRequired | String | Yes | Maximum payable amount (in smallest unit, with precision) |
| >maxTimeoutSeconds | Integer| No | Maximum waiting time (in seconds) after authorization becomes valid |
| >payTo | String | Yes | Payee address |
| >asset | String | No | Asset identifier or contract address (depending on the network) |
| >outputSchema | Object | No | Optional parameter specifying the expected JSON structure of the returned resource data |
| >extra | Object | No | Optional additional parameters, e.g. gasLimit |
## Response parameters
| Parameter | Type | Description |
|---------------|---------|--------------------------------------------------------------------------------------------|
| isValid | Boolean | Whether the payment is valid (true = valid, false = invalid) |
| payer | String | Address of the payer |
| invalidReason | String | Reason for invalidation (e.g. insufficient_funds, invalid_network, etc.) |
## Request example
```shell
curl --request POST \
--url https://web3.okx.com/api/v6/payments/verify \
--header 'Authorization: Bearer ' \
--header 'Content-Type: application/json' \
--data '{
"x402Version": 1,
"paymentPayload": {
"x402Version": 1,
"scheme": "exact",
"chainIndex": "196",
"payload": {
"signature": "0xf3746613c2d920b5fdabc0856f2aeb2d4f88ee6037b8cc5d04a71a4462f13480",
"authorization": {
"from": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"to": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"value": "1000000000000000000",
"validAfter": "1716150000",
"validBefore": "1716150000",
"nonce": "0x1234567890abcdef1234567890abcdef12345678"
}
}
},
"paymentRequirements": {
"scheme": "exact",
"chainIndex": "196",
"maxAmountRequired": "1000000",
"resource": "https://api.example.com/premium/resource/123",
"description": "Premium API access for data analysis",
"mimeType": "application/json",
"outputSchema": {
"data": "string"
},
"payTo": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"maxTimeoutSeconds": 10,
"asset": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"extra": {
"gasLimit": "1000000"
}
}
}'
```
## Response example
```json
{
"code": "0",
"msg": "success",
"data": [
{
"isValid": true,
"invalidReason": null,
"payer": "0xcb30ed083ad246b126a3aa1f414b44346e83e67d"
}
]
}
```
- [Error code](https://web3.okx.com/onchainos/dev-docs/payments/error-code.md)
# Error code
| Error code | HTTP status | Prompt message |
| ---------- | ----------- | ------------------------------------------------------------------------------------- |
| 50011 | 429 | The user request frequency is too fast, exceeding the limit allowed by the interface. |
| 50014 | 400 | Required parameter param0 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 " error |
| 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 |
| 81001 | 200 | param0 parameter error |
| 81004 | 200 | Unsupported chain |
| 80007 | 200 | Risk address |
- [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:
App Wallet
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 |
| 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 |
- [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)
**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\