首页 > web前端 > js教程 > OKX DEX API 要点:Avalanche C 链上的单链和跨链互换

OKX DEX API 要点:Avalanche C 链上的单链和跨链互换

DDD
发布: 2024-11-28 05:32:11
原创
1089 人浏览过

OKX DEX API Essentials: Single and Cross-Chain Swaps on Avalanche C-Chain

准备好将 DEX 聚合和跨链交换集成到您的 EVM DApp 中了吗?本教程向您展示如何与 OKX DEX API 交互,以在单个链内以及 Avalanche C 链的不同区块链之间执行代币交换。您的实施将使用 Web3.js 和 OKX DEX API 来创建对报价、批准和互换执行的强大处理。默认情况下,此实现演示:

  • 单链互换:Avalanche C 链上的 AVAX 到 WAVAX
  • 跨链交换:Avalanche C 链上的 AVAX 到 Polygon 上的 POL

文件结构

本教程重点介绍 dexUtils.js 的实现,这是一个实用程序文件,其中包含与 OKX DEX API 交互所需的所有函数。该文件处理:

  • 网络和令牌配置
  • 标题结构
  • API端点和调用构造
  • 报价检索
  • 代币批准
  • 单链互换
  • 跨链交换

先决条件

开始之前,您需要:

  • 已安装 Node.js(v20 或更高版本)
  • Web3 和区块链概念的基础知识
  • 钱包地址和私钥
  • 来自 OKX 开发者门户的 OKX API 凭证(API 密钥、密钥和密码)
  • 来自 OKX 开发者门户的项目 ID
  • Git 安装在您的计算机上

设置

您有两种开始选择:

选项 1:本地开发

  1. 克隆存储库并切换到演示分支:
git clone https://github.com/Julian-dev28/okx-os-evm-swap-app.git
cd okx-os-evm-swap-app
git checkout avalanche-demo
登录后复制
登录后复制
  1. 安装依赖项:
npm install
登录后复制
登录后复制
  1. 设置环境变量:
REACT_APP_API_KEY=your_api_key
REACT_APP_SECRET_KEY=your_secret_key
REACT_APP_API_PASSPHRASE=your_passphrase
REACT_APP_PROJECT_ID=your_project_id
REACT_APP_USER_ADDRESS=your_wallet_address
REACT_APP_PRIVATE_KEY=your_private_key
登录后复制
登录后复制

选项 2:使用 Replit

  1. 分叉 Replit 项目:
    OKX OS Avalanche 交换应用程序

  2. 在 Replit Secrets 选项卡(位于“工具”面板中)中添加环境变量:

    • 点击“秘密”
    • 添加各个环境变量:
      • REACT_APP_API_KEY
      • REACT_APP_SECRET_KEY
      • REACT_APP_API_PASSPHRASE
      • REACT_APP_PROJECT_ID
      • REACT_APP_USER_ADDRESS
      • REACT_APP_PRIVATE_KEY
  3. 单击“运行”启动您的开发环境

初始配置

本节展示如何设置与 Avalanche C 链上的 OKX DEX 交互所需的网络配置和代币地址:

import Web3 from "web3";
import cryptoJS from "crypto-js";

// RPC endpoint for Avalanche C-Chain
const avalancheCMainnet = "https://avalanche-c-chain-rpc.publicnode.com";

// OKX DEX contract address on Avalanche
// Used to show token allowance
const okxDexAddress = "0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f";

// Standard token addresses
// baseTokenAddress represents the native token (ETH/AVAX) across chains
const baseTokenAddress = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
// WAVAX token address on Avalanche
const wavaxTokenAddress = "0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7";

// Initialize Web3 instance with Avalanche RPC
const web3 = new Web3(avalancheCMainnet);

// Base URL for API requests
const apiBaseUrl = "https://www.okx.com/api/v5/dex/aggregator";

/**
 * Helper function for constructing API URLs
 * @param {string} methodName - API endpoint path
 * @param {Object} queryParams - URL parameters
 * @returns {string} Complete API URL
 */
function getAggregatorRequestUrl(methodName, queryParams) {
    return (
        apiBaseUrl +
        methodName +
        "?" +
        new URLSearchParams(queryParams).toString()
    );
}
登录后复制
登录后复制

获取代币报价

报价功能检索当前价格和掉期路线。这是实现:

生成标头

git clone https://github.com/Julian-dev28/okx-os-evm-swap-app.git
cd okx-os-evm-swap-app
git checkout avalanche-demo
登录后复制
登录后复制

调用API

npm install
登录后复制
登录后复制

令牌批准

在交换之前为 ERC20 代币实现这些批准功能:

生成标头

REACT_APP_API_KEY=your_api_key
REACT_APP_SECRET_KEY=your_secret_key
REACT_APP_API_PASSPHRASE=your_passphrase
REACT_APP_PROJECT_ID=your_project_id
REACT_APP_USER_ADDRESS=your_wallet_address
REACT_APP_PRIVATE_KEY=your_private_key
登录后复制
登录后复制

调用API

import Web3 from "web3";
import cryptoJS from "crypto-js";

// RPC endpoint for Avalanche C-Chain
const avalancheCMainnet = "https://avalanche-c-chain-rpc.publicnode.com";

// OKX DEX contract address on Avalanche
// Used to show token allowance
const okxDexAddress = "0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f";

// Standard token addresses
// baseTokenAddress represents the native token (ETH/AVAX) across chains
const baseTokenAddress = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
// WAVAX token address on Avalanche
const wavaxTokenAddress = "0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7";

// Initialize Web3 instance with Avalanche RPC
const web3 = new Web3(avalancheCMainnet);

// Base URL for API requests
const apiBaseUrl = "https://www.okx.com/api/v5/dex/aggregator";

/**
 * Helper function for constructing API URLs
 * @param {string} methodName - API endpoint path
 * @param {Object} queryParams - URL parameters
 * @returns {string} Complete API URL
 */
function getAggregatorRequestUrl(methodName, queryParams) {
    return (
        apiBaseUrl +
        methodName +
        "?" +
        new URLSearchParams(queryParams).toString()
    );
}
登录后复制
登录后复制

单链互换

以下实现演示了在同一链内执行交换,特别是在 Avalanche C 链上从 AVAX 到 WAVAX:

/**
 * Generates headers required for OKX DEX quote API calls
 * Headers include timestamp, signature, and API credentials
 * 
 * @param {Object} quoteParams - Parameters for the quote request
 * @returns {Object} Headers object with required authentication
 */
function getQuoteHeaders(quoteParams) {
    const date = new Date();
    const timestamp = date.toISOString();

    // Create signature string following OKX API requirements
    const stringToSign =
        timestamp +
        "GET" +
        "/api/v5/dex/aggregator/quote?" +
        new URLSearchParams(quoteParams).toString();

    // Return headers with HMAC signature
    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,
    };
}
登录后复制

跨链互换

以下实现演示了如何执行从 AVAX(Avalanche C-Chain)到 MATIC(Polygon)的跨链交换,包括报价检索和交易执行:

/**
 * Fetches a quote from the OKX DEX Aggregator
 * Used to get current prices and optimal swap routes
 * 
 * @param {Object} quoteParams - Parameters including tokens, amount, and chain
 * @returns {Promise<Object>} Quote data including price and route information
 */
async function getQuote(quoteParams) {
    const apiRequestUrl = `${apiBaseUrl}/quote?${new URLSearchParams(quoteParams)}`;
    const response = await fetch(apiRequestUrl, {
        method: "GET",
        headers: getQuoteHeaders(quoteParams),
    });

    if (!response.ok) {
        throw new Error("Network response was not ok");
    }

    return response.json();
}
登录后复制

签署和发送交易

sendSignedTransaction 方法使用用户的钱包私钥签名并发送交易

/**
* Generates headers required for OKX DEX approve transaction API calls
* Headers include timestamp, signature, and API credentials
* 
* @param {Object} params - Parameters for the approve transaction
* @returns {Promise<Object>} Headers object with required authentication
*/
function getApproveTransactionHeaders(params) {
   const date = new Date();
   const timestamp = date.toISOString();
   const stringToSign =
       timestamp +
       "GET" +
       "/api/v5/dex/aggregator/approve-transaction?" +
       new URLSearchParams(params).toString();

   // Check if required environment variables are present
   if (!projectId || !apiKey || !secretKey || !apiPassphrase) {
       throw new Error(
           "Missing required environment variables for API authentication"
       );
   }

   return {
       "Content-Type": "application/json",
       "OK-PROJECT-ID": projectId,
       "OK-ACCESS-KEY": apiKey,
       "OK-ACCESS-SIGN": cryptoJS.enc.Base64.stringify(
           cryptoJS.HmacSHA256(stringToSign, secretKey)
       ),
       "OK-ACCESS-TIMESTAMP": timestamp,
       "OK-ACCESS-PASSPHRASE": apiPassphrase,
   };
}
登录后复制

使用功能

应用程序的灵活性通过 Params 对象、swapParams 和 quoteParams 来展示。这些对象充当配置点,使用户能够根据自己的具体要求自定义报价请求和掉期。

例如,在 swapParams 对象中,您将找到以下属性:

// ABI for ERC20 token allowance function
// This minimal ABI only includes the allowance function needed for checking token approvals
// Full ERC20 ABI not needed since we're only checking allowances
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",
    },
];

/**
 * Checks the current allowance for a token
 * Used to determine if approval is needed before swap
 * 
 * @param {string} ownerAddress - Address of token owner
 * @param {string} spenderAddress - Address of spender (DEX contract)
 * @param {string} tokenAddress - Address of token contract
 * @returns {Promise<number>} Current allowance amount
 */
async function getAllowance(ownerAddress, spenderAddress, tokenAddress) {
    const tokenContract = new web3.eth.Contract(tokenABI, tokenAddress);
    try {
        const allowance = await tokenContract.methods
            .allowance(ownerAddress, spenderAddress)
            .call();
        return parseFloat(allowance);
    } catch (error) {
        console.error("Failed to query allowance:", error);
        throw error;
    }
}


/**
 * Gets approval transaction data from the API
 * 
 * @param {string} chainId - Network chain ID
 * @param {string} tokenContractAddress - Token to approve
 * @param {string} approveAmount - Amount to approve
 * @returns {Promise<Object>} Approval transaction data
 */
async function approveTransaction(chainId, tokenContractAddress, approveAmount) {
    if (!chainId || !tokenContractAddress || !approveAmount) {
        throw new Error("Missing required parameters for approval");
    }

    const params = { chainId, tokenContractAddress, approveAmount };
    const apiRequestUrl = getAggregatorRequestUrl("/approve-transaction", params);
    const headersParams = getApproveTransactionHeaders(params);

    try {
        const response = await fetch(apiRequestUrl, {
            method: "GET",
            headers: headersParams,
        });

        if (!response.ok) {
            const errorData = await response.json().catch(() => null);
            throw new Error(
                `API request failed: ${response.status} ${response.statusText}${
                    errorData ? ` - ${JSON.stringify(errorData)}` : ""
                }`
            );
        }

        const data = await response.json();

        // Validate the response data
        if (!data || !data.data || !Array.isArray(data.data) || data.data.length === 0) {
            throw new Error("Invalid response format from approval API");
        }

        return data;
    } catch (error) {
        console.error("Approval request failed:", error);
        throw error;
    }
}

/**
 * Handles the approval transaction if needed
 * Checks current allowance and submits approval transaction if necessary
 * 
 * @param {string} approveAmount - Amount to approve for spending
 * @returns {Promise<Object|null>} Transaction receipt or null if approval not needed
 */
async function sendApproveTx(approveAmount) {
    // Skip approval for native tokens (ETH/AVAX)
    if (fromTokenAddress.toLowerCase() === baseTokenAddress.toLowerCase()) {
        return null;
    }

    const allowanceAmount = await getAllowance(
        user,
        spenderAddress,
        fromTokenAddress
    );

    // Only approve if current allowance is insufficient
    if (BigInt(allowanceAmount) < BigInt(approveAmount)) {
        const approvalResult = await approveTransaction(
            chainId,
            fromTokenAddress,
            approveAmount
        );

        // Prepare approval transaction with safety margins for gas
        const txObject = {
            nonce: await web3.eth.getTransactionCount(user),
            to: fromTokenAddress,
            gasLimit: BigInt(approvalResult.data[0].gasLimit) * BigInt(2),
            gasPrice: (BigInt(await web3.eth.getGasPrice()) * BigInt(3)) / BigInt(2),
            data: approvalResult.data[0].data,
            value: "0",
        };

        return sendSignedTransaction(txObject);
    }

    return null;
}
登录后复制

在这里,您可以指定chainId(您要使用的区块链网络)、fromTokenAddress和toTokenAddress(您要交换的代币)、您要交换的代币数量、可接受的滑点百分比以及您自己的值用户钱包地址。

dexUtils.js 对象中的 quoteParams 允许您配置源和目标区块链网络:

/**
 * Helper function to get headers for swap API calls
 * @param {Object} swapParams - Swap parameters
 * @returns {Object} Headers with authentication
 */
function getSwapHeaders(swapParams) {
    const date = new Date();
    const timestamp = date.toISOString();
    const stringToSign = 
        timestamp + 
        "GET" + 
        "/api/v5/dex/aggregator/swap?" + 
        new URLSearchParams(swapParams).toString();

    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,
    };
}

/**
 * Helper function to get swap data from API
 * @param {Object} swapParams - Swap parameters
 * @returns {Promise<Object>} Swap transaction data
 */
async function getSwapData(swapParams) {
    const apiRequestUrl = getAggregatorRequestUrl("/swap", swapParams);
    const response = await fetch(apiRequestUrl, {
        method: "GET",
        headers: getSwapHeaders(swapParams),
    });

    if (!response.ok) {
        throw new Error("Network response was not ok");
    }

    return response.json();
}

/**
 * Executes a single-chain token swap
 * Handles the main swap transaction after approval
 * 
 * @param {Object} swapParams - Parameters for the swap
 * @returns {Promise<Object>} Transaction receipt
 */
async function sendSwapTx(swapParams) {
    // Get swap transaction data from API
    const { data: swapData } = await getSwapData(swapParams);

    // Validate swap data
    if (!swapData || swapData.length === 0 || !swapData[0].tx) {
        throw new Error("Invalid swap data received");
    }

    const swapDataTxInfo = swapData[0].tx;
    const nonce = await web3.eth.getTransactionCount(user, "latest");

    // Prepare transaction with adjusted gas parameters for safety
    const signTransactionParams = {
        data: swapDataTxInfo.data,
        gasPrice: BigInt(swapDataTxInfo.gasPrice) * BigInt(ratio),
        to: swapDataTxInfo.to,
        value: swapDataTxInfo.value,
        gas: BigInt(swapDataTxInfo.gas) * BigInt(ratio),
        nonce,
    };

    return sendSignedTransaction(signTransactionParams);
}
登录后复制

在此示例中,您可以指定 fromChainId(您起始的区块链网络)和 toChainId(您要交换到的区块链网络),以及 fromTokenAddress 和 toTokenAddress。这使您可以轻松地在不同的区块链生态系统之间移动您的代币,例如从 Avalanche 到 Polygon。

此外,您可以设置 receiveAddress 来指定交换的代币应发送到的位置,调整滑点容差,甚至配置 PriceImpactProtectionPercentage 以防止不利的价格变动。

通过公开这些配置选项,应用程序变得具有高度适应性,使开发人员能够根据用户的特定需求定制应用程序。

通过查看示例 React 应用程序,您可以找到如何在组件中实现这些功能并将其集成到应用程序中的工作示例。

结论

感谢您花时间查看本教程!我希望所提供的信息有助于了解如何在您自己的项目中利用 OKX DEX Aggregator API 的强大功能。

其他资源

  • OKX DEX API 文档
  • Web3.js 文档
  • Avalanche C 链文档

觉得这有帮助吗?不要忘记查看文章开头的资源,包括样板代码和文档。加入 OKX OS 社区与其他开发者联系,并在 Twitter 上关注 Julian 以获取更多 Web3 开发内容!


此内容仅供参考,可能涵盖您所在地区不提供的产品。仅代表作者观点,不代表OKX立场。它无意提供 (i) 投资建议或投资推荐; (ii) 购买、出售或持有数字资产的要约或招揽,或 (iii) 财务、会计、法律或税务建议。数字资产持有量,包括稳定币和 NFT,风险较高,波动较大。您应该根据您的财务状况仔细考虑交易或持有数字资产是否适合您。有关您具体情况的问题,请咨询您的法律/税务/投资专业人士。本文中出现的信息(包括市场数据和统计信息,如果有)仅供一般参考之用。尽管我们在准备这些数据和图表时已采取了所有合理的谨慎措施,但对于此处表达的任何事实错误或遗漏,我们不承担任何责任。 OKX Web3 钱包和 OKX NFT 市场均受 www.okx.com 上单独的服务条款约束。

© 2024 OKX。本文可以全文复制或分发,也可以使用本文 100 字或更少的摘录,前提是此类使用是非商业性的。 任何对整篇文章的复制或分发还必须在显着位置注明:“本文版权所有 © 2024 OKX,经许可使用。” 允许的摘录必须引用文章名称并包含出处,例如“在短短 30 分钟内集成 OKX DEX Widget,Julian Martinez,© 2024 OKX”。 不允许对本文进行衍生作品或其他用途。

以上是OKX DEX API 要点:Avalanche C 链上的单链和跨链互换的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板