Build limit order applications#
In this guide, we will provide an example token limit order through OKX DEX. This process includes:
- Set up your environment
- Check allowance
- Create order
- Cancel order
1. Set up your environment#
Import the necessary Node.js libraries and set your environment variables as well as define helper functions and assembly parameters Node.js Environment Settings.
2. Check allowance#
2.1 Please refer to the tutorial#
- The variable allowanceAmount in the following text represents the actual allowance amount on the blockchain.
2.2 Get allowance amount#
Obtain the specific quantity. If allowanceAmount !== '0'
, please check step 4. If allowanceAmount === '0'
, please check step 5.
const { data: allowanceData } = await getAllowanceData();
const allowanceAmount = allowanceData?.[0]?.allowanceAmount;
3. Create order#
Tip
If allowanceAmount is greater than zero, it indicates that the approval
operation has been performed and the transaction can be directly sent.
3.1 Offline signature#
Structured signature using EIP712, the wallet will show the order structured content when signing.
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 Define parameters#
const limitOrderRequestParams = { orderHash, orderData, chainId, signature };
3.3 Create order#
const resp = await fetch(apiBaseUrl +"/limit-order/save-order", {
method: "POST",
body: JSON.stringify(limitOrderRequestParams),
headers: headersParams,
});
4. Cancel order#
const ethers = require('ethers');
// Example Limit Order Data
const orderData = {
salt: 1700110500, // random number salt as idempotent identifier , Current timestamp (millisecond value)
makerToken: "0xMakerTokenAddress", //Address of makerToken
takerToken: "0xTakerTokenAddress", //Address of takerToken
maker: "0xMakerAddress", //Address of order signer
receiver: "0xTakerAddress", //Default is zero address, and the recipient’s assets will be sent to the address of the limit order creator. If you set a value, the asset will be sent to the current address.
allowedSender: "0xAllowedSender", //User-specified counterparty address
makingAmount: 2000, //The number of a token to be sold
takingAmount: 1000, //The number of a token to be bought
minReturn: 950, //Minimum number of currencies to be cashed out for slippage control
deadLine: 1700120500, //Order Timeout Timestamp
partiallyAble: false //Whether to support partial transaction
};
// Connecting to an Ethernet node
const provider = new ethers.providers.JsonRpcProvider("https://mainnet.infura.io/v3/your_infura_project_id");
// Contract address and ABI
const contractAddress = "0x2ae8947FB81f0AAd5955Baeff9Dcc7779A3e49F2"; // LimitOrder contract address
const contractABI = [
{
"inputs": [
{
"components": [
{
"internalType": "uint256",
"name": "salt",
"type": "uint256"
},
{
"internalType": "address",
"name": "makerToken",
"type": "address"
},
{
"internalType": "address",
"name": "takerToken",
"type": "address"
},
{
"internalType": "address",
"name": "maker",
"type": "address"
},
{
"internalType": "address",
"name": "receiver",
"type": "address"
},
{
"internalType": "address",
"name": "allowedSender",
"type": "address"
},
{
"internalType": "uint256",
"name": "makingAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "takingAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "minReturn",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "deadLine",
"type": "uint256"
},
{
"internalType": "bool",
"name": "partiallyAble",
"type": "bool"
}
],
"internalType": "struct OrderLibV2.Order",
"name": "_order",
"type": "tuple"
}
],
"name": "cancelOrder",
"outputs": [
{
"internalType": "uint256",
"name": "orderRemaining",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "orderHash",
"type": "bytes32"
}
],
"stateMutability": "nonpayable",
"type": "function"
}
];
// Creating Contract Instances with Contract ABIs and Addresses
const contract = new ethers.Contract(contractAddress, contractABI, provider);
// Creating a wallet with a private key
const privateKey = "your_private_key";
const wallet = new ethers.Wallet(privateKey, provider);
// Cancel order
async function cancelOrder(orderData) {
const tx = await contract.connect(wallet).cancelOrder(orderData);
await tx.wait;
console.log("txhash:", tx.hash);
}
// Example of interaction
(async () => {
await cancelOrder(orderData);
})();