Skip to Content

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 ↗
Parameters:
NameTypeDefault
paramsOmit<OptionalOrderParams, "orderType">
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 ↗
Parameters:
NameTypeDefault
optionalOrderParamsOptionalOrderParams
overridingParamsRecord<string, any>
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 ↗
Parameters:
NameTypeDefault
orderParamsOptionalOrderParams
txParamsTxParams
subAccountIdnumber
isolatedPositionDepositAmountany
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);

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);

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 ↗
Parameters:
NameTypeDefault
orderParamsOptionalOrderParams
subAccountIdnumber
depositToTradeArgs{ isMakingNewAccount: boolean; depositMarketIndex: number; }
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 ↗
Parameters:
NameTypeDefault
orderParamsOptionalOrderParams
subAccountIdnumber
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 ↗
Parameters:
NameTypeDefault
marketTypeMarketType
marketIndexnumber
directionPositionDirection
subAccountIdnumber
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 ↗
Parameters:
NameTypeDefault
userAccountPublicKeyPublicKey
userAccountUserAccount
orderPick<Order, "marketIndex" | "orderId">
makerInfoMakerInfo | MakerInfo[]
referrerInfoReferrerInfo
fillerSubAccountIdnumber
isSignedMsgboolean
fillerAuthorityPublicKey
hasBuilderFeeboolean
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 ↗
Parameters:
NameTypeDefault
userAccountPublicKeyPublicKey
userAccountUserAccount
orderPick<Order, "marketIndex" | "orderId">
fulfillmentConfigSerumV3FulfillmentConfigAccount | PhoenixV1FulfillmentConfigAccount | OpenbookV2FulfillmentConfigAccount
makerInfoMakerInfo | MakerInfo[]
referrerInfoReferrerInfo
fillerPublicKeyPublicKey
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 ↗
Parameters:
NameTypeDefault
userAccountPublicKeyPublicKey
userAccountUserAccount
orderOrder
fillerPublicKeyPublicKey
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 ↗
Parameters:
NameTypeDefault
fillerPublicKeyPublicKey
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 market
Method DriftClient.getSettlePNLsIxsReference ↗
Parameters:
NameTypeDefault
users{ settleeUserAccountPublicKey: PublicKey; settleeUserAccount: UserAccount; }[]
marketIndexesnumber[]
revenueShareEscrowMapRevenueShareEscrowMap
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 ↗
Parameters:
NameTypeDefault
__0{ jupiterClient: JupiterClient; outMarketIndex: number; inMarketIndex: number; outAssociatedTokenAccount?: PublicKey; inAssociatedTokenAccount?: PublicKey; ... 6 more ...; userAccountPublicKey?: PublicKey; }
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 ↗
Parameters:
NameTypeDefault
orderParamsOptionalOrderParams
txParamsTxParams
subAccountIdnumber
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 ↗
Parameters:
NameTypeDefault
paramsOrderParams[]
txParamsTxParams
subAccountIdnumber
optionalIxsTransactionInstruction[]
isolatedPositionDepositAmountany
Returns:
Promise<string>

Cancel Orders

await driftClient.cancelOrder(1);
Method DriftClient.cancelOrderReference ↗
Parameters:
NameTypeDefault
orderIdnumber
txParamsTxParams
subAccountIdnumber
overrides{ withdrawIsolatedDepositAmount?: any; }
Returns:
Promise<string>
await driftClient.cancelOrdersByIds([1]);
Method DriftClient.cancelOrdersByIdsReference ↗
Parameters:
NameTypeDefault
orderIdsnumber[]

The order ids to cancel.

txParamsTxParams

The transaction parameters.

subAccountIdnumber

The sub account id to cancel the orders for.

userUser

The user to cancel the orders for. If provided, it will be prioritized over the subAccountId.

overrides{ authority?: PublicKey; }
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 ↗
Parameters:
NameTypeDefault
marketTypeMarketType
marketIndexnumber
directionPositionDirection
txParamsTxParams
subAccountIdnumber
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 ↗
Parameters:
NameTypeDefault
cancelOrderParams{ marketType?: MarketType; marketIndex?: number; direction?: PositionDirection; }
placeOrderParamsOrderParams[]
txParamsTxParams
subAccountIdnumber
Returns:
Promise<string>

Modify Orders

await driftClient.modifyOrder({ orderId: 1, newBaseAmount: driftClient.convertToPerpPrecision(2), });
Method DriftClient.modifyOrderReference ↗
Parameters:
NameTypeDefault
orderParams{ orderId: number; newDirection?: PositionDirection; newBaseAmount?: any; newLimitPrice?: any; newOraclePriceOffset?: number; newTriggerPrice?: any; newTriggerCondition?: OrderTriggerCondition; ... 7 more ...; policy?: number; }
txParamsTxParams
subAccountIdnumber
Returns:
Promise<string>
await driftClient.modifyOrderByUserOrderId({ userOrderId: 1, newBaseAmount: driftClient.convertToPerpPrecision(2), });
Method DriftClient.modifyOrderByUserOrderIdReference ↗
Parameters:
NameTypeDefault
orderParams{ userOrderId: number; newDirection?: PositionDirection; newBaseAmount?: any; newLimitPrice?: any; newOraclePriceOffset?: number; newTriggerPrice?: any; newTriggerCondition?: OrderTriggerCondition; ... 7 more ...; maxTs?: any; }
txParamsTxParams
subAccountIdnumber
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);
Last updated on