@drift-labs/sdk 2.17.0 → 2.18.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/dlob/DLOB.ts CHANGED
@@ -6,7 +6,6 @@ import {
6
6
  calculateBidPrice,
7
7
  DriftClient,
8
8
  convertToNumber,
9
- isAuctionComplete,
10
9
  isOrderExpired,
11
10
  isOneOfVariant,
12
11
  isVariant,
@@ -19,7 +18,6 @@ import {
19
18
  SlotSubscriber,
20
19
  MarketTypeStr,
21
20
  StateAccount,
22
- isMarketOrder,
23
21
  mustBeTriggered,
24
22
  isTriggered,
25
23
  getLimitPrice,
@@ -28,6 +26,9 @@ import {
28
26
  OrderActionRecord,
29
27
  ZERO,
30
28
  BN_MAX,
29
+ isRestingLimitOrder,
30
+ isTakingOrder,
31
+ isFallbackAvailableLiquiditySource,
31
32
  } from '..';
32
33
  import { PublicKey } from '@solana/web3.js';
33
34
  import { DLOBNode, DLOBNodeType, TriggerOrderNode } from '..';
@@ -35,14 +36,18 @@ import { ammPaused, exchangePaused, fillPaused } from '../math/exchangeStatus';
35
36
  import { DLOBOrders } from './DLOBOrders';
36
37
 
37
38
  export type MarketNodeLists = {
38
- limit: {
39
- ask: NodeList<'limit'>;
40
- bid: NodeList<'limit'>;
39
+ restingLimit: {
40
+ ask: NodeList<'restingLimit'>;
41
+ bid: NodeList<'restingLimit'>;
41
42
  };
42
43
  floatingLimit: {
43
44
  ask: NodeList<'floatingLimit'>;
44
45
  bid: NodeList<'floatingLimit'>;
45
46
  };
47
+ takingLimit: {
48
+ ask: NodeList<'takingLimit'>;
49
+ bid: NodeList<'takingLimit'>;
50
+ };
46
51
  market: {
47
52
  ask: NodeList<'market'>;
48
53
  bid: NodeList<'market'>;
@@ -75,6 +80,7 @@ const SUPPORTED_ORDER_TYPES = [
75
80
  export class DLOB {
76
81
  openOrders = new Map<MarketTypeStr, Set<string>>();
77
82
  orderLists = new Map<MarketTypeStr, Map<number, MarketNodeLists>>();
83
+ maxSlotForRestingLimitOrders = 0;
78
84
 
79
85
  initialized = false;
80
86
 
@@ -109,6 +115,8 @@ export class DLOB {
109
115
  }
110
116
  this.orderLists.clear();
111
117
 
118
+ this.maxSlotForRestingLimitOrders = 0;
119
+
112
120
  this.init();
113
121
  }
114
122
 
@@ -117,7 +125,10 @@ export class DLOB {
117
125
  *
118
126
  * @returns a promise that resolves when the DLOB is initialized
119
127
  */
120
- public async initFromUserMap(userMap: UserMap): Promise<boolean> {
128
+ public async initFromUserMap(
129
+ userMap: UserMap,
130
+ slot: number
131
+ ): Promise<boolean> {
121
132
  if (this.initialized) {
122
133
  return false;
123
134
  }
@@ -128,7 +139,7 @@ export class DLOB {
128
139
  const userAccountPubkey = user.getUserAccountPublicKey();
129
140
 
130
141
  for (const order of userAccount.orders) {
131
- this.insertOrder(order, userAccountPubkey);
142
+ this.insertOrder(order, userAccountPubkey, slot);
132
143
  }
133
144
  }
134
145
 
@@ -136,24 +147,27 @@ export class DLOB {
136
147
  return true;
137
148
  }
138
149
 
139
- public initFromOrders(dlobOrders: DLOBOrders): boolean {
150
+ public initFromOrders(dlobOrders: DLOBOrders, slot: number): boolean {
140
151
  if (this.initialized) {
141
152
  return false;
142
153
  }
143
154
 
144
155
  for (const { user, order } of dlobOrders) {
145
- this.insertOrder(order, user);
156
+ this.insertOrder(order, user, slot);
146
157
  }
147
158
 
148
159
  this.initialized = true;
149
160
  return true;
150
161
  }
151
162
 
152
- public handleOrderRecord(record: OrderRecord): void {
153
- this.insertOrder(record.order, record.user);
163
+ public handleOrderRecord(record: OrderRecord, slot: number): void {
164
+ this.insertOrder(record.order, record.user, slot);
154
165
  }
155
166
 
156
- public handleOrderActionRecord(record: OrderActionRecord): void {
167
+ public handleOrderActionRecord(
168
+ record: OrderActionRecord,
169
+ slot: number
170
+ ): void {
157
171
  if (isOneOfVariant(record.action, ['place', 'expire'])) {
158
172
  return;
159
173
  }
@@ -162,14 +176,14 @@ export class DLOB {
162
176
  if (record.taker !== null) {
163
177
  const takerOrder = this.getOrder(record.takerOrderId, record.taker);
164
178
  if (takerOrder) {
165
- this.trigger(takerOrder, record.taker);
179
+ this.trigger(takerOrder, record.taker, slot);
166
180
  }
167
181
  }
168
182
 
169
183
  if (record.maker !== null) {
170
184
  const makerOrder = this.getOrder(record.makerOrderId, record.maker);
171
185
  if (makerOrder) {
172
- this.trigger(makerOrder, record.maker);
186
+ this.trigger(makerOrder, record.maker, slot);
173
187
  }
174
188
  }
175
189
  } else if (isVariant(record.action, 'fill')) {
@@ -179,6 +193,7 @@ export class DLOB {
179
193
  this.updateOrder(
180
194
  takerOrder,
181
195
  record.taker,
196
+ slot,
182
197
  record.takerOrderCumulativeBaseAssetAmountFilled
183
198
  );
184
199
  }
@@ -190,6 +205,7 @@ export class DLOB {
190
205
  this.updateOrder(
191
206
  makerOrder,
192
207
  record.maker,
208
+ slot,
193
209
  record.makerOrderCumulativeBaseAssetAmountFilled
194
210
  );
195
211
  }
@@ -198,14 +214,14 @@ export class DLOB {
198
214
  if (record.taker !== null) {
199
215
  const takerOrder = this.getOrder(record.takerOrderId, record.taker);
200
216
  if (takerOrder) {
201
- this.delete(takerOrder, record.taker);
217
+ this.delete(takerOrder, record.taker, slot);
202
218
  }
203
219
  }
204
220
 
205
221
  if (record.maker !== null) {
206
222
  const makerOrder = this.getOrder(record.makerOrderId, record.maker);
207
223
  if (makerOrder) {
208
- this.delete(makerOrder, record.maker);
224
+ this.delete(makerOrder, record.maker, slot);
209
225
  }
210
226
  }
211
227
  }
@@ -214,6 +230,7 @@ export class DLOB {
214
230
  public insertOrder(
215
231
  order: Order,
216
232
  userAccount: PublicKey,
233
+ slot: number,
217
234
  onInsert?: OrderBookCallback
218
235
  ): void {
219
236
  if (isVariant(order.status, 'init')) {
@@ -235,7 +252,7 @@ export class DLOB {
235
252
  .get(marketType)
236
253
  .add(getOrderSignature(order.orderId, userAccount));
237
254
  }
238
- this.getListForOrder(order)?.insert(order, marketType, userAccount);
255
+ this.getListForOrder(order, slot)?.insert(order, marketType, userAccount);
239
256
 
240
257
  if (onInsert) {
241
258
  onInsert();
@@ -244,14 +261,18 @@ export class DLOB {
244
261
 
245
262
  addOrderList(marketType: MarketTypeStr, marketIndex: number): void {
246
263
  this.orderLists.get(marketType).set(marketIndex, {
247
- limit: {
248
- ask: new NodeList('limit', 'asc'),
249
- bid: new NodeList('limit', 'desc'),
264
+ restingLimit: {
265
+ ask: new NodeList('restingLimit', 'asc'),
266
+ bid: new NodeList('restingLimit', 'desc'),
250
267
  },
251
268
  floatingLimit: {
252
269
  ask: new NodeList('floatingLimit', 'asc'),
253
270
  bid: new NodeList('floatingLimit', 'desc'),
254
271
  },
272
+ takingLimit: {
273
+ ask: new NodeList('takingLimit', 'asc'),
274
+ bid: new NodeList('takingLimit', 'asc'), // always sort ascending for market orders
275
+ },
255
276
  market: {
256
277
  ask: new NodeList('market', 'asc'),
257
278
  bid: new NodeList('market', 'asc'), // always sort ascending for market orders
@@ -266,11 +287,14 @@ export class DLOB {
266
287
  public updateOrder(
267
288
  order: Order,
268
289
  userAccount: PublicKey,
290
+ slot: number,
269
291
  cumulativeBaseAssetAmountFilled: BN,
270
292
  onUpdate?: OrderBookCallback
271
293
  ): void {
294
+ this.updateRestingLimitOrders(slot);
295
+
272
296
  if (order.baseAssetAmount.eq(cumulativeBaseAssetAmountFilled)) {
273
- this.delete(order, userAccount);
297
+ this.delete(order, userAccount, slot);
274
298
  return;
275
299
  }
276
300
 
@@ -283,7 +307,7 @@ export class DLOB {
283
307
  };
284
308
  newOrder.baseAssetAmountFilled = cumulativeBaseAssetAmountFilled;
285
309
 
286
- this.getListForOrder(order)?.update(newOrder, userAccount);
310
+ this.getListForOrder(order, slot)?.update(newOrder, userAccount);
287
311
 
288
312
  if (onUpdate) {
289
313
  onUpdate();
@@ -293,12 +317,15 @@ export class DLOB {
293
317
  public trigger(
294
318
  order: Order,
295
319
  userAccount: PublicKey,
320
+ slot: number,
296
321
  onTrigger?: OrderBookCallback
297
322
  ): void {
298
323
  if (isVariant(order.status, 'init')) {
299
324
  return;
300
325
  }
301
326
 
327
+ this.updateRestingLimitOrders(slot);
328
+
302
329
  if (isTriggered(order)) {
303
330
  return;
304
331
  }
@@ -309,7 +336,7 @@ export class DLOB {
309
336
  .trigger[isVariant(order.triggerCondition, 'above') ? 'above' : 'below'];
310
337
  triggerList.remove(order, userAccount);
311
338
 
312
- this.getListForOrder(order)?.insert(order, marketType, userAccount);
339
+ this.getListForOrder(order, slot)?.insert(order, marketType, userAccount);
313
340
  if (onTrigger) {
314
341
  onTrigger();
315
342
  }
@@ -318,19 +345,25 @@ export class DLOB {
318
345
  public delete(
319
346
  order: Order,
320
347
  userAccount: PublicKey,
348
+ slot: number,
321
349
  onDelete?: OrderBookCallback
322
350
  ): void {
323
351
  if (isVariant(order.status, 'init')) {
324
352
  return;
325
353
  }
326
354
 
327
- this.getListForOrder(order)?.remove(order, userAccount);
355
+ this.updateRestingLimitOrders(slot);
356
+
357
+ this.getListForOrder(order, slot)?.remove(order, userAccount);
328
358
  if (onDelete) {
329
359
  onDelete();
330
360
  }
331
361
  }
332
362
 
333
- public getListForOrder(order: Order): NodeList<any> | undefined {
363
+ public getListForOrder(
364
+ order: Order,
365
+ slot: number
366
+ ): NodeList<any> | undefined {
334
367
  const isInactiveTriggerOrder =
335
368
  mustBeTriggered(order) && !isTriggered(order);
336
369
 
@@ -344,7 +377,8 @@ export class DLOB {
344
377
  } else if (order.oraclePriceOffset !== 0) {
345
378
  type = 'floatingLimit';
346
379
  } else {
347
- type = 'limit';
380
+ const isResting = isRestingLimitOrder(order, slot);
381
+ type = isResting ? 'restingLimit' : 'takingLimit';
348
382
  }
349
383
 
350
384
  let subType: string;
@@ -365,6 +399,58 @@ export class DLOB {
365
399
  ];
366
400
  }
367
401
 
402
+ public updateRestingLimitOrders(slot: number): void {
403
+ if (slot <= this.maxSlotForRestingLimitOrders) {
404
+ return;
405
+ }
406
+
407
+ this.maxSlotForRestingLimitOrders = slot;
408
+
409
+ this.updateRestingLimitOrdersForMarketType(slot, 'perp');
410
+
411
+ this.updateRestingLimitOrdersForMarketType(slot, 'spot');
412
+ }
413
+
414
+ updateRestingLimitOrdersForMarketType(
415
+ slot: number,
416
+ marketTypeStr: MarketTypeStr
417
+ ): void {
418
+ for (const [_, nodeLists] of this.orderLists.get(marketTypeStr)) {
419
+ const nodesToUpdate = [];
420
+ for (const node of nodeLists.takingLimit.ask.getGenerator()) {
421
+ if (!isRestingLimitOrder(node.order, slot)) {
422
+ continue;
423
+ }
424
+
425
+ nodesToUpdate.push({
426
+ side: 'ask',
427
+ node,
428
+ });
429
+ }
430
+
431
+ for (const node of nodeLists.takingLimit.bid.getGenerator()) {
432
+ if (!isRestingLimitOrder(node.order, slot)) {
433
+ continue;
434
+ }
435
+
436
+ nodesToUpdate.push({
437
+ side: 'bid',
438
+ node,
439
+ });
440
+ }
441
+
442
+ for (const nodeToUpdate of nodesToUpdate) {
443
+ const { side, node } = nodeToUpdate;
444
+ nodeLists.takingLimit[side].remove(node.order, node.userAccount);
445
+ nodeLists.restingLimit[side].insert(
446
+ node.order,
447
+ marketTypeStr,
448
+ node.userAccount
449
+ );
450
+ }
451
+ }
452
+ }
453
+
368
454
  public getOrder(orderId: number, userAccount: PublicKey): Order | undefined {
369
455
  for (const nodeList of this.getNodeLists()) {
370
456
  const node = nodeList.get(orderId, userAccount);
@@ -393,24 +479,30 @@ export class DLOB {
393
479
 
394
480
  const isAmmPaused = ammPaused(stateAccount, marketAccount);
395
481
 
396
- const marketOrderNodesToFill: Array<NodeToFill> =
397
- this.findMarketNodesToFill(
482
+ const minAuctionDuration = isVariant(marketType, 'perp')
483
+ ? stateAccount.minPerpAuctionDuration
484
+ : 0;
485
+
486
+ const restingLimitOrderNodesToFill: Array<NodeToFill> =
487
+ this.findRestingLimitOrderNodesToFill(
398
488
  marketIndex,
399
489
  slot,
400
490
  marketType,
401
491
  oraclePriceData,
402
492
  isAmmPaused,
493
+ minAuctionDuration,
403
494
  fallbackAsk,
404
495
  fallbackBid
405
496
  );
406
497
 
407
- const limitOrderNodesToFill: Array<NodeToFill> =
408
- this.findLimitOrderNodesToFill(
498
+ const takingOrderNodesToFill: Array<NodeToFill> =
499
+ this.findTakingNodesToFill(
409
500
  marketIndex,
410
501
  slot,
411
502
  marketType,
412
503
  oraclePriceData,
413
504
  isAmmPaused,
505
+ minAuctionDuration,
414
506
  fallbackAsk,
415
507
  fallbackBid
416
508
  );
@@ -421,28 +513,30 @@ export class DLOB {
421
513
  ts,
422
514
  marketType
423
515
  );
424
- return marketOrderNodesToFill.concat(
425
- limitOrderNodesToFill,
516
+ return restingLimitOrderNodesToFill.concat(
517
+ takingOrderNodesToFill,
426
518
  expiredNodesToFill
427
519
  );
428
520
  }
429
521
 
430
- public findLimitOrderNodesToFill(
522
+ public findRestingLimitOrderNodesToFill(
431
523
  marketIndex: number,
432
524
  slot: number,
433
525
  marketType: MarketType,
434
526
  oraclePriceData: OraclePriceData,
435
527
  isAmmPaused: boolean,
528
+ minAuctionDuration: number,
436
529
  fallbackAsk: BN | undefined,
437
530
  fallbackBid: BN | undefined
438
531
  ): NodeToFill[] {
439
532
  const nodesToFill = new Array<NodeToFill>();
440
533
 
441
- const crossingNodes = this.findCrossingLimitOrders(
534
+ const crossingNodes = this.findCrossingRestingLimitOrders(
442
535
  marketIndex,
443
536
  slot,
444
537
  marketType,
445
538
  oraclePriceData,
539
+ minAuctionDuration,
446
540
  fallbackAsk,
447
541
  fallbackBid
448
542
  );
@@ -452,7 +546,7 @@ export class DLOB {
452
546
  }
453
547
 
454
548
  if (fallbackBid && !isAmmPaused) {
455
- const askGenerator = this.getLimitAsks(
549
+ const askGenerator = this.getRestingLimitAsks(
456
550
  marketIndex,
457
551
  slot,
458
552
  marketType,
@@ -466,7 +560,8 @@ export class DLOB {
466
560
  fallbackBid,
467
561
  (askPrice, fallbackPrice) => {
468
562
  return askPrice.lte(fallbackPrice);
469
- }
563
+ },
564
+ minAuctionDuration
470
565
  );
471
566
 
472
567
  for (const askCrossingFallback of asksCrossingFallback) {
@@ -475,7 +570,7 @@ export class DLOB {
475
570
  }
476
571
 
477
572
  if (fallbackAsk && !isAmmPaused) {
478
- const bidGenerator = this.getLimitBids(
573
+ const bidGenerator = this.getRestingLimitBids(
479
574
  marketIndex,
480
575
  slot,
481
576
  marketType,
@@ -489,7 +584,8 @@ export class DLOB {
489
584
  fallbackAsk,
490
585
  (bidPrice, fallbackPrice) => {
491
586
  return bidPrice.gte(fallbackPrice);
492
- }
587
+ },
588
+ minAuctionDuration
493
589
  );
494
590
 
495
591
  for (const bidCrossingFallback of bidsCrossingFallback) {
@@ -500,25 +596,31 @@ export class DLOB {
500
596
  return nodesToFill;
501
597
  }
502
598
 
503
- public findMarketNodesToFill(
599
+ public findTakingNodesToFill(
504
600
  marketIndex: number,
505
601
  slot: number,
506
602
  marketType: MarketType,
507
603
  oraclePriceData: OraclePriceData,
508
604
  isAmmPaused: boolean,
605
+ minAuctionDuration: number,
509
606
  fallbackAsk: BN | undefined,
510
607
  fallbackBid?: BN | undefined
511
608
  ): NodeToFill[] {
512
609
  const nodesToFill = new Array<NodeToFill>();
513
610
 
514
- let marketOrderGenerator = this.getMarketAsks(marketIndex, marketType);
611
+ let takingOrderGenerator = this.getTakingAsks(
612
+ marketIndex,
613
+ marketType,
614
+ slot,
615
+ oraclePriceData
616
+ );
515
617
 
516
- const marketAsksCrossingBids = this.findMarketNodesCrossingLimitNodes(
618
+ const takingAsksCrossingBids = this.findTakingNodesCrossingMakerNodes(
517
619
  marketIndex,
518
620
  slot,
519
621
  marketType,
520
622
  oraclePriceData,
521
- marketOrderGenerator,
623
+ takingOrderGenerator,
522
624
  this.getMakerLimitBids.bind(this),
523
625
  (takerPrice, makerPrice) => {
524
626
  if (isVariant(marketType, 'spot')) {
@@ -534,37 +636,48 @@ export class DLOB {
534
636
  },
535
637
  fallbackAsk
536
638
  );
537
- for (const marketAskCrossingBid of marketAsksCrossingBids) {
538
- nodesToFill.push(marketAskCrossingBid);
639
+ for (const takingAskCrossingBid of takingAsksCrossingBids) {
640
+ nodesToFill.push(takingAskCrossingBid);
539
641
  }
540
642
 
541
643
  if (fallbackBid && !isAmmPaused) {
542
- marketOrderGenerator = this.getMarketAsks(marketIndex, marketType);
543
- const marketAsksCrossingFallback =
644
+ takingOrderGenerator = this.getTakingAsks(
645
+ marketIndex,
646
+ marketType,
647
+ slot,
648
+ oraclePriceData
649
+ );
650
+ const takingAsksCrossingFallback =
544
651
  this.findNodesCrossingFallbackLiquidity(
545
652
  marketType,
546
653
  slot,
547
654
  oraclePriceData,
548
- marketOrderGenerator,
655
+ takingOrderGenerator,
549
656
  fallbackBid,
550
657
  (takerPrice, fallbackPrice) => {
551
658
  return takerPrice === undefined || takerPrice.lte(fallbackPrice);
552
- }
659
+ },
660
+ minAuctionDuration
553
661
  );
554
662
 
555
- for (const marketAskCrossingFallback of marketAsksCrossingFallback) {
556
- nodesToFill.push(marketAskCrossingFallback);
663
+ for (const takingAskCrossingFallback of takingAsksCrossingFallback) {
664
+ nodesToFill.push(takingAskCrossingFallback);
557
665
  }
558
666
  }
559
667
 
560
- marketOrderGenerator = this.getMarketBids(marketIndex, marketType);
668
+ takingOrderGenerator = this.getTakingBids(
669
+ marketIndex,
670
+ marketType,
671
+ slot,
672
+ oraclePriceData
673
+ );
561
674
 
562
- const marketBidsToFill = this.findMarketNodesCrossingLimitNodes(
675
+ const takingBidsToFill = this.findTakingNodesCrossingMakerNodes(
563
676
  marketIndex,
564
677
  slot,
565
678
  marketType,
566
679
  oraclePriceData,
567
- marketOrderGenerator,
680
+ takingOrderGenerator,
568
681
  this.getMakerLimitAsks.bind(this),
569
682
  (takerPrice, makerPrice) => {
570
683
  if (isVariant(marketType, 'spot')) {
@@ -582,24 +695,30 @@ export class DLOB {
582
695
  fallbackBid
583
696
  );
584
697
 
585
- for (const marketBidToFill of marketBidsToFill) {
586
- nodesToFill.push(marketBidToFill);
698
+ for (const takingBidToFill of takingBidsToFill) {
699
+ nodesToFill.push(takingBidToFill);
587
700
  }
588
701
 
589
702
  if (fallbackAsk && !isAmmPaused) {
590
- marketOrderGenerator = this.getMarketBids(marketIndex, marketType);
591
- const marketBidsCrossingFallback =
703
+ takingOrderGenerator = this.getTakingBids(
704
+ marketIndex,
705
+ marketType,
706
+ slot,
707
+ oraclePriceData
708
+ );
709
+ const takingBidsCrossingFallback =
592
710
  this.findNodesCrossingFallbackLiquidity(
593
711
  marketType,
594
712
  slot,
595
713
  oraclePriceData,
596
- marketOrderGenerator,
714
+ takingOrderGenerator,
597
715
  fallbackAsk,
598
716
  (takerPrice, fallbackPrice) => {
599
717
  return takerPrice === undefined || takerPrice.gte(fallbackPrice);
600
- }
718
+ },
719
+ minAuctionDuration
601
720
  );
602
- for (const marketBidCrossingFallback of marketBidsCrossingFallback) {
721
+ for (const marketBidCrossingFallback of takingBidsCrossingFallback) {
603
722
  nodesToFill.push(marketBidCrossingFallback);
604
723
  }
605
724
  }
@@ -607,7 +726,7 @@ export class DLOB {
607
726
  return nodesToFill;
608
727
  }
609
728
 
610
- public findMarketNodesCrossingLimitNodes(
729
+ public findTakingNodesCrossingMakerNodes(
611
730
  marketIndex: number,
612
731
  slot: number,
613
732
  marketType: MarketType,
@@ -671,7 +790,7 @@ export class DLOB {
671
790
  const newMakerOrder = { ...makerOrder };
672
791
  newMakerOrder.baseAssetAmountFilled =
673
792
  makerOrder.baseAssetAmountFilled.add(baseFilled);
674
- this.getListForOrder(newMakerOrder).update(
793
+ this.getListForOrder(newMakerOrder, slot).update(
675
794
  newMakerOrder,
676
795
  makerNode.userAccount
677
796
  );
@@ -679,7 +798,7 @@ export class DLOB {
679
798
  const newTakerOrder = { ...takerOrder };
680
799
  newTakerOrder.baseAssetAmountFilled =
681
800
  takerOrder.baseAssetAmountFilled.add(baseFilled);
682
- this.getListForOrder(newTakerOrder).update(
801
+ this.getListForOrder(newTakerOrder, slot).update(
683
802
  newTakerOrder,
684
803
  takerNode.userAccount
685
804
  );
@@ -701,7 +820,8 @@ export class DLOB {
701
820
  oraclePriceData: OraclePriceData,
702
821
  nodeGenerator: Generator<DLOBNode>,
703
822
  fallbackPrice: BN,
704
- doesCross: (nodePrice: BN | undefined, fallbackPrice: BN) => boolean
823
+ doesCross: (nodePrice: BN | undefined, fallbackPrice: BN) => boolean,
824
+ minAuctionDuration: number
705
825
  ): NodeToFill[] {
706
826
  const nodesToFill = new Array<NodeToFill>();
707
827
 
@@ -721,7 +841,12 @@ export class DLOB {
721
841
 
722
842
  // fallback is available if auction is complete or it's a spot order
723
843
  const fallbackAvailable =
724
- isVariant(marketType, 'spot') || isAuctionComplete(node.order, slot);
844
+ isVariant(marketType, 'spot') ||
845
+ isFallbackAvailableLiquiditySource(
846
+ node.order,
847
+ minAuctionDuration,
848
+ slot
849
+ );
725
850
 
726
851
  if (crosses && fallbackAvailable) {
727
852
  nodesToFill.push({
@@ -752,12 +877,14 @@ export class DLOB {
752
877
 
753
878
  // All bids/asks that can expire
754
879
  const bidGenerators = [
755
- nodeLists.limit.bid.getGenerator(),
880
+ nodeLists.takingLimit.bid.getGenerator(),
881
+ nodeLists.restingLimit.bid.getGenerator(),
756
882
  nodeLists.floatingLimit.bid.getGenerator(),
757
883
  nodeLists.market.bid.getGenerator(),
758
884
  ];
759
885
  const askGenerators = [
760
- nodeLists.limit.ask.getGenerator(),
886
+ nodeLists.takingLimit.ask.getGenerator(),
887
+ nodeLists.restingLimit.ask.getGenerator(),
761
888
  nodeLists.floatingLimit.ask.getGenerator(),
762
889
  nodeLists.market.ask.getGenerator(),
763
890
  ];
@@ -788,31 +915,40 @@ export class DLOB {
788
915
  public findJitAuctionNodesToFill(
789
916
  marketIndex: number,
790
917
  slot: number,
918
+ oraclePriceData: OraclePriceData,
791
919
  marketType: MarketType
792
920
  ): NodeToFill[] {
793
921
  const nodesToFill = new Array<NodeToFill>();
794
922
  // Then see if there are orders still in JIT auction
795
- for (const marketBid of this.getMarketBids(marketIndex, marketType)) {
796
- if (!isAuctionComplete(marketBid.order, slot)) {
797
- nodesToFill.push({
798
- node: marketBid,
799
- });
800
- }
923
+ for (const marketBid of this.getTakingBids(
924
+ marketIndex,
925
+ marketType,
926
+ slot,
927
+ oraclePriceData
928
+ )) {
929
+ nodesToFill.push({
930
+ node: marketBid,
931
+ });
801
932
  }
802
933
 
803
- for (const marketAsk of this.getMarketAsks(marketIndex, marketType)) {
804
- if (!isAuctionComplete(marketAsk.order, slot)) {
805
- nodesToFill.push({
806
- node: marketAsk,
807
- });
808
- }
934
+ for (const marketAsk of this.getTakingAsks(
935
+ marketIndex,
936
+ marketType,
937
+ slot,
938
+ oraclePriceData
939
+ )) {
940
+ nodesToFill.push({
941
+ node: marketAsk,
942
+ });
809
943
  }
810
944
  return nodesToFill;
811
945
  }
812
946
 
813
- *getMarketBids(
947
+ *getTakingBids(
814
948
  marketIndex: number,
815
- marketType: MarketType
949
+ marketType: MarketType,
950
+ slot: number,
951
+ oraclePriceData: OraclePriceData
816
952
  ): Generator<DLOBNode> {
817
953
  const marketTypeStr = getVariant(marketType) as MarketTypeStr;
818
954
  const orderLists = this.orderLists.get(marketTypeStr).get(marketIndex);
@@ -820,18 +956,28 @@ export class DLOB {
820
956
  return;
821
957
  }
822
958
 
823
- const generator = orderLists.market.bid.getGenerator();
824
- for (const marketBidNode of generator) {
825
- if (marketBidNode.isBaseFilled()) {
826
- continue;
959
+ this.updateRestingLimitOrders(slot);
960
+
961
+ const generatorList = [
962
+ orderLists.market.bid.getGenerator(),
963
+ orderLists.takingLimit.bid.getGenerator(),
964
+ ];
965
+
966
+ yield* this.getBestNode(
967
+ generatorList,
968
+ oraclePriceData,
969
+ slot,
970
+ (bestNode, currentNode) => {
971
+ return bestNode.order.slot.lt(currentNode.order.slot);
827
972
  }
828
- yield marketBidNode;
829
- }
973
+ );
830
974
  }
831
975
 
832
- *getMarketAsks(
976
+ *getTakingAsks(
833
977
  marketIndex: number,
834
- marketType: MarketType
978
+ marketType: MarketType,
979
+ slot: number,
980
+ oraclePriceData: OraclePriceData
835
981
  ): Generator<DLOBNode> {
836
982
  const marketTypeStr = getVariant(marketType) as MarketTypeStr;
837
983
  const orderLists = this.orderLists.get(marketTypeStr).get(marketIndex);
@@ -839,20 +985,33 @@ export class DLOB {
839
985
  return;
840
986
  }
841
987
 
842
- const generator = orderLists.market.ask.getGenerator();
843
- for (const marketAskNode of generator) {
844
- if (marketAskNode.isBaseFilled()) {
845
- continue;
988
+ this.updateRestingLimitOrders(slot);
989
+
990
+ const generatorList = [
991
+ orderLists.market.ask.getGenerator(),
992
+ orderLists.takingLimit.ask.getGenerator(),
993
+ ];
994
+
995
+ yield* this.getBestNode(
996
+ generatorList,
997
+ oraclePriceData,
998
+ slot,
999
+ (bestNode, currentNode) => {
1000
+ return bestNode.order.slot.lt(currentNode.order.slot);
846
1001
  }
847
- yield marketAskNode;
848
- }
1002
+ );
849
1003
  }
850
1004
 
851
1005
  private *getBestNode(
852
1006
  generatorList: Array<Generator<DLOBNode>>,
853
1007
  oraclePriceData: OraclePriceData,
854
1008
  slot: number,
855
- compareFcn: (bestPrice: BN, currentPrice: BN) => boolean
1009
+ compareFcn: (
1010
+ bestDLOBNode: DLOBNode,
1011
+ currentDLOBNode: DLOBNode,
1012
+ slot: number,
1013
+ oraclePriceData: OraclePriceData
1014
+ ) => boolean
856
1015
  ): Generator<DLOBNode> {
857
1016
  const generators = generatorList.map((generator) => {
858
1017
  return {
@@ -876,18 +1035,7 @@ export class DLOB {
876
1035
  const bestValue = bestGenerator.next.value as DLOBNode;
877
1036
  const currentValue = currentGenerator.next.value as DLOBNode;
878
1037
 
879
- // always return the market orders first
880
- if (bestValue.order && isMarketOrder(bestValue.order)) {
881
- return bestGenerator;
882
- }
883
- if (currentValue.order && isMarketOrder(currentValue.order)) {
884
- return currentGenerator;
885
- }
886
-
887
- const bestPrice = bestValue.getPrice(oraclePriceData, slot);
888
- const currentPrice = currentValue.getPrice(oraclePriceData, slot);
889
-
890
- return compareFcn(bestPrice, currentPrice)
1038
+ return compareFcn(bestValue, currentValue, slot, oraclePriceData)
891
1039
  ? bestGenerator
892
1040
  : currentGenerator;
893
1041
  }
@@ -908,7 +1056,7 @@ export class DLOB {
908
1056
  }
909
1057
  }
910
1058
 
911
- *getLimitAsks(
1059
+ *getRestingLimitAsks(
912
1060
  marketIndex: number,
913
1061
  slot: number,
914
1062
  marketType: MarketType,
@@ -917,6 +1065,9 @@ export class DLOB {
917
1065
  if (isVariant(marketType, 'spot') && !oraclePriceData) {
918
1066
  throw new Error('Must provide OraclePriceData to get spot asks');
919
1067
  }
1068
+
1069
+ this.updateRestingLimitOrders(slot);
1070
+
920
1071
  const marketTypeStr = getVariant(marketType) as MarketTypeStr;
921
1072
  const nodeLists = this.orderLists.get(marketTypeStr).get(marketIndex);
922
1073
 
@@ -925,7 +1076,7 @@ export class DLOB {
925
1076
  }
926
1077
 
927
1078
  const generatorList = [
928
- nodeLists.limit.ask.getGenerator(),
1079
+ nodeLists.restingLimit.ask.getGenerator(),
929
1080
  nodeLists.floatingLimit.ask.getGenerator(),
930
1081
  ];
931
1082
 
@@ -933,15 +1084,17 @@ export class DLOB {
933
1084
  generatorList,
934
1085
  oraclePriceData,
935
1086
  slot,
936
- (bestPrice, currentPrice) => {
937
- return bestPrice.lt(currentPrice);
1087
+ (bestNode, currentNode, slot, oraclePriceData) => {
1088
+ return bestNode
1089
+ .getPrice(oraclePriceData, slot)
1090
+ .lt(currentNode.getPrice(oraclePriceData, slot));
938
1091
  }
939
1092
  );
940
1093
  }
941
1094
 
942
1095
  /**
943
- * Filters the limit asks that are post only, have been place for sufficiently long or are above the fallback bid
944
- * Market orders can only fill against orders that meet this criteria
1096
+ * Filters the limit asks that are resting and do not cross fallback bid
1097
+ * Taking orders can only fill against orders that meet this criteria
945
1098
  *
946
1099
  * @returns
947
1100
  */
@@ -952,28 +1105,23 @@ export class DLOB {
952
1105
  oraclePriceData: OraclePriceData,
953
1106
  fallbackBid?: BN
954
1107
  ): Generator<DLOBNode> {
955
- for (const node of this.getLimitAsks(
1108
+ for (const node of this.getRestingLimitAsks(
956
1109
  marketIndex,
957
1110
  slot,
958
1111
  marketType,
959
1112
  oraclePriceData
960
1113
  )) {
961
- if (this.isRestingLimitOrder(node.order, slot)) {
962
- yield node;
963
- } else if (
1114
+ if (
964
1115
  fallbackBid &&
965
- node.getPrice(oraclePriceData, slot).gt(fallbackBid)
1116
+ node.getPrice(oraclePriceData, slot).lte(fallbackBid)
966
1117
  ) {
967
- yield node;
1118
+ continue;
968
1119
  }
1120
+ yield node;
969
1121
  }
970
1122
  }
971
1123
 
972
- isRestingLimitOrder(order: Order, slot: number): boolean {
973
- return order.postOnly || new BN(slot).sub(order.slot).gte(new BN(45));
974
- }
975
-
976
- *getLimitBids(
1124
+ *getRestingLimitBids(
977
1125
  marketIndex: number,
978
1126
  slot: number,
979
1127
  marketType: MarketType,
@@ -983,6 +1131,8 @@ export class DLOB {
983
1131
  throw new Error('Must provide OraclePriceData to get spot bids');
984
1132
  }
985
1133
 
1134
+ this.updateRestingLimitOrders(slot);
1135
+
986
1136
  const marketTypeStr = getVariant(marketType) as MarketTypeStr;
987
1137
  const nodeLists = this.orderLists.get(marketTypeStr).get(marketIndex);
988
1138
 
@@ -991,7 +1141,7 @@ export class DLOB {
991
1141
  }
992
1142
 
993
1143
  const generatorList = [
994
- nodeLists.limit.bid.getGenerator(),
1144
+ nodeLists.restingLimit.bid.getGenerator(),
995
1145
  nodeLists.floatingLimit.bid.getGenerator(),
996
1146
  ];
997
1147
 
@@ -999,8 +1149,10 @@ export class DLOB {
999
1149
  generatorList,
1000
1150
  oraclePriceData,
1001
1151
  slot,
1002
- (bestPrice, currentPrice) => {
1003
- return bestPrice.gt(currentPrice);
1152
+ (bestNode, currentNode, slot, oraclePriceData) => {
1153
+ return bestNode
1154
+ .getPrice(oraclePriceData, slot)
1155
+ .gt(currentNode.getPrice(oraclePriceData, slot));
1004
1156
  }
1005
1157
  );
1006
1158
  }
@@ -1018,20 +1170,19 @@ export class DLOB {
1018
1170
  oraclePriceData: OraclePriceData,
1019
1171
  fallbackAsk?: BN
1020
1172
  ): Generator<DLOBNode> {
1021
- for (const node of this.getLimitBids(
1173
+ for (const node of this.getRestingLimitBids(
1022
1174
  marketIndex,
1023
1175
  slot,
1024
1176
  marketType,
1025
1177
  oraclePriceData
1026
1178
  )) {
1027
- if (this.isRestingLimitOrder(node.order, slot)) {
1028
- yield node;
1029
- } else if (
1179
+ if (
1030
1180
  fallbackAsk &&
1031
- node.getPrice(oraclePriceData, slot).lt(fallbackAsk)
1181
+ node.getPrice(oraclePriceData, slot).gte(fallbackAsk)
1032
1182
  ) {
1033
- yield node;
1183
+ continue;
1034
1184
  }
1185
+ yield node;
1035
1186
  }
1036
1187
  }
1037
1188
 
@@ -1047,8 +1198,8 @@ export class DLOB {
1047
1198
  }
1048
1199
 
1049
1200
  const generatorList = [
1050
- this.getMarketAsks(marketIndex, marketType),
1051
- this.getLimitAsks(marketIndex, slot, marketType, oraclePriceData),
1201
+ this.getTakingAsks(marketIndex, marketType, slot, oraclePriceData),
1202
+ this.getRestingLimitAsks(marketIndex, slot, marketType, oraclePriceData),
1052
1203
  ];
1053
1204
 
1054
1205
  const marketTypeStr = getVariant(marketType) as MarketTypeStr;
@@ -1060,8 +1211,29 @@ export class DLOB {
1060
1211
  generatorList,
1061
1212
  oraclePriceData,
1062
1213
  slot,
1063
- (bestPrice, currentPrice) => {
1064
- return bestPrice.lt(currentPrice);
1214
+ (bestNode, currentNode, slot, oraclePriceData) => {
1215
+ const bestNodeTaking = bestNode.order
1216
+ ? isTakingOrder(bestNode.order, slot)
1217
+ : false;
1218
+ const currentNodeTaking = currentNode.order
1219
+ ? isTakingOrder(currentNode.order, slot)
1220
+ : false;
1221
+
1222
+ if (bestNodeTaking && currentNodeTaking) {
1223
+ return bestNode.order.slot.lt(currentNode.order.slot);
1224
+ }
1225
+
1226
+ if (bestNodeTaking) {
1227
+ return true;
1228
+ }
1229
+
1230
+ if (currentNodeTaking) {
1231
+ return false;
1232
+ }
1233
+
1234
+ return bestNode
1235
+ .getPrice(oraclePriceData, slot)
1236
+ .lt(currentNode.getPrice(oraclePriceData, slot));
1065
1237
  }
1066
1238
  );
1067
1239
  }
@@ -1078,8 +1250,8 @@ export class DLOB {
1078
1250
  }
1079
1251
 
1080
1252
  const generatorList = [
1081
- this.getMarketBids(marketIndex, marketType),
1082
- this.getLimitBids(marketIndex, slot, marketType, oraclePriceData),
1253
+ this.getTakingBids(marketIndex, marketType, slot, oraclePriceData),
1254
+ this.getRestingLimitBids(marketIndex, slot, marketType, oraclePriceData),
1083
1255
  ];
1084
1256
 
1085
1257
  const marketTypeStr = getVariant(marketType) as MarketTypeStr;
@@ -1091,40 +1263,64 @@ export class DLOB {
1091
1263
  generatorList,
1092
1264
  oraclePriceData,
1093
1265
  slot,
1094
- (bestPrice, currentPrice) => {
1095
- return bestPrice.gt(currentPrice);
1266
+ (bestNode, currentNode, slot, oraclePriceData) => {
1267
+ const bestNodeTaking = bestNode.order
1268
+ ? isTakingOrder(bestNode.order, slot)
1269
+ : false;
1270
+ const currentNodeTaking = currentNode.order
1271
+ ? isTakingOrder(currentNode.order, slot)
1272
+ : false;
1273
+
1274
+ if (bestNodeTaking && currentNodeTaking) {
1275
+ return bestNode.order.slot.lt(currentNode.order.slot);
1276
+ }
1277
+
1278
+ if (bestNodeTaking) {
1279
+ return true;
1280
+ }
1281
+
1282
+ if (currentNodeTaking) {
1283
+ return false;
1284
+ }
1285
+
1286
+ return bestNode
1287
+ .getPrice(oraclePriceData, slot)
1288
+ .gt(currentNode.getPrice(oraclePriceData, slot));
1096
1289
  }
1097
1290
  );
1098
1291
  }
1099
1292
 
1100
- findCrossingLimitOrders(
1293
+ findCrossingRestingLimitOrders(
1101
1294
  marketIndex: number,
1102
1295
  slot: number,
1103
1296
  marketType: MarketType,
1104
1297
  oraclePriceData: OraclePriceData,
1298
+ minAuctionDuration: number,
1105
1299
  fallbackAsk: BN | undefined,
1106
1300
  fallbackBid: BN | undefined
1107
1301
  ): NodeToFill[] {
1108
1302
  const nodesToFill = new Array<NodeToFill>();
1109
1303
 
1110
- for (const askNode of this.getLimitAsks(
1304
+ for (const askNode of this.getRestingLimitAsks(
1111
1305
  marketIndex,
1112
1306
  slot,
1113
1307
  marketType,
1114
1308
  oraclePriceData
1115
1309
  )) {
1116
- for (const bidNode of this.getLimitBids(
1310
+ const bidGenerator = this.getRestingLimitBids(
1117
1311
  marketIndex,
1118
1312
  slot,
1119
1313
  marketType,
1120
1314
  oraclePriceData
1121
- )) {
1315
+ );
1316
+
1317
+ for (const bidNode of bidGenerator) {
1122
1318
  const bidPrice = bidNode.getPrice(oraclePriceData, slot);
1123
1319
  const askPrice = askNode.getPrice(oraclePriceData, slot);
1124
1320
 
1125
- // orders don't cross - we're done walking the book
1321
+ // orders don't cross
1126
1322
  if (bidPrice.lt(askPrice)) {
1127
- return nodesToFill;
1323
+ break;
1128
1324
  }
1129
1325
 
1130
1326
  const bidOrder = bidNode.order;
@@ -1132,17 +1328,27 @@ export class DLOB {
1132
1328
 
1133
1329
  // Can't match orders from the same user
1134
1330
  const sameUser = bidNode.userAccount.equals(askNode.userAccount);
1135
- if (sameUser || (bidOrder.postOnly && askOrder.postOnly)) {
1331
+ if (sameUser) {
1136
1332
  continue;
1137
1333
  }
1138
1334
 
1139
- const { takerNode, makerNode } = this.determineMakerAndTaker(
1140
- askNode,
1141
- bidNode
1142
- );
1335
+ const makerAndTaker = this.determineMakerAndTaker(askNode, bidNode);
1336
+
1337
+ // unable to match maker and taker due to post only or slot
1338
+ if (!makerAndTaker) {
1339
+ continue;
1340
+ }
1341
+
1342
+ const { takerNode, makerNode } = makerAndTaker;
1143
1343
 
1144
1344
  // extra guard against bad fills for limit orders where auction is incomplete
1145
- if (!isAuctionComplete(takerNode.order, slot)) {
1345
+ if (
1346
+ !isFallbackAvailableLiquiditySource(
1347
+ takerNode.order,
1348
+ minAuctionDuration,
1349
+ slot
1350
+ )
1351
+ ) {
1146
1352
  let bidPrice: BN;
1147
1353
  let askPrice: BN;
1148
1354
  if (isVariant(takerNode.order.direction, 'long')) {
@@ -1176,7 +1382,7 @@ export class DLOB {
1176
1382
  const newBidOrder = { ...bidOrder };
1177
1383
  newBidOrder.baseAssetAmountFilled =
1178
1384
  bidOrder.baseAssetAmountFilled.add(baseFilled);
1179
- this.getListForOrder(newBidOrder).update(
1385
+ this.getListForOrder(newBidOrder, slot).update(
1180
1386
  newBidOrder,
1181
1387
  bidNode.userAccount
1182
1388
  );
@@ -1185,7 +1391,7 @@ export class DLOB {
1185
1391
  const newAskOrder = { ...askOrder };
1186
1392
  newAskOrder.baseAssetAmountFilled =
1187
1393
  askOrder.baseAssetAmountFilled.add(baseFilled);
1188
- this.getListForOrder(newAskOrder).update(
1394
+ this.getListForOrder(newAskOrder, slot).update(
1189
1395
  newAskOrder,
1190
1396
  askNode.userAccount
1191
1397
  );
@@ -1207,27 +1413,25 @@ export class DLOB {
1207
1413
  determineMakerAndTaker(
1208
1414
  askNode: DLOBNode,
1209
1415
  bidNode: DLOBNode
1210
- ): { takerNode: DLOBNode; makerNode: DLOBNode } {
1211
- if (bidNode.order.postOnly) {
1212
- return {
1213
- takerNode: askNode,
1214
- makerNode: bidNode,
1215
- };
1216
- } else if (askNode.order.postOnly) {
1217
- return {
1218
- takerNode: bidNode,
1219
- makerNode: askNode,
1220
- };
1221
- } else if (askNode.order.slot.lt(bidNode.order.slot)) {
1416
+ ): { takerNode: DLOBNode; makerNode: DLOBNode } | undefined {
1417
+ const askSlot = askNode.order.slot.add(
1418
+ new BN(askNode.order.auctionDuration)
1419
+ );
1420
+ const bidSlot = bidNode.order.slot.add(
1421
+ new BN(bidNode.order.auctionDuration)
1422
+ );
1423
+ if (askSlot.lte(bidSlot) && !bidNode.order.postOnly) {
1222
1424
  return {
1223
1425
  takerNode: bidNode,
1224
1426
  makerNode: askNode,
1225
1427
  };
1226
- } else {
1428
+ } else if (bidSlot.lte(askSlot) && !askNode.order.postOnly) {
1227
1429
  return {
1228
1430
  takerNode: askNode,
1229
1431
  makerNode: bidNode,
1230
1432
  };
1433
+ } else {
1434
+ return undefined;
1231
1435
  }
1232
1436
  }
1233
1437
 
@@ -1288,11 +1492,9 @@ export class DLOB {
1288
1492
  if (triggerAboveList) {
1289
1493
  for (const node of triggerAboveList.getGenerator()) {
1290
1494
  if (oraclePrice.gt(node.order.triggerPrice)) {
1291
- if (isAuctionComplete(node.order, slot)) {
1292
- nodesToTrigger.push({
1293
- node: node,
1294
- });
1295
- }
1495
+ nodesToTrigger.push({
1496
+ node: node,
1497
+ });
1296
1498
  } else {
1297
1499
  break;
1298
1500
  }
@@ -1305,11 +1507,9 @@ export class DLOB {
1305
1507
  if (triggerBelowList) {
1306
1508
  for (const node of triggerBelowList.getGenerator()) {
1307
1509
  if (oraclePrice.lt(node.order.triggerPrice)) {
1308
- if (isAuctionComplete(node.order, slot)) {
1309
- nodesToTrigger.push({
1310
- node: node,
1311
- });
1312
- }
1510
+ nodesToTrigger.push({
1511
+ node: node,
1512
+ });
1313
1513
  } else {
1314
1514
  break;
1315
1515
  }
@@ -1438,8 +1638,10 @@ export class DLOB {
1438
1638
 
1439
1639
  *getNodeLists(): Generator<NodeList<DLOBNodeType>> {
1440
1640
  for (const [_, nodeLists] of this.orderLists.get('perp')) {
1441
- yield nodeLists.limit.bid;
1442
- yield nodeLists.limit.ask;
1641
+ yield nodeLists.restingLimit.bid;
1642
+ yield nodeLists.restingLimit.ask;
1643
+ yield nodeLists.takingLimit.bid;
1644
+ yield nodeLists.takingLimit.ask;
1443
1645
  yield nodeLists.market.bid;
1444
1646
  yield nodeLists.market.ask;
1445
1647
  yield nodeLists.floatingLimit.bid;
@@ -1449,8 +1651,10 @@ export class DLOB {
1449
1651
  }
1450
1652
 
1451
1653
  for (const [_, nodeLists] of this.orderLists.get('spot')) {
1452
- yield nodeLists.limit.bid;
1453
- yield nodeLists.limit.ask;
1654
+ yield nodeLists.restingLimit.bid;
1655
+ yield nodeLists.restingLimit.ask;
1656
+ yield nodeLists.takingLimit.bid;
1657
+ yield nodeLists.takingLimit.ask;
1454
1658
  yield nodeLists.market.bid;
1455
1659
  yield nodeLists.market.ask;
1456
1660
  yield nodeLists.floatingLimit.bid;