Build Your DApp#
If you're a DApp developer, this demo shows you how to build your DApp.
Example: Using the Trade API endpoint for token swaps. You'll swap USDC for ETH on the Ethereum network.
1. Set Up Your Environment#
// --------------------- 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.okx200.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.okx200.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.
/**
* 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<bigint> {
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#
const getApproveTransactionParams = {
chainIndex: chainIndex,
tokenContractAddress: tokenAddress,
approveAmount: amount
};
3.2 Define helper functions#
async function getApproveTransaction(
tokenAddress: string,
amount: string
): Promise<any> {
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.
/**
* 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<string> {
try {
const path = 'dex/pre-transaction/gas-limit';
const url = `https://web3.okx200.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.
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#
/**
* 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<string | null> {
const spenderAddress = '0x3b3ae790Df4F312e745D270119c6052904FB6790'; // Ethereum Mainnet DEX spender
// See Router addresses at: https://web3.okx200.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#
const quoteParams = {
amount: fromAmount,
chainIndex: chainIndex,
toTokenAddress: toTokenAddress,
fromTokenAddress: fromTokenAddress,
};
4.2 Define helper functions#
/**
* 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<any> {
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#
const swapParams = {
chainIndex: chainIndex,
fromTokenAddress,
toTokenAddress,
amount,
userWalletAddress: userAddress,
slippagePercent
};
5.2 Request swap transaction data#
/**
* 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<any> {
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@okx200.com to request access.
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.okx200.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.
/**
* 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<string> {
try {
const path = 'dex/pre-transaction/gas-limit';
const url = `https://web3.okx200.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;
}
}
- 1. Set Up Your Environment2. Check Allowance3. Check the Approval Parameters and Initiate the Approval3.1 Define your transaction approval parameters3.2 Define helper functions3.3 Create Compute gasLimit utility function3.4 Get transaction information and send approveTransaction4. Get Quote Data4.1 Define quote parameters4.2 Define helper functions5. Prepare Transaction5.1 Define swap parameters5.2 Request swap transaction data6. Simulate Transaction7. Broadcast Transaction
