Orders
How it works
Orders on Drift go through a multi-stage matching process. When you place an order, it enters a JIT auction (Just-In-Time) where market makers can compete to fill it at better prices. If no one fills during the auction, the order either executes against the DLOB (Decentralized Limit Order Book) or the AMM as a fallback. This design ensures you get the best price from multiple liquidity sources.
Drift supports several order types: market (immediate execution), limit (rests on the orderbook at a specific price), oracle (price pegged to oracle with an offset), and trigger orders (conditional execution when a price threshold is hit). Each order has parameters like size, price, post-only flags, and reduce-only settings that control how it behaves.
Orders are stored in your user account and have both an onchain order ID and an optional user-assigned ID for tracking. When an order fills, your position updates automatically, and you can query fill events to see execution details.
SDK Usage
This page focuses on placing and canceling orders via DriftClient. For concise examples we use helper builders like getMarketOrderParams(...).
Build Market Order Params
import { BN, BASE_PRECISION, MarketType, PositionDirection, getMarketOrderParams } from "@drift-labs/sdk";
const orderParams = getMarketOrderParams({
marketIndex: 0,
marketType: MarketType.PERP,
direction: PositionDirection.LONG,
baseAssetAmount: new BN(1).mul(BASE_PRECISION), // 1 SOL (in 1e9 precision)
});Function getMarketOrderParamsReference ↗
Function getMarketOrderParamsReference ↗| Parameter | Type | Required |
|---|---|---|
params | Omit<OptionalOrderParams, "orderType"> | Yes |
| Returns |
|---|
OptionalOrderParams |
Build Order Params (Generic Helper)
If you want a single helper that works for limit/market/oracle/trigger, use getOrderParams(...).
import { getOrderParams, OrderType, PositionDirection } from "@drift-labs/sdk";
const orderParams = getOrderParams({
orderType: OrderType.LIMIT,
marketIndex: 0,
direction: PositionDirection.LONG,
baseAssetAmount: driftClient.convertToPerpPrecision(1), // 1 base unit → BN(1e9)
price: driftClient.convertToPricePrecision(21.23), // $21.23 → BN(21_230_000)
});Function getOrderParamsReference ↗
Function getOrderParamsReference ↗Creates an OrderParams object with the given OptionalOrderParams and any params to override.
example: ``` const orderParams = getOrderParams(optionalOrderParams, { marketType: MarketType.PERP }); ```
| Parameter | Type | Required |
|---|---|---|
optionalOrderParams | OptionalOrderParams | Yes |
overridingParams | Record<string, any> | No |
| Returns |
|---|
OrderParams |
Place a Perp Order
// Assumes `driftClient` is subscribed.
const txSig = await driftClient.placePerpOrder(
getMarketOrderParams({
marketIndex: 0,
direction: PositionDirection.LONG,
baseAssetAmount: new BN(1).mul(BASE_PRECISION),
})
);
console.log(txSig);Method DriftClient.placePerpOrderReference ↗
Method DriftClient.placePerpOrderReference ↗| Parameter | Type | Required |
|---|---|---|
orderParams | OptionalOrderParams | Yes |
txParams | TxParams | No |
subAccountId | number | No |
isolatedPositionDepositAmount | any | No |
| Returns |
|---|
Promise<string> |
Oracle / Auction-Style Orders
Oracle orders have prices that track the oracle feed with an offset. They go through a JIT auction before execution, with auction prices that gradually converge from the start offset to the end offset relative to oracle.
Important: For OrderType.ORACLE, auctionStartPrice, auctionEndPrice, and oraclePriceOffset are all offsets from the oracle price (in PRICE_PRECISION, 1e6), not absolute prices.
import { BN, OrderType, PositionDirection, PRICE_PRECISION } from "@drift-labs/sdk";
const marketIndex = 18;
// Offsets are relative to oracle price (in PRICE_PRECISION)
// For a long: auction starts at a better (lower) price and ends at a worse (higher) price
const auctionStartPrice = PRICE_PRECISION.muln(-5).divn(10); // -$0.50 below oracle
const auctionEndPrice = PRICE_PRECISION.muln(5).divn(10); // +$0.50 above oracle
const orderParams = {
orderType: OrderType.ORACLE,
baseAssetAmount: driftClient.convertToPerpPrecision(10),
direction: PositionDirection.LONG,
marketIndex,
auctionStartPrice,
auctionEndPrice,
oraclePriceOffset: driftClient.convertToPricePrecision(0.30).toNumber(), // +$0.30 from oracle
auctionDuration: 30, // slots
};
await driftClient.placePerpOrder(orderParams);Example Oracle orderReference ↗
Example Oracle orderReference ↗Oracle order.Instruction Builders (Advanced)
Higher-level methods like placePerpOrder() build, sign, and send a transaction in one call. Instruction (IX) builders give you the raw TransactionInstruction objects so you can:
- Set a custom compute budget with priority fees for faster inclusion
- Batch multiple instructions into a single transaction (e.g., cancel + place atomically)
- Use Address Lookup Tables (ALTs) to fit more accounts into a transaction
- Compose with other programs (e.g., add a memo or call another protocol in the same tx)
Complete Example: Batching IXs with Compute Budget
import { ComputeBudgetProgram } from "@solana/web3.js";
import {
MarketType, PositionDirection, OrderType, getOrderParams,
} from "@drift-labs/sdk";
// 1. Build individual instructions
const cancelIx = await driftClient.getCancelOrdersIx(
MarketType.PERP, // marketType (null to cancel all types)
0, // marketIndex (null to cancel across all markets)
null // direction (null to cancel both sides)
);
const placeIx = await driftClient.getPlacePerpOrderIx(
getOrderParams({
orderType: OrderType.LIMIT,
marketIndex: 0,
direction: PositionDirection.LONG,
baseAssetAmount: driftClient.convertToPerpPrecision(1),
price: driftClient.convertToPricePrecision(21.0),
})
);
// 2. Add compute budget instructions for priority fees
const computeUnitPrice = ComputeBudgetProgram.setComputeUnitPrice({
microLamports: 50_000, // priority fee in micro-lamports per CU
});
const computeUnitLimit = ComputeBudgetProgram.setComputeUnitLimit({
units: 400_000, // max compute units for the transaction
});
// 3. Build a versioned transaction with all instructions
const tx = await driftClient.txSender.getVersionedTransaction(
[computeUnitLimit, computeUnitPrice, cancelIx, placeIx],
[], // lookup table accounts (AddressLookupTableAccount[])
driftClient.wallet.publicKey
);
// 4. Send the transaction
const { txSig } = await driftClient.txSender.sendVersionedTransaction(
tx,
[],
driftClient.opts
);
console.log("Batch tx:", txSig);Example IX batching exampleReference ↗
Example IX batching exampleReference ↗IX batching example.Individual IX Builders
getPlacePerpOrderIx builds an instruction to place a perp order.
// Params:
// orderParams: OptionalOrderParams - same params as placePerpOrder()
// subAccountId?: number - defaults to active subaccount
const ix = await driftClient.getPlacePerpOrderIx(
getOrderParams({
orderType: OrderType.LIMIT,
marketIndex: 0,
direction: PositionDirection.LONG,
baseAssetAmount: driftClient.convertToPerpPrecision(1),
price: driftClient.convertToPricePrecision(21.0),
})
);Method DriftClient.getPlacePerpOrderIxReference ↗
Method DriftClient.getPlacePerpOrderIxReference ↗| Parameter | Type | Required |
|---|---|---|
orderParams | OptionalOrderParams | Yes |
subAccountId | number | No |
depositToTradeArgs | { isMakingNewAccount: boolean; depositMarketIndex: number; } | No |
| Returns |
|---|
Promise<TransactionInstruction> |
getPlaceSpotOrderIx builds an instruction to place a spot order.
// Params:
// orderParams: OptionalOrderParams - same params as placeSpotOrder()
// subAccountId?: number - defaults to active subaccount
const ix = await driftClient.getPlaceSpotOrderIx({
orderType: OrderType.LIMIT,
marketIndex: 1,
direction: PositionDirection.LONG,
baseAssetAmount: driftClient.convertToSpotPrecision(1, 1),
price: driftClient.convertToPricePrecision(150),
});Method DriftClient.getPlaceSpotOrderIxReference ↗
Method DriftClient.getPlaceSpotOrderIxReference ↗| Parameter | Type | Required |
|---|---|---|
orderParams | OptionalOrderParams | Yes |
subAccountId | number | No |
| Returns |
|---|
Promise<TransactionInstruction> |
getCancelOrdersIx builds an instruction to cancel orders matching the given filters. Pass null for any filter to match all.
import { MarketType, PositionDirection } from "@drift-labs/sdk";
// Params:
// marketType: MarketType | null - filter by PERP or SPOT (null = all)
// marketIndex: number | null - filter by market index (null = all)
// direction: PositionDirection | null - filter by LONG or SHORT (null = both)
// subAccountId?: number - defaults to active subaccount
// Cancel all perp orders on market 0
const ix = await driftClient.getCancelOrdersIx(MarketType.PERP, 0, null);
// Cancel ALL orders across all markets
const ixAll = await driftClient.getCancelOrdersIx(null, null, null);Method DriftClient.getCancelOrdersIxReference ↗
Method DriftClient.getCancelOrdersIxReference ↗| Parameter | Type | Required |
|---|---|---|
marketType | MarketType | Yes |
marketIndex | number | Yes |
direction | PositionDirection | Yes |
subAccountId | number | No |
| Returns |
|---|
Promise<TransactionInstruction> |
getFillPerpOrderIx builds an instruction to fill another user’s perp order (used by filler/keeper bots).
// Params:
// userAccountPublicKey: PublicKey - the taker's user account address
// userAccount: UserAccount - the taker's deserialized user account
// order: { marketIndex, orderId } - the order to fill
// makerInfo?: MakerInfo | MakerInfo[] - optional maker(s) to match against
// referrerInfo?: ReferrerInfo - optional referrer for fee sharing
// fillerSubAccountId?: number - filler's subaccount
const takerPubkey = takerUser.userAccountPublicKey;
const takerAccount = takerUser.getUserAccount();
const order = takerAccount.orders[0]; // the order to fill
const ix = await driftClient.getFillPerpOrderIx(
takerPubkey,
takerAccount,
{ marketIndex: order.marketIndex, orderId: order.orderId }
);Method DriftClient.getFillPerpOrderIxReference ↗
Method DriftClient.getFillPerpOrderIxReference ↗| Parameter | Type | Required |
|---|---|---|
userAccountPublicKey | PublicKey | Yes |
userAccount | UserAccount | Yes |
order | Pick<Order, "marketIndex" | "orderId"> | Yes |
makerInfo | MakerInfo | MakerInfo[] | No |
referrerInfo | ReferrerInfo | No |
fillerSubAccountId | number | No |
isSignedMsg | boolean | No |
fillerAuthority | PublicKey | No |
hasBuilderFee | boolean | No |
| Returns |
|---|
Promise<TransactionInstruction> |
getFillSpotOrderIx builds an instruction to fill another user’s spot order.
// Same pattern as getFillPerpOrderIx but for spot markets.
const ix = await driftClient.getFillSpotOrderIx(
takerPubkey,
takerAccount,
{ marketIndex: order.marketIndex, orderId: order.orderId }
);Method DriftClient.getFillSpotOrderIxReference ↗
Method DriftClient.getFillSpotOrderIxReference ↗| Parameter | Type | Required |
|---|---|---|
userAccountPublicKey | PublicKey | Yes |
userAccount | UserAccount | Yes |
order | Pick<Order, "marketIndex" | "orderId"> | No |
fulfillmentConfig | SerumV3FulfillmentConfigAccount | PhoenixV1FulfillmentConfigAccount | OpenbookV2FulfillmentConfigAccount | No |
makerInfo | MakerInfo | MakerInfo[] | No |
referrerInfo | ReferrerInfo | No |
fillerPublicKey | PublicKey | No |
| Returns |
|---|
Promise<TransactionInstruction> |
getTriggerOrderIx builds an instruction to trigger a conditional order (stop-loss or take-profit) that has met its trigger condition.
// Params:
// userAccountPublicKey: PublicKey - the user whose order to trigger
// userAccount: UserAccount - the deserialized user account
// order: Order - the full order object (must have trigger condition met)
// fillerPublicKey?: PublicKey - optional, defaults to your user account
const userPubkey = targetUser.userAccountPublicKey;
const userAccount = targetUser.getUserAccount();
const triggerOrder = userAccount.orders.find(
(o) => o.orderType.triggerMarket !== undefined || o.orderType.triggerLimit !== undefined
);
const ix = await driftClient.getTriggerOrderIx(
userPubkey,
userAccount,
triggerOrder
);Method DriftClient.getTriggerOrderIxReference ↗
Method DriftClient.getTriggerOrderIxReference ↗| Parameter | Type | Required |
|---|---|---|
userAccountPublicKey | PublicKey | Yes |
userAccount | UserAccount | Yes |
order | Order | Yes |
fillerPublicKey | PublicKey | No |
| Returns |
|---|
Promise<TransactionInstruction> |
getRevertFillIx builds an instruction to revert a fill (used by filler bots when a fill was invalid).
// Params:
// fillerPublicKey?: PublicKey - defaults to your user account
const ix = await driftClient.getRevertFillIx();Method DriftClient.getRevertFillIxReference ↗
Method DriftClient.getRevertFillIxReference ↗| Parameter | Type | Required |
|---|---|---|
fillerPublicKey | PublicKey | No |
| Returns |
|---|
Promise<TransactionInstruction> |
getSettlePNLsIxs builds instructions to settle PnL for one or more users across multiple markets. Returns an array of instructions (one per user per market).
// Params:
// users: Array of { settleeUserAccountPublicKey, settleeUserAccount }
// marketIndexes: number[] - perp market indexes to settle
const user = driftClient.getUser();
const ixs = await driftClient.getSettlePNLsIxs(
[
{
settleeUserAccountPublicKey: user.userAccountPublicKey,
settleeUserAccount: user.getUserAccount(),
},
],
[0, 1] // settle PnL on perp markets 0 and 1
);
// ixs is an array of TransactionInstruction, one per user per marketMethod DriftClient.getSettlePNLsIxsReference ↗
Method DriftClient.getSettlePNLsIxsReference ↗| Parameter | Type | Required |
|---|---|---|
users | { settleeUserAccountPublicKey: PublicKey; settleeUserAccount: UserAccount; }[] | Yes |
marketIndexes | number[] | Yes |
revenueShareEscrowMap | RevenueShareEscrowMap | No |
| Returns |
|---|
Promise<TransactionInstruction[]> |
getJupiterSwapIxV6 builds a Jupiter swap instruction routed through Drift.
// Params:
// inMarketIndex: number - spot market index of the input token
// outMarketIndex: number - spot market index of the output token
// amount: BN - amount of input token (in spot precision)
// slippageBps: number - max slippage in basis points
const ix = await driftClient.getJupiterSwapIxV6({
inMarketIndex: 0, // e.g. USDC
outMarketIndex: 1, // e.g. SOL
amount: driftClient.convertToSpotPrecision(0, 10), // 10 USDC
slippageBps: 50, // 0.5% max slippage
});Method DriftClient.getJupiterSwapIxV6Reference ↗
Method DriftClient.getJupiterSwapIxV6Reference ↗| Parameter | Type | Required |
|---|---|---|
__0 | { jupiterClient: JupiterClient; outMarketIndex: number; inMarketIndex: number; outAssociatedTokenAccount?: PublicKey; inAssociatedTokenAccount?: PublicKey; ... 6 more ...; userAccountPublicKey?: PublicKey; } | Yes |
| Returns |
|---|
Promise<{ ixs: TransactionInstruction[]; lookupTables: AddressLookupTableAccount[]; }> |
Place a Spot Order
import { OrderType, PositionDirection } from "@drift-labs/sdk";
await driftClient.placeSpotOrder({
orderType: OrderType.LIMIT,
marketIndex: 1, // e.g. SOL spot
direction: PositionDirection.LONG,
baseAssetAmount: driftClient.convertToSpotPrecision(1, 1), // 1 SOL
price: driftClient.convertToPricePrecision(150),
});Method DriftClient.placeSpotOrderReference ↗
Method DriftClient.placeSpotOrderReference ↗| Parameter | Type | Required |
|---|---|---|
orderParams | OptionalOrderParams | Yes |
txParams | TxParams | No |
subAccountId | number | No |
| Returns |
|---|
Promise<string> |
Place Multiple Orders
await driftClient.placeOrders([
{
orderType: OrderType.LIMIT,
marketType: MarketType.PERP,
marketIndex: 0,
direction: PositionDirection.LONG,
baseAssetAmount: driftClient.convertToPerpPrecision(1),
price: driftClient.convertToPricePrecision(21.23),
},
{
orderType: OrderType.LIMIT,
marketType: MarketType.PERP,
marketIndex: 0,
direction: PositionDirection.SHORT,
baseAssetAmount: driftClient.convertToPerpPrecision(1),
oraclePriceOffset: driftClient.convertToPricePrecision(0.05).toNumber(),
},
]);Method DriftClient.placeOrdersReference ↗
Method DriftClient.placeOrdersReference ↗| Parameter | Type | Required |
|---|---|---|
params | OrderParams[] | Yes |
txParams | TxParams | No |
subAccountId | number | No |
optionalIxs | TransactionInstruction[] | No |
isolatedPositionDepositAmount | any | No |
| Returns |
|---|
Promise<string> |
Cancel Orders
await driftClient.cancelOrder(1);Method DriftClient.cancelOrderReference ↗
Method DriftClient.cancelOrderReference ↗| Parameter | Type | Required |
|---|---|---|
orderId | number | No |
txParams | TxParams | No |
subAccountId | number | No |
overrides | { withdrawIsolatedDepositAmount?: any; } | No |
| Returns |
|---|
Promise<string> |
await driftClient.cancelOrdersByIds([1]);Method DriftClient.cancelOrdersByIdsReference ↗
Method DriftClient.cancelOrdersByIdsReference ↗| Parameter | Type | Required |
|---|---|---|
orderIds | number[]The order ids to cancel. | No |
txParams | TxParamsThe transaction parameters. | No |
subAccountId | numberThe sub account id to cancel the orders for. | No |
user | UserThe user to cancel the orders for. If provided, it will be prioritized over the subAccountId. | No |
overrides | { authority?: PublicKey; } | No |
| Returns |
|---|
Promise<string> |
import { MarketType, PositionDirection } from "@drift-labs/sdk";
// Cancels orders matching the filters. To cancel all orders, omit parameters.
await driftClient.cancelOrders(MarketType.PERP, 0, PositionDirection.LONG);Method DriftClient.cancelOrdersReference ↗
Method DriftClient.cancelOrdersReference ↗| Parameter | Type | Required |
|---|---|---|
marketType | MarketType | No |
marketIndex | number | No |
direction | PositionDirection | No |
txParams | TxParams | No |
subAccountId | number | No |
| Returns |
|---|
Promise<string> |
Cancel and Place (Atomic)
await driftClient.cancelAndPlaceOrders(
{ marketType: MarketType.PERP, marketIndex: 0 },
[
{
orderType: OrderType.LIMIT,
marketIndex: 0,
direction: PositionDirection.LONG,
baseAssetAmount: driftClient.convertToPerpPrecision(1),
price: driftClient.convertToPricePrecision(21.23),
},
]
);Method DriftClient.cancelAndPlaceOrdersReference ↗
Method DriftClient.cancelAndPlaceOrdersReference ↗| Parameter | Type | Required |
|---|---|---|
cancelOrderParams | { marketType?: MarketType; marketIndex?: number; direction?: PositionDirection; } | Yes |
placeOrderParams | OrderParams[] | Yes |
txParams | TxParams | No |
subAccountId | number | No |
| Returns |
|---|
Promise<string> |
Modify Orders
await driftClient.modifyOrder({
orderId: 1,
newBaseAmount: driftClient.convertToPerpPrecision(2),
});Method DriftClient.modifyOrderReference ↗
Method DriftClient.modifyOrderReference ↗| Parameter | Type | Required |
|---|---|---|
orderParams | { orderId: number; newDirection?: PositionDirection; newBaseAmount?: any; newLimitPrice?: any; newOraclePriceOffset?: number; newTriggerPrice?: any; newTriggerCondition?: OrderTriggerCondition; ... 7 more ...; policy?: number; } | Yes |
txParams | TxParams | No |
subAccountId | number | No |
| Returns |
|---|
Promise<string> |
await driftClient.modifyOrderByUserOrderId({
userOrderId: 1,
newBaseAmount: driftClient.convertToPerpPrecision(2),
});Method DriftClient.modifyOrderByUserOrderIdReference ↗
Method DriftClient.modifyOrderByUserOrderIdReference ↗| Parameter | Type | Required |
|---|---|---|
orderParams | { userOrderId: number; newDirection?: PositionDirection; newBaseAmount?: any; newLimitPrice?: any; newOraclePriceOffset?: number; newTriggerPrice?: any; newTriggerCondition?: OrderTriggerCondition; ... 7 more ...; maxTs?: any; } | Yes |
txParams | TxParams | No |
subAccountId | number | No |
| Returns |
|---|
Promise<string> |
Trigger Orders (Stop / Take-Profit)
import { OrderTriggerCondition, OrderType, PositionDirection } from "@drift-labs/sdk";
const orderParams = {
orderType: OrderType.TRIGGER_MARKET,
marketIndex: 0,
direction: PositionDirection.SHORT,
baseAssetAmount: driftClient.convertToPerpPrecision(1),
triggerPrice: driftClient.convertToPricePrecision(95),
triggerCondition: OrderTriggerCondition.BELOW,
};
await driftClient.placePerpOrder(orderParams);Example Trigger orderReference ↗
Example Trigger orderReference ↗Trigger order.