Skip to main content

Overview

The DLOB (Decentralized Limit Order Book) is Drift’s on-chain order matching system. It aggregates all user orders and provides efficient access to market liquidity, order matching, and L2/L3 order book views.

DLOB Class

Constructor

Creates a new DLOB instance.
import { DLOB } from '@drift-labs/sdk';

const dlob = new DLOB();
Parameters:
protectedMakerParamsMap
ProtectMakerParamsMap
Optional map of protected maker parameters by market.

initFromUserMap

Initializes the DLOB from a UserMap.
await dlob.initFromUserMap(userMap, currentSlot);
Parameters:
userMap
UserMap
required
Map of user accounts containing orders.
slot
number
required
Current blockchain slot number.
Returns: Promise<boolean> - True if successfully initialized

insertOrder

Inserts an order into the DLOB.
dlob.insertOrder(
  order,
  userAccountPubkey,
  slot,
  isProtectedMaker,
  baseAssetAmount
);
Parameters:
order
Order
required
The order to insert.
userAccount
string
required
User account public key as string.
slot
number
required
Current slot number.
isUserProtectedMaker
boolean
required
Whether user has protected maker status.
baseAssetAmount
BN
required
Base asset amount for the order.
onInsert
OrderBookCallback
Optional callback executed after insertion.

clear

Clears all orders from the DLOB.
dlob.clear();

Order Book Queries

getL2

Returns an L2 (aggregated by price level) view of the order book.
const l2 = dlob.getL2({
  marketIndex: 0,
  marketType: MarketType.PERP,
  slot: currentSlot,
  oraclePriceData: mmOraclePriceData,
  depth: 20,
  fallbackL2Generators: [vammGenerator],
});

console.log('Best bid:', l2.bids[0].price.toString());
console.log('Best ask:', l2.asks[0].price.toString());
Parameters:
marketIndex
number
required
Market index to query.
marketType
MarketType
required
Market type (PERP or SPOT).
slot
number
required
Current slot number.
oraclePriceData
OraclePriceData | MMOraclePriceData
required
Oracle price data for the market.
depth
number
required
Number of price levels to return on each side.
fallbackL2Generators
L2OrderBookGenerator[]
default:"[]"
Additional liquidity sources (e.g., vAMM, OpenBook).
Returns: L2OrderBook
bids
L2Level[]
Array of bid levels sorted by price (descending).
asks
L2Level[]
Array of ask levels sorted by price (ascending).
slot
number
Slot number when the book was generated.
L2Level fields:
price
BN
Price level in PRICE_PRECISION (1e6).
size
BN
Total size at this price level.
sources
object
Map of liquidity sources to sizes.

getL3

Returns an L3 (individual orders) view of the order book.
const l3 = dlob.getL3({
  marketIndex: 0,
  marketType: MarketType.PERP,
  slot: currentSlot,
  oraclePriceData: oraclePriceData,
});

for (const bid of l3.bids) {
  console.log(`Order ${bid.orderId} from ${bid.maker}: ${bid.size} @ ${bid.price}`);
}
Parameters:
marketIndex
number
required
Market index to query.
marketType
MarketType
required
Market type (PERP or SPOT).
slot
number
required
Current slot number.
oraclePriceData
OraclePriceData | MMOraclePriceData
required
Oracle price data for the market.
Returns: L3OrderBook
bids
L3Level[]
Individual bid orders sorted by price (descending).
asks
L3Level[]
Individual ask orders sorted by price (ascending).
slot
number
Slot number when the book was generated.
L3Level fields:
price
BN
Order price in PRICE_PRECISION (1e6).
size
BN
Order size (remaining).
maker
PublicKey
Public key of the order maker.
orderId
number
Order ID.

getBestBid / getBestAsk

Get the best bid or ask price for a market.
const bestBid = dlob.getBestBid(
  marketIndex,
  slot,
  MarketType.PERP,
  oraclePriceData
);

const bestAsk = dlob.getBestAsk(
  marketIndex,
  slot,
  MarketType.PERP,
  oraclePriceData
);

if (bestBid && bestAsk) {
  const spread = bestAsk.sub(bestBid);
  console.log('Spread:', spread.toString());
}
Parameters:
marketIndex
number
required
Market index to query.
slot
number
required
Current slot number.
marketType
MarketType
required
Market type.
oraclePriceData
OraclePriceData | MMOraclePriceData
required
Oracle price data.
Returns: BN | undefined - Best bid/ask price or undefined if no orders

Order Matching

findNodesToFill

Finds orders that can be filled, considering both maker-taker matching and fallback liquidity.
const nodesToFill = dlob.findNodesToFill(
  marketIndex,
  fallbackBid,
  fallbackAsk,
  slot,
  timestamp,
  MarketType.PERP,
  oraclePriceData,
  stateAccount,
  perpMarketAccount
);

for (const nodeToFill of nodesToFill) {
  console.log('Fillable order:', nodeToFill.node.order.orderId);
  console.log('Maker nodes:', nodeToFill.makerNodes.length);
}
Parameters:
marketIndex
number
required
Market index.
fallbackBid
BN | undefined
required
Fallback bid price (e.g., from vAMM).
fallbackAsk
BN | undefined
required
Fallback ask price (e.g., from vAMM).
slot
number
required
Current slot.
ts
number
required
Current timestamp.
marketType
MarketType
required
Market type.
oraclePriceData
OraclePriceData | MMOraclePriceData
required
Oracle price data.
stateAccount
StateAccount
required
State account.
marketAccount
PerpMarketAccount | SpotMarketAccount
required
Market account.
Returns: NodeToFill[]
node
DLOBNode
The taker order node to fill.
makerNodes
DLOBNode[]
Array of maker nodes that can fill the taker. Empty if filling against fallback liquidity.

findNodesToTrigger

Finds trigger orders (stop loss / take profit) that should be activated.
const nodesToTrigger = dlob.findNodesToTrigger(
  marketIndex,
  slot,
  oraclePrice,
  MarketType.PERP,
  stateAccount
);

for (const trigger of nodesToTrigger) {
  console.log('Trigger order:', trigger.node.order.orderId);
}
Parameters:
marketIndex
number
required
Market index.
slot
number
required
Current slot.
triggerPrice
BN
required
Current oracle price to check against.
marketType
MarketType
required
Market type.
stateAccount
StateAccount
required
State account.
Returns: NodeToTrigger[]
node
TriggerOrderNode
The trigger order that should be activated.

Trigger Orders

getStopLosses

Get all stop loss orders for a position direction.
for (const stopLoss of dlob.getStopLosses(
  marketIndex,
  MarketType.PERP,
  PositionDirection.LONG
)) {
  console.log('Stop loss:', stopLoss.order.triggerPrice.toString());
}
Parameters:
marketIndex
number
required
Market index.
marketType
MarketType
required
Market type.
direction
PositionDirection
required
Position direction to get stop losses for.
Returns: Generator<DLOBNode> - Iterator of stop loss orders

getTakeProfits

Get all take profit orders for a position direction.
for (const takeProfit of dlob.getTakeProfits(
  marketIndex,
  MarketType.PERP,
  PositionDirection.LONG
)) {
  console.log('Take profit:', takeProfit.order.triggerPrice.toString());
}
Parameters:
marketIndex
number
required
Market index.
marketType
MarketType
required
Market type.
direction
PositionDirection
required
Position direction to get take profits for.
Returns: Generator<DLOBNode> - Iterator of take profit orders

DLOBSubscriber

The DLOBSubscriber automatically updates the DLOB in the background.

Constructor

import { DLOBSubscriber, UserMap } from '@drift-labs/sdk';

const userMap = new UserMap({
  driftClient,
  subscriptionConfig: {
    type: 'websocket',
    resubTimeoutMs: 30_000,
  },
});

const dlobSubscriber = new DLOBSubscriber({
  driftClient,
  dlobSource: userMap,
  slotSource: userMap,
  updateFrequency: 1000, // Update every 1 second
  protectedMakerView: false,
});
Configuration:
driftClient
DriftClient
required
The Drift client instance.
dlobSource
DLOBSource
required
Source for DLOB data (typically UserMap).
slotSource
SlotSource
required
Source for current slot (typically UserMap).
updateFrequency
number
required
Update frequency in milliseconds.
protectedMakerView
boolean
default:"false"
Enable protected maker view.

subscribe / unsubscribe

// Start subscribing
await dlobSubscriber.subscribe();

// Listen for updates
dlobSubscriber.eventEmitter.on('update', (dlob) => {
  console.log('DLOB updated');
});

dlobSubscriber.eventEmitter.on('error', (error) => {
  console.error('DLOB error:', error);
});

// Get current DLOB
const dlob = dlobSubscriber.getDLOB();

// Stop subscribing
await dlobSubscriber.unsubscribe();

getL2 / getL3

Convenience methods for getting order book views.
const l2 = dlobSubscriber.getL2({
  marketName: 'SOL-PERP',
  depth: 20,
  includeVamm: true,
});

const l3 = dlobSubscriber.getL3({
  marketIndex: 0,
  marketType: MarketType.PERP,
});
Parameters:
marketName
string
Market name (e.g., “SOL-PERP” or “SOL”). Alternative to marketIndex + marketType.
marketIndex
number
Market index (required if marketName not provided).
marketType
MarketType
Market type (required if marketName not provided).
depth
number
default:"10"
Number of levels to return (L2 only).
includeVamm
boolean
default:"false"
Include vAMM liquidity (L2 only, perp markets only).
numVammOrders
number
Number of vAMM orders to generate (L2 only).
fallbackL2Generators
L2OrderBookGenerator[]
default:"[]"
Additional liquidity sources (L2 only).
latestSlot
BN
Latest slot for accurate vAMM quotes (L2 only).

DLOBNode Types

The DLOB uses different node types for different order categories:
  • RestingLimitOrderNode - Limit orders past auction period
  • TakingLimitOrderNode - Limit orders in auction period
  • FloatingLimitOrderNode - Orders with oracle price offset
  • MarketOrderNode - Market orders
  • TriggerOrderNode - Trigger orders (stop loss / take profit)
  • SignedMsgOrderNode - Off-chain signed message orders

Example: Market Making Bot

import { DLOBSubscriber, MarketType } from '@drift-labs/sdk';

// Subscribe to DLOB
const dlobSubscriber = new DLOBSubscriber({
  driftClient,
  dlobSource: userMap,
  slotSource: userMap,
  updateFrequency: 1000,
});

await dlobSubscriber.subscribe();

// Monitor order book
dlobSubscriber.eventEmitter.on('update', (dlob) => {
  const l2 = dlobSubscriber.getL2({
    marketName: 'SOL-PERP',
    depth: 5,
    includeVamm: true,
  });
  
  if (l2.bids.length > 0 && l2.asks.length > 0) {
    const bestBid = l2.bids[0].price;
    const bestAsk = l2.asks[0].price;
    const midPrice = bestBid.add(bestAsk).divn(2);
    
    console.log('Mid price:', midPrice.toString());
    console.log('Spread:', bestAsk.sub(bestBid).toString());
    
    // Place orders based on mid price...
  }
});

See Also

Build docs developers (and LLMs) love