Skip to Content
DevelopersMarket MakersOrderbook & DLOB

Orderbook & DLOB

To quote well, you usually need current best bid/ask, depth, and recent flow. Drift exposes multiple ways to access orderbook state:

  • SDK (local DLOB) via UserMap / DLOB
  • SDK (subscription) via DLOBSubscriber
  • Hosted DLOB server (HTTP) for convenience

UserMap + DLOB (local)

This approach subscribes to user accounts and builds an in-memory orderbook (DLOB). It’s powerful, but can be heavier than calling a hosted DLOB endpoint.

import { UserMap } from "@drift-labs/sdk";
Class UserMapReference ↗
NameTypeDefault
userMapany
driftClientDriftClient
eventEmitterStrictEventEmitter<EventEmitter, UserEvents>
connectionany
commitmentany
includeIdleany
filterByPoolIdany
additionalFiltersany
disableSyncOnTotalAccountsChangeany
lastNumberOfSubAccountsany
subscriptionany
stateAccountUpdateCallbackany
decodeany
mostRecentSlotany
syncConfigany
syncPromiseany
syncPromiseResolverany
throwOnFailedSyncany
subscribe() => Promise<void>
addPubkey(userAccountPublicKey: PublicKey, userAccount?: UserAccount | undefined, slot?: number | undefined, accountSubscription?: UserSubscriptionConfig | undefined) => Promise<...>
has(key: string) => boolean
get(key: string) => User | undefined

gets the User for a particular userAccountPublicKey, if no User exists, undefined is returned

getWithSlot(key: string) => DataAndSlot<User> | undefined
mustGet(key: string, accountSubscription?: UserSubscriptionConfig | undefined) => Promise<User>

gets the User for a particular userAccountPublicKey, if no User exists, new one is created

mustGetWithSlot(key: string, accountSubscription?: UserSubscriptionConfig | undefined) => Promise<DataAndSlot<User>>
mustGetUserAccount(key: string) => Promise<UserAccount>
getUserAuthority(key: string) => PublicKey | undefined

gets the Authority for a particular userAccountPublicKey, if no User exists, undefined is returned

getDLOB(slot: number, protectedMakerParamsMap?: ProtectMakerParamsMap | undefined) => Promise<DLOB>

implements the DLOBSource interface create a DLOB from all the subscribed users

updateWithOrderRecord(record: OrderRecord) => Promise<void>
updateWithEventRecord(record: any) => Promise<void>
values() => IterableIterator<User>
valuesWithSlot() => IterableIterator<DataAndSlot<User>>
entries() => IterableIterator<[string, User]>
entriesWithSlot() => IterableIterator<[string, DataAndSlot<User>]>
size() => number
getUniqueAuthorities(filterCriteria?: UserAccountFilterCriteria | undefined) => PublicKey[]

Returns a unique list of authorities for all users in the UserMap that meet the filter criteria

sync() => Promise<void>
getFiltersany
defaultSyncany

Syncs the UserMap using the default sync method (single getProgramAccounts call with filters). This method may fail when drift has too many users. (nodejs response size limits)

paginatedSyncany

Syncs the UserMap using the paginated sync method (multiple getMultipleAccounts calls with filters). This method is more reliable when drift has many users.

unsubscribe() => Promise<void>
updateUserAccount(key: string, userAccount: UserAccount, slot: number) => Promise<void>
updateLatestSlot(slot: number) => void
getSlot() => number
import { DLOB } from "@drift-labs/sdk";
Class DLOBReference ↗
NameTypeDefault
openOrdersMap<MarketTypeStr, Set<string>>
orderListsMap<MarketTypeStr, Map<number, MarketNodeLists>>
maxSlotForRestingLimitOrdersnumber
initializedboolean
protectedMakerParamsMapProtectMakerParamsMap
initany
clear() => void
initFromUserMap(userMap: UserMap, slot: number) => Promise<boolean>

initializes a new DLOB instance

insertOrder(order: Order, userAccount: string, slot: number, isUserProtectedMaker: boolean, baseAssetAmount: BN, onInsert?: OrderBookCallback | undefined) => void
insertSignedMsgOrder(order: Order, userAccount: string, isUserProtectedMaker: boolean, baseAssetAmount?: any, onInsert?: OrderBookCallback | undefined) => void
addOrderList(marketType: MarketTypeStr, marketIndex: number) => void
delete(order: Order, userAccount: PublicKey, slot: number, isUserProtectedMaker: boolean, onDelete?: OrderBookCallback | undefined) => void
getListForOnChainOrder(order: Order, slot: number, isProtectedMaker: boolean) => NodeList<any> | undefined
updateRestingLimitOrders(slot: number) => void
updateRestingLimitOrdersForMarketType(slot: number, marketTypeStr: MarketTypeStr) => void
getOrder(orderId: number, userAccount: PublicKey) => Order | undefined
findNodesToFill<T extends MarketType>(marketIndex: number, fallbackBid: any, fallbackAsk: any, slot: number, ts: number, marketType: T, oraclePriceData: T extends { spot: unknown; } ? OraclePriceData : MMOraclePriceData, stateAccount: StateAccount, marketAccount: T extends { ...; } ? SpotMarketAccount : PerpMarketAccount) => NodeT...
getMakerRebate(marketType: MarketType, stateAccount: StateAccount, marketAccount: SpotMarketAccount | PerpMarketAccount) => { ...; }
mergeNodesToFill(restingLimitOrderNodesToFill: NodeToFill[], takingOrderNodesToFill: NodeToFill[]) => NodeToFill[]
findRestingLimitOrderNodesToFill<T extends MarketType>(marketIndex: number, slot: number, marketType: T, oraclePriceData: T extends { spot: unknown; } ? OraclePriceData : MMOraclePriceData, isAmmPaused: boolean, stateAccount: StateAccount, marketAccount: T extends { ...; } ? SpotMarketAccount : PerpMarketAccount, makerRebateNumerator: number, make...
findTakingNodesToFill<T extends MarketType>(marketIndex: number, slot: number, marketType: T, oraclePriceData: T extends { spot: unknown; } ? OraclePriceData : MMOraclePriceData, isAmmPaused: boolean, state: StateAccount, marketAccount: T extends { ...; } ? SpotMarketAccount : PerpMarketAccount, fallbackAsk: any, fallbackBid?: any) => N...
findTakingNodesCrossingMakerNodes<T extends MarketType>(marketIndex: number, slot: number, marketType: T, oraclePriceData: T extends { spot: unknown; } ? OraclePriceData : MMOraclePriceData, takerNodeGenerator: Generator<...>, makerNodeGeneratorFn: (marketIndex: number, slot: number, marketType: MarketType, oraclePriceData: T extends { ...; } ? Ora...
findNodesCrossingFallbackLiquidity<T extends MarketType>(marketType: T, slot: number, oraclePriceData: T extends { spot: unknown; } ? OraclePriceData : MMOraclePriceData, nodeGenerator: Generator<DLOBNode, any, any>, doesCross: (nodePrice: any) => boolean, state: StateAccount, marketAccount: T extends { ...; } ? SpotMarketAccount : PerpMarketAccount...
findExpiredNodesToFill(marketIndex: number, ts: number, marketType: MarketType, slot?: any) => NodeToFill[]
findUnfillableReduceOnlyOrdersToCancel(marketIndex: number, marketType: MarketType, stepSize: BN) => NodeToFill[]
getTakingBids<T extends MarketType>(marketIndex: number, marketType: T, slot: number, oraclePriceData: T extends { spot: unknown; } ? OraclePriceData : MMOraclePriceData, filterFcn?: DLOBFilterFcn | undefined) => Generator<...>
getTakingAsks<T extends MarketType>(marketIndex: number, marketType: T, slot: number, oraclePriceData: T extends { spot: unknown; } ? OraclePriceData : MMOraclePriceData, filterFcn?: DLOBFilterFcn | undefined) => Generator<...>
signedMsgGenerator(signedMsgOrderList: NodeList<"signedMsg">, filter: (x: DLOBNode) => boolean) => Generator<DLOBNode, any, any>
getBestNode<T extends MarketTypeStr>(generatorList: Generator<DLOBNode, any, any>[], oraclePriceData: T extends "spot" ? OraclePriceData : MMOraclePriceData, slot: number, compareFcn: (bestDLOBNode: DLOBNode, currentDLOBNode: DLOBNode, slot: number, oraclePriceData: T extends "spot" ? OraclePriceData : MMOraclePriceData) => bo...
getRestingLimitAsks<T extends MarketType>(marketIndex: number, slot: number, marketType: T, oraclePriceData: T extends { spot: unknown; } ? OraclePriceData : MMOraclePriceData, filterFcn?: DLOBFilterFcn | undefined) => Generator<...>
getRestingLimitBids<T extends MarketType>(marketIndex: number, slot: number, marketType: T, oraclePriceData: T extends { spot: unknown; } ? OraclePriceData : MMOraclePriceData, filterFcn?: DLOBFilterFcn | undefined) => Generator<...>
getAsks<T extends MarketType>(marketIndex: number, _fallbackAsk: any, slot: number, marketType: T, oraclePriceData: T extends { spot: unknown; } ? OraclePriceData : MMOraclePriceData, filterFcn?: DLOBFilterFcn | undefined) => Generator<...>

This will look at both the taking and resting limit asks

getBids<T extends MarketType>(marketIndex: number, _fallbackBid: any, slot: number, marketType: T, oraclePriceData: T extends { spot: unknown; } ? OraclePriceData : MMOraclePriceData, filterFcn?: DLOBFilterFcn | undefined) => Generator<...>

This will look at both the taking and resting limit bids

findCrossingRestingLimitOrders<T extends MarketType>(marketIndex: number, slot: number, marketType: T, oraclePriceData: T extends { spot: unknown; } ? OraclePriceData : MMOraclePriceData) => NodeToFill[]
determineMakerAndTaker(askNode: DLOBNode, bidNode: DLOBNode) => { takerNode: DLOBNode; makerNode: DLOBNode; } | undefined
getBestAsk<T extends MarketType>(marketIndex: number, slot: number, marketType: T, oraclePriceData: T extends { spot: unknown; } ? OraclePriceData : MMOraclePriceData) => any
getBestBid<T extends MarketType>(marketIndex: number, slot: number, marketType: T, oraclePriceData: T extends { spot: unknown; } ? OraclePriceData : MMOraclePriceData) => any
getStopLosses(marketIndex: number, marketType: MarketType, direction: PositionDirection) => Generator<DLOBNode, any, any>
getStopLossMarkets(marketIndex: number, marketType: MarketType, direction: PositionDirection) => Generator<DLOBNode, any, any>
getStopLossLimits(marketIndex: number, marketType: MarketType, direction: PositionDirection) => Generator<DLOBNode, any, any>
getTakeProfits(marketIndex: number, marketType: MarketType, direction: PositionDirection) => Generator<DLOBNode, any, any>
getTakeProfitMarkets(marketIndex: number, marketType: MarketType, direction: PositionDirection) => Generator<DLOBNode, any, any>
getTakeProfitLimits(marketIndex: number, marketType: MarketType, direction: PositionDirection) => Generator<DLOBNode, any, any>
findNodesToTrigger(marketIndex: number, slot: number, triggerPrice: BN, marketType: MarketType, stateAccount: StateAccount) => NodeToTrigger[]
printTop(driftClient: DriftClient, slotSubscriber: SlotSubscriber, marketIndex: number, marketType: MarketType) => void
getDLOBOrders() => DLOBOrders
getNodeLists() => Generator<NodeList<DLOBNodeType>, any, any>
getL2<T extends MarketType>({ marketIndex, marketType, slot, oraclePriceData, depth, fallbackL2Generators, }: { marketIndex: number; marketType: T; slot: number; oraclePriceData: T extends { spot: unknown; } ? OraclePriceData : MMOraclePriceData; depth: number; fallbackL2Generators?: L2OrderBookGenerator[]; }) => L2Order...

Get an L2 view of the order book for a given market.

getL3<T extends MarketType>({ marketIndex, marketType, slot, oraclePriceData, }: { marketIndex: number; marketType: T; slot: number; oraclePriceData: T extends { spot: unknown; } ? OraclePriceData : MMOraclePriceData; }) => L3OrderBook

Get an L3 view of the order book for a given market. Does not include fallback liquidity sources

estimateFillExactBaseAmountInForSideany
estimateFillWithExactBaseAmount<T extends MarketType>({ marketIndex, marketType, baseAmount, orderDirection, slot, oraclePriceData, }: { marketIndex: number; marketType: T; baseAmount: BN; orderDirection: PositionDirection; slot: number; oraclePriceData: T extends { spot: unknown; } ? OraclePriceData : MMOraclePriceData; }) => BN
getBestMakers<T extends MarketType>({ marketIndex, marketType, direction, slot, oraclePriceData, numMakers, }: { marketIndex: number; marketType: T; direction: PositionDirection; slot: number; oraclePriceData: T extends { spot: unknown; } ? OraclePriceData : MMOraclePriceData; numMakers: number; }) => PublicKey[]
import { DLOBSubscriber, OrderSubscriber, SlotSubscriber } from "@drift-labs/sdk"; const slotSubscriber = new SlotSubscriber(connection); await slotSubscriber.subscribe(); const orderSubscriber = new OrderSubscriber({ driftClient, subscriptionConfig: { type: "websocket" }, fastDecode: true, decodeData: true, }); await orderSubscriber.subscribe(); const dlobSubscriber = new DLOBSubscriber({ driftClient, dlobSource: orderSubscriber, slotSource: slotSubscriber, updateFrequency: 1000, }); await dlobSubscriber.subscribe();

Auction subscriber (on-chain auctions)

If your workflow is centered around on-chain auctions / JIT, you can subscribe to auction-related updates.

import { AuctionSubscriber } from "@drift-labs/sdk";
Class AuctionSubscriberReference ↗
NameTypeDefault
driftClientany
optsany
resubOptsany
eventEmitterStrictEventEmitter<EventEmitter, AuctionSubscriberEvents>
subscriberany
subscribe() => Promise<void>
unsubscribe() => Promise<void>

Detecting Swift orders in on-chain feeds

If you also integrate Swift, you may see the same order “twice”: once off-chain via Swift, and again after it lands on-chain. Use isSignedMsgOrder(...) to filter Swift-origin orders.

import { isSignedMsgOrder } from "@drift-labs/sdk";
Function isSignedMsgOrderReference ↗
Parameters:
NameTypeDefault
orderOrder
Returns:
boolean
Last updated on