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 { Wallet } from 'ethers';
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.
An order requires a number of parameters, encapsulated by the OrderActionParams['order'] type.
In the example below:
The order expiration time is given by calling the nowInSeconds function from the utils 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, the getExpirationTimestamp function will return the correct expiration timestamp for the given order type.
The price field is set at 20000 - 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 at 10**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 size for BTC is 10**16 and for ETH is 10**17. Orders below these sizes will fail to be placed.
Alternatively, you can create an order tx and interface with lower level methods to place the order. The order parameters are encapsulated by OrderParams.
import { Wallet } from 'ethers';
import { getVertexClient, prettyPrintJson } from "./common";
import { OrderActionParams } from "@vertex-protocol/client";
import { nowInSeconds } from "@vertex-protocol/utils";
import { getExpirationTimestamp } from "@vertex-protocol/contracts";
async function main() {
const vertexClient = await getVertexClient();
const address = await (
vertexClient.context.signerOrProvider as Wallet
).getAddress();
const subaccountName = "default";
const depositAmount = 10 ** 6;
// SETUP - skipping logging here as it's in depositWithdraw
let tx = await vertexClient.spot._mintMockERC20({
productId: 0,
amount: depositAmount,
});
await tx.wait();
tx = await vertexClient.spot.approveAllowance({
productId: 0,
amount: depositAmount,
});
await tx.wait();
tx = await vertexClient.spot.deposit({
productId: 0,
amount: depositAmount,
subaccountName,
});
await tx.wait();
await new Promise((resolve) => setTimeout(resolve, 10000));
// Create the order
const orderParams: OrderActionParams["order"] = {
subaccountName,
// `nowInSeconds` is exposed by the `@vertex-protocol/utils` package
// This gives 60s before the order expires
// Currently, IOC is also supported as an expiration type
expiration: getExpirationTimestamp("default", nowInSeconds() + 60).toString(),
// Limit price
// Set this to a low amount so that the order does not fill immediately, this might need adjustment based on the product & current price
price: 20000,
// Positive amount for buys, negative for sells
amount: 1,
};
// Place the order
const placeOrderResult = await vertexClient.market.placeOrder({
order: orderParams,
productId: 1,
});
prettyPrintJson("Place Order Result", placeOrderResult);
// Now query orders for this subaccount
const openOrders = await vertexClient.market.getOpenSubaccountOrders({
subaccountOwner: address,
subaccountName,
productId: 1,
});
prettyPrintJson("Subaccount Open Orders", openOrders);
// Now cancel the order by its digest, you can cancel multiple at once
const cancelOrderResult = await vertexClient.market.cancelOrder({
digests: [placeOrderResult.digest],
productIds: [1],
subaccountName,
});
prettyPrintJson("Cancel Order Result", cancelOrderResult);
// Now query orders after cancellation
const openOrdersAfterCancel =
await vertexClient.market.getOpenSubaccountOrders({
subaccountOwner: address,
subaccountName,
productId: 1,
});
prettyPrintJson("Subaccount Open Orders After Cancel", openOrdersAfterCancel);
// Cleanup by withdrawing
await vertexClient.spot.withdraw({
productId: 0,
amount: depositAmount - 10 ** 5,
subaccountName,
});
}
main();