For an example using a separate approve transaction rather than permit, see create_order_approve.ts.
Direct Orders
This example submits a BUY order request to the OrderProcessor contract. This process involves two method calls bundled together into one transaction using the OrderProcessor's multicall utility.
// ------------------ Configure Order ------------------// buy order amount (100 USDC)constorderAmount=BigInt(100_000_000);// buy order (Change to true for Sell Order)constsellOrder=false;// market orderconstorderType=Number(0);// check the order precision doesn't exceed max decimals// applicable to sell and limit orders onlyif (sellOrder || orderType ===1) {constallowedDecimalReduction=awaitorderProcessor.orderDecimalReduction(assetTokenAddress);constallowablePrecisionReduction=10** allowedDecimalReduction;if (Number(orderAmount) % allowablePrecisionReduction !=0) {constassetTokenDecimals=awaitassetToken.decimals();constmaxDecimals= assetTokenDecimals - allowedDecimalReduction;thrownewError(`Order amount precision exceeds max decimals of ${maxDecimals}`); }}constorderParams= { requestTimestamp:Date.now(), recipient:signer.address, assetToken: assetTokenAddress, paymentToken: paymentTokenAddress, sell: sellOrder, orderType: orderType, assetTokenQuantity:0,// Asset amount to sell. Ignored for buys. Fees will be taken from proceeds for sells. paymentTokenQuantity: Number(orderAmount), // Payment amount to spend. Ignored for sells. Fees will be added to this amount for buys.
price:0,// Unused limit price tif:1,// GTC};
The first step is to determine the fees to add to the desired order amount.
// get fees, fees will be added to buy order deposit or taken from sell order proceeds// TODO: get fees quote for sell orderconstfeeQuoteData= { chain_id: chainId, contract_address: orderProcessorAddress, order_data: orderParams};constfeeQuoteResponse=awaitdinariClient.post("/api/v1/web3/orders/fee", feeQuoteData);constfees=BigInt(feeQuoteResponse.data.fee_quote.fee);consttotalSpendAmount= orderAmount + fees;console.log(`fees: ${ethers.utils.formatUnits(fees,6)}`);
The first method call - selfPermit - gives the OrderProcessor permission to spend the payment token by pulling the order amount + fees from the user's account.
The second method call - createOrder - submits the order request to be filled by the protocol. This is submitted with the spending permit.
Once the transaction is mined, the event logs from resulting transaction receipt can be unpacked to obtain the order recipient's order index. The recipient's order index can be used to query the OrderProcessor for the current state of the order or look up the event history for that order.
The Permit and FeeQuote data have a deadline. If createOrder is attempted after one of these deadlines, the transaction will fail.
// ------------------ Submit Order ------------------// createOrder call data// see IOrderProcessor.Order struct for order parametersconstrequestOrderData=orderProcessor.interface.encodeFunctionData("createOrder", [[orderParams.requestTimestamp,orderParams.recipient,orderParams.assetToken,orderParams.paymentToken,orderParams.sell,orderParams.orderType,orderParams.assetTokenQuantity,orderParams.paymentTokenQuantity,orderParams.price,orderParams.tif,], [feeQuoteResponse.data.fee_quote.orderId,feeQuoteResponse.data.fee_quote.requester,feeQuoteResponse.data.fee_quote.fee,feeQuoteResponse.data.fee_quote.timestamp,feeQuoteResponse.data.fee_quote.deadline,],feeQuoteResponse.data.fee_quote_signature]);// submit permit + create order multicall transactionconsttx=awaitorderProcessor.multicall([ selfPermitData, requestOrderData,]);constreceipt=awaittx.wait();console.log(`tx hash: ${tx.hash}`);// get order id from eventconst orderEvent = receipt.logs.filter((log: any) => log.topics[0] === orderProcessor.interface.getEventTopic("OrderCreated")).map((log: any) => orderProcessor.interface.parseLog(log))[0];
if (!orderEvent) thrownewError("no order event");constorderId=orderEvent.args[0];constorderAccount=orderEvent.args[1];console.log(`Order ID: ${orderId}`);console.log(`Order Account: ${orderAccount}`);// use order id to get order status (ACTIVE, FULFILLED, CANCELLED)constorderStatus=awaitorderProcessor.getOrderStatus(orderId);console.log(`Order Status: ${orderStatus}`);