Manage Orders
This guide shows you how to:
Create an order.
Place an order.
Cancel an order.
Query orders by subaccount.
If you inspect the underlying types for these transactions, you'll notice that a nonce
field is required. This is a unique integer in ascending order. Our off-chain engine has a nonce
query to return the latest nonce for a given subaccount. All this is abstracted away within the SDK, so you do not need to manually use this query.
Import the functions
import { getVertexClient, prettyPrintJson } from "./common";
import { OrderActionParams } from "@vertex-protocol/client";
import { nowInSeconds, toFixedPoint } from "@vertex-protocol/utils";
import { getExpirationTimestamp } from "@vertex-protocol/contracts";
Scaffold Your Subaccount
To place orders, we need a subaccount with funds. We need to perform the deposit funds step as before, this time with 1000 USDC.
const vertexClient = getVertexClient();
const { walletClient, publicClient } = vertexClient.context;
const address = walletClient!.account.address;
const subaccountName = 'default';
const depositAmount = toFixedPoint(1000, 6);
const mintTxHash = await vertexClient.spot._mintMockERC20({
amount: depositAmount,
productId: 0,
});
await publicClient.waitForTransactionReceipt({
hash: mintTxHash,
});
const approveTxHash = await vertexClient.spot.approveAllowance({
amount: depositAmount,
productId: 0,
});
await publicClient.waitForTransactionReceipt({
hash: approveTxHash,
});
const depositTxHash = await vertexClient.spot.deposit({
subaccountName: 'default',
amount: depositAmount,
productId: 0,
});
await publicClient.waitForTransactionReceipt({
hash: depositTxHash,
});
await new Promise((resolve) => setTimeout(resolve, 10000));
Create an order
Placing an order requires a number of parameters, represented by the PlaceOrderParams['order']
type.
In the example below:
The order
expiration
time is given by calling thenowInSeconds
function from theutils
package and adding 60 seconds. This means the order will expire 60 seconds from now.Notice the usage of
getExpirationTimestamp
, order types, such as IOC (immediate or cancel) are encoded in the expiration field, thegetExpirationTimestamp
function will return the correct expiration timestamp for the given order type.
The
price
field is set at80000
- a low value (at the time of writing) to prevent execution. This enables us to cancel the order later on without it being instantly filled. Please adjust this price accordingly.The
amount
field is set at10**16
- this is the amount to buy/sell. A positive value is to buy, negative is to sell.Amount is normalized to 18 decimal places, which is what
toFixedPoint
does by default.NOTE: Min limit order size for
BTC
is10**16
and forETH
is10**17
. Orders below these sizes will fail to be placed.
const orderParams: PlaceOrderParams['order'] = {
// When using the `placeOrder` call, the `subaccountOwner` defaults to the
// address of the `walletClient`
subaccountName: 'default',
expiration: getExpirationTimestamp({
expirationTime: nowInSeconds() + 60,
reduceOnly: false,
type: 'post_only',
}),
price: 80000,
// Setting order amount to 10**16
amount: toFixedPoint(0.01, 18),
};
Place the order
Use the order parameters to place the order with the placeOrder
function.
const placeOrderResult = await vertexClient.market.placeOrder({
order: orderParams,
productId: 2,
// Used for spot orders to enable/disable borrowing
spotLeverage: undefined,
});
prettyPrintJson("Place Order Result", placeOrderResult);
Alternative order placement
Alternatively, you can manually use payloadBuilder
to manually generate the place order payload. This may be useful in cases where you want to build the tx
separately from sending the execute API call.
// Use one of the following to generate a payload
vertexClient.context.engineClient.payloadBuilder.buildPlaceOrderPayload(...)
vertexClient.context.engineClient.payloadBuilder.buildPlaceOrderPayloadSync(...)
// Then execute
vertexClient.context.engineClient.execute('place_order', placeOrderPayload.payload);
Order digest
You can optionally generate the order digest, which can then be used to further manage the order e.g: cancelling the order. The order digest is also returned upon executing the placeOrder
transaction.
import { getOrderDigest } from "@vertex-protocol/contracts";
const productId = 2;
const orderParams: EIP712OrderParams = {
subaccountOwner: address,
subaccountName,
expiration: getExpirationTimestamp({
expirationTime: nowInSeconds() + 60,
reduceOnly: false,
type: 'post_only',
}),
price: 80000,
// Setting order amount to 10**16
amount: toFixedPoint(0.01, 18),
nonce: getOrderNonce(),
};
// Optional: generate a digest ahead of time so that you can manage the order, alternatively, the digest
// will be returned via placeOrderResult.data.digest
const orderbookAddress =
await vertexClient.context.engineClient.getOrderbookAddress(productId);
const orderDigest = getOrderDigest({
chainId: walletClient!.chain.id,
order: orderParams,
verifyingAddr: orderbookAddress,
});
Query orders on the subaccount
Now we can query the subaccount for open orders with the getOpenSubaccountOrders
function.
const openOrders = await vertexClient.market.getOpenSubaccountOrders({
subaccountOwner: address,
subaccountName,
productId: 2,
});
prettyPrintJson('Subaccount Open Orders', openOrders);
Cancel order
Cancel the order using the digest of the placed order. You can cancel multiple orders at once.
const cancelOrderResult = await vertexClient.market.cancelOrders({
digests: [placeOrderResult.data.digest],
productIds: [2],
subaccountName: 'default',
});
prettyPrintJson('Cancel Order Result', cancelOrderResult);
Query Orders to Verify Cancellation
Run query orders on the subaccount again to make sure the cancellation was successful.
Clean up
Finally, clean up by withdrawing the same amount as you have deposited, minus the 1 USDC withdrawal fee.
await vertexClient.spot.withdraw({
productId: 0,
amount: depositAmount - toFixedPoint(1, 6),
subaccountName,
});
Full example
import { PlaceOrderParams } from '@vertex-protocol/client';
import { getExpirationTimestamp } from '@vertex-protocol/contracts';
import { nowInSeconds, toFixedPoint } from '@vertex-protocol/utils';
import { getVertexClient, prettyPrintJson } from './common';
async function main() {
const vertexClient = getVertexClient();
const { walletClient, publicClient } = vertexClient.context;
const address = walletClient!.account.address;
const subaccountName = 'default';
const depositAmount = toFixedPoint(1000, 6);
const mintTxHash = await vertexClient.spot._mintMockERC20({
amount: depositAmount,
productId: 0,
});
await publicClient.waitForTransactionReceipt({
hash: mintTxHash,
});
const approveTxHash = await vertexClient.spot.approveAllowance({
amount: depositAmount,
productId: 0,
});
await publicClient.waitForTransactionReceipt({
hash: approveTxHash,
});
const depositTxHash = await vertexClient.spot.deposit({
subaccountName: 'default',
amount: depositAmount,
productId: 0,
});
await publicClient.waitForTransactionReceipt({
hash: depositTxHash,
});
await new Promise((resolve) => setTimeout(resolve, 10000));
const orderParams: PlaceOrderParams['order'] = {
subaccountName,
expiration: getExpirationTimestamp({
expirationTime: nowInSeconds() + 60,
reduceOnly: false,
type: 'post_only',
}),
price: 80000,
// Setting order amount to 10**16
amount: toFixedPoint(0.01, 18),
};
const placeOrderResult = await vertexClient.market.placeOrder({
order: orderParams,
productId: 2,
// Used for spot orders to enable/disable borrowing
spotLeverage: undefined,
});
prettyPrintJson('Place Order Result', placeOrderResult);
const openOrders = await vertexClient.market.getOpenSubaccountOrders({
subaccountOwner: address,
subaccountName,
productId: 2,
});
prettyPrintJson('Subaccount Open Orders', openOrders);
const cancelOrderResult = await vertexClient.market.cancelOrders({
digests: [placeOrderResult.data.digest],
productIds: [2],
subaccountName: 'default',
});
prettyPrintJson('Cancel Order Result', cancelOrderResult);
await vertexClient.spot.withdraw({
productId: 0,
amount: depositAmount - toFixedPoint(1, 6),
subaccountName,
});
}
main();
Last updated