DEX API
构建限价单应用

构建限价单应用#

在本指南中,我们将通过欧易 DEX 提供一个用例来进行限价单下单。这个过程包括:

  • 设置你的环境
  • 检查授权额度
  • 创建订单
  • 取消订单

1. 设置你的环境#

导入必要的 Node.js 库并设置你的环境变量以及定义辅助函数和组装参数 Node.js 环境设置

2. 检查授权额度#

2.1 请参考查询授权额度教程#

查询授权额度

  • 下文的 allowanceAmount 代表真实的链上授权额度

2.2 获取授权数量#

获取数量。如果 allowanceAmount !== '0',请查看步骤 4。如果 allowanceAmount === '0',请查看步骤 5。

const { data: allowanceData } = await getAllowanceData();
const allowanceAmount = allowanceData?.[0]?.allowanceAmount;

3. 创建订单#

提示
如果 allowanceAmount 大于零,则表示已执行批准操作,可以直接创建订单。

3.1 离线签名#

采用 EIP712 结构化签名,签名时钱包将显示订单结构化内容。

const ethers = require('ethers');

// Build domain data
const domainData = {
    name: 'OKX LIMIT ORDER',
    version: '2.0',
    chainId: 1, // The chainId of the ETH mainnet
    verifyingContract: '0x2ae8947FB81f0AAd5955Baeff9Dcc7779A3e49F2' // LimitOrder contract address
};

// Define the limit order type
const Order = [
    { name: "salt", type: "uint256" },
    { name: "makerToken", type: "address" },
    { name: "takerToken", type: "address" },
    { name: "maker", type: "address" },
    { name: "receiver", type: "address" },
    { name: "allowedSender", type: "address" },
    { name: "makingAmount", type: "uint256" },
    { name: "takingAmount", type: "uint256" },
    { name: "minReturn", type: "uint256" },
    { name: "deadLine", type: "uint256" },
    { name: "partiallyAble", type: "bool" }
];

const orderData = {
    salt: 1702979522,
    makerToken: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
    takerToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
    maker: "0x5F73e69237eB5bA3544273D165907447bF6a0AA7",
    receiver: "0x5F73e69237eB5bA3544273D165907447bF6a0AA7",
    allowedSender: "0x0000000000000000000000000000000000000000",
    makingAmount: 1000000,
    takingAmount: 1000000,
    minReturn: 1000000,
    deadLine: 1703254942,
    partiallyAble: true
}

// Build EIP-712 messages
const message = {
    domain: domainData,
    types: { Order },
    value: orderData,
};

// Create an Ethereum signature wallet
const privateKey = '<YOUR_PRIVATE_KEY>';
const wallet = new ethers.Wallet(privateKey);

(async () => {
    // Calculate the EIP-712 orderHash
    const orderHash = ethers.utils._TypedDataEncoder.hash(message.domain,
        message.types,
        message.value);
    console.log("Order data:", orderData);
    console.log("Order Hash:", orderHash);

    // Sign the message with the privatekey
    const signature =
        await wallet._signTypedData(
            message.domain,
            message.types,
            message.value
        );
    console.log("Order signature:", signature);

})();


3.2 定义参数#

const limitOrderRequestParams = { orderHash,orderData,chainId, signature };

3.3 下单#

const resp = await fetch(apiBaseUrl +"/limit-order/save-order", {
    method: "POST",
    body: JSON.stringify(limitOrderRequestParams),
    headers: headersParams,
  });

4. 取消订单#

const ethers = require('ethers');

// 示例限价单数据
const orderData = {
    salt: 1700110500,    //随机数盐,作为幂等标识,(传入当前时间戳)
    makerToken: "0xMakerTokenAddress",    //兑入币种地址
    takerToken: "0xTakerTokenAddress",    //兑出币种地址
    maker: "0xMakerAddress",    //用户钱包地址
    receiver: "0xTakerAddress",    //用户指定收款地址
    allowedSender: "0xAllowedSender",    //用户指定交易对方地址
    makingAmount: 2000,    //兑入币种数量
    takingAmount: 1000,    //兑出币种数量
    minReturn: 950,    //最少兑出币种数量,用于滑点控制
    deadLine: 1700120500,    //订单超时时间戳
    partiallyAble: false    //是否支持部分成交
};

// 连接到以太坊节点
const provider = new ethers.providers.JsonRpcProvider("https://mainnet.infura.io/v3/your_infura_project_id");

// 合约地址和 ABI
const contractAddress = "0x2ae8947FB81f0AAd5955Baeff9Dcc7779A3e49F2"; // LimitOrder合约地址
const contractABI = [
    {
        "inputs": [
            {
                "components": [
                    {
                        "internalType": "uint256",
                        "name": "salt",
                        "type": "uint256"
                    },
                    {
                        "internalType": "address",
                        "name": "makerToken",
                        "type": "address"
                    },
                    {
                        "internalType": "address",
                        "name": "takerToken",
                        "type": "address"
                    },
                    {
                        "internalType": "address",
                        "name": "maker",
                        "type": "address"
                    },
                    {
                        "internalType": "address",
                        "name": "receiver",
                        "type": "address"
                    },
                    {
                        "internalType": "address",
                        "name": "allowedSender",
                        "type": "address"
                    },
                    {
                        "internalType": "uint256",
                        "name": "makingAmount",
                        "type": "uint256"
                    },
                    {
                        "internalType": "uint256",
                        "name": "takingAmount",
                        "type": "uint256"
                    },
                    {
                        "internalType": "uint256",
                        "name": "minReturn",
                        "type": "uint256"
                    },
                    {
                        "internalType": "uint256",
                        "name": "deadLine",
                        "type": "uint256"
                    },
                    {
                        "internalType": "bool",
                        "name": "partiallyAble",
                        "type": "bool"
                    }
                ],
                "internalType": "struct OrderLibV2.Order",
                "name": "_order",
                "type": "tuple"
            }
        ],
        "name": "cancelOrder",
        "outputs": [
            {
                "internalType": "uint256",
                "name": "orderRemaining",
                "type": "uint256"
            },
            {
                "internalType": "bytes32",
                "name": "orderHash",
                "type": "bytes32"
            }
        ],
        "stateMutability": "nonpayable",
        "type": "function"
    }
];

// 使用合约 ABI 和地址创建合约实例
const contract = new ethers.Contract(contractAddress, contractABI, provider);

// 使用私钥创建钱包
const privateKey = "your_private_key";
const wallet = new ethers.Wallet(privateKey, provider);

// 撤销订单
async function cancelOrder(orderData) {
    const tx = await contract.connect(wallet).cancelOrder(orderData);
    await tx.wait;
    console.log("txhash:", tx.hash);
}

// 交互示例
(async () => {
    await cancelOrder(orderData);
})();