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.

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.

Order Types

TypeDescription
MARKETExecutes immediately. Goes through a JIT auction first (controlled by auctionStartPrice, auctionEndPrice, auctionDuration), then fills against the DLOB or AMM.
LIMITRests on the DLOB at a fixed price until filled or canceled. Set postOnly: PostOnlyParams.MUST_POST_ONLY to guarantee maker status and avoid crossing the spread.
ORACLELike a market order, but auction prices and the resting limit price are expressed as offsets from the oracle price (not absolute prices). Useful for market makers who want tight spreads without hardcoding prices.
TRIGGER_MARKETA stop/take-profit market order. Executes as a market order when the oracle price crosses triggerPrice in the specified triggerCondition direction.
TRIGGER_LIMITA stop/take-profit limit order. Same trigger mechanism as TRIGGER_MARKET, but executes as a limit order at price once triggered.

Post-Only Params

When placing limit orders, you can control maker/taker behavior with postOnly:

ValueBehavior
PostOnlyParams.NONEOrder can be maker or taker (default)
PostOnlyParams.MUST_POST_ONLYTransaction fails if the order would cross the spread
PostOnlyParams.TRY_POST_ONLYOrder is silently skipped (not placed) if it would cross; tx succeeds
PostOnlyParams.SLIDEOrder price is adjusted one tick inside the spread to guarantee maker status

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 ↗
ParameterTypeRequired
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 ↗

Creates an OrderParams object with the given OptionalOrderParams and any params to override.

example: ``` const orderParams = getOrderParams(optionalOrderParams, &#123; marketType: MarketType.PERP &#125;); ```

ParameterTypeRequired
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 ↗
ParameterTypeRequired
orderParams
OptionalOrderParams
Yes
txParams
TxParams
No
subAccountId
number
No
isolatedPositionDepositAmount
any
No
Returns
Promise<string>

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 ↗
ParameterTypeRequired
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 ↗
ParameterTypeRequired
params
OrderParams[]
Yes
txParams
TxParams
No
subAccountId
number
No
optionalIxs
TransactionInstruction[]
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 ↗
TypeScript docs unavailable for Oracle order.

Cancel Orders

Cancel a specific order by its onchain order ID.

await driftClient.cancelOrder(1);
Method DriftClient.cancelOrderReference ↗
ParameterTypeRequired
orderId
number
No
txParams
TxParams
No
subAccountId
number
No
overrides
{ withdrawIsolatedDepositAmount?: any; }
No
Returns
Promise<string>

Cancel multiple specific orders by their onchain order IDs in a single transaction.

await driftClient.cancelOrdersByIds([1, 2, 3]);
Method DriftClient.cancelOrdersByIdsReference ↗
ParameterTypeRequired
orderIds
number[]
The order ids to cancel.
No
txParams
TxParams
The transaction parameters.
No
subAccountId
number
The sub account id to cancel the orders for.
No
user
User
The user to cancel the orders for. If provided, it will be prioritized over the subAccountId.
No
overrides
{ authority?: PublicKey; }
No
Returns
Promise<string>

Cancel all orders matching the given market and direction filters. Pass null for any filter to match all. Omit all parameters to cancel every open order.

import { MarketType, PositionDirection } from "@drift-labs/sdk"; // Cancel all long perp orders on market 0 await driftClient.cancelOrders(MarketType.PERP, 0, PositionDirection.LONG); // Cancel all orders across all markets await driftClient.cancelOrders(null, null, null);
Method DriftClient.cancelOrdersReference ↗
ParameterTypeRequired
marketType
MarketType
No
marketIndex
number
No
direction
PositionDirection
No
txParams
TxParams
No
subAccountId
number
No
Returns
Promise<string>

Cancel and Place (Atomic)

Atomically cancels existing orders and places new ones in a single transaction. This is the preferred approach for market makers who need to replace quotes without risk of being filled on stale orders in the gap between a separate cancel and re-quote.

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 ↗
ParameterTypeRequired
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 ↗
ParameterTypeRequired
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 ↗
ParameterTypeRequired
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 ↗
TypeScript docs unavailable for Trigger 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 ↗
TypeScript docs unavailable for 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 ↗
ParameterTypeRequired
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 ↗
ParameterTypeRequired
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 ↗
ParameterTypeRequired
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 ↗
ParameterTypeRequired
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 ↗
ParameterTypeRequired
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 ↗
ParameterTypeRequired
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 ↗
ParameterTypeRequired
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 market
Method DriftClient.getSettlePNLsIxsReference ↗
ParameterTypeRequired
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 ↗
ParameterTypeRequired
__0
{ jupiterClient: JupiterClient; outMarketIndex: number; inMarketIndex: number; outAssociatedTokenAccount?: PublicKey; inAssociatedTokenAccount?: PublicKey; ... 6 more ...; userAccountPublicKey?: PublicKey; }
Yes
Returns
Promise<{ ixs: TransactionInstruction[]; lookupTables: AddressLookupTableAccount[]; }>
Last updated on