@drift-labs/sdk 2.43.0-beta.8 → 2.44.0-beta.0

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.
@@ -21,6 +21,7 @@ export class WebSocketProgramAccountSubscriber<T>
21
21
  onChange: (accountId: PublicKey, data: T, context: Context) => void;
22
22
  listenerId?: number;
23
23
  resubTimeoutMs?: number;
24
+ isUnsubscribing = false;
24
25
  timeoutId?: NodeJS.Timeout;
25
26
  options: { filters: MemcmpFilter[]; commitment?: Commitment };
26
27
 
@@ -48,7 +49,7 @@ export class WebSocketProgramAccountSubscriber<T>
48
49
  async subscribe(
49
50
  onChange: (accountId: PublicKey, data: T, context: Context) => void
50
51
  ): Promise<void> {
51
- if (this.listenerId) {
52
+ if (this.listenerId || this.isUnsubscribing) {
52
53
  return;
53
54
  }
54
55
 
@@ -81,6 +82,11 @@ export class WebSocketProgramAccountSubscriber<T>
81
82
  throw new Error('onChange callback function must be set');
82
83
  }
83
84
  this.timeoutId = setTimeout(async () => {
85
+ if (this.isUnsubscribing) {
86
+ // If we are in the process of unsubscribing, do not attempt to resubscribe
87
+ return;
88
+ }
89
+
84
90
  if (this.receivingData) {
85
91
  console.log(
86
92
  `No ws data from ${this.subscriptionName} in ${this.resubTimeoutMs}ms, resubscribing`
@@ -140,13 +146,20 @@ export class WebSocketProgramAccountSubscriber<T>
140
146
  }
141
147
 
142
148
  unsubscribe(): Promise<void> {
149
+ this.isUnsubscribing = true;
150
+ clearTimeout(this.timeoutId);
151
+ this.timeoutId = undefined;
152
+
143
153
  if (this.listenerId) {
144
- const promise =
145
- this.program.provider.connection.removeAccountChangeListener(
146
- this.listenerId
147
- );
148
- this.listenerId = undefined;
154
+ const promise = this.program.provider.connection
155
+ .removeAccountChangeListener(this.listenerId)
156
+ .then(() => {
157
+ this.listenerId = undefined;
158
+ this.isUnsubscribing = false;
159
+ });
149
160
  return promise;
161
+ } else {
162
+ this.isUnsubscribing = false;
150
163
  }
151
164
  }
152
165
  }
@@ -787,6 +787,20 @@ export class AdminClient extends DriftClient {
787
787
  );
788
788
  }
789
789
 
790
+ public async updateLiquidationMarginBufferRatio(
791
+ updateLiquidationMarginBufferRatio: number
792
+ ): Promise<TransactionSignature> {
793
+ return await this.program.rpc.updateLiquidationMarginBufferRatio(
794
+ updateLiquidationMarginBufferRatio,
795
+ {
796
+ accounts: {
797
+ admin: this.wallet.publicKey,
798
+ state: await this.getStatePublicKey(),
799
+ },
800
+ }
801
+ );
802
+ }
803
+
790
804
  public async updateOracleGuardRails(
791
805
  oracleGuardRails: OracleGuardRails
792
806
  ): Promise<TransactionSignature> {
@@ -184,6 +184,16 @@ export const DevnetPerpMarkets: PerpMarketConfig[] = [
184
184
  launchTs: 1698074659000,
185
185
  oracleSource: OracleSource.PYTH,
186
186
  },
187
+ {
188
+ fullName: 'Rollbit',
189
+ category: ['Exchange'],
190
+ symbol: 'RLB-PERP',
191
+ baseAssetSymbol: 'RLB',
192
+ marketIndex: 17,
193
+ oracle: new PublicKey('6BmJozusMugAySsfNfMFsU1YRWcGwyP3oycNX9Pv9oCz'),
194
+ launchTs: 11699265968000,
195
+ oracleSource: OracleSource.PYTH,
196
+ },
187
197
  ];
188
198
 
189
199
  export const MainnetPerpMarkets: PerpMarketConfig[] = [
@@ -357,6 +367,16 @@ export const MainnetPerpMarkets: PerpMarketConfig[] = [
357
367
  launchTs: 1698074659000,
358
368
  oracleSource: OracleSource.PYTH,
359
369
  },
370
+ {
371
+ fullName: 'Rollbit',
372
+ category: ['Exchange'],
373
+ symbol: 'RLB-PERP',
374
+ baseAssetSymbol: 'RLB',
375
+ marketIndex: 17,
376
+ oracle: new PublicKey('4BA3RcS4zE32WWgp49vvvre2t6nXY1W1kMyKZxeeuUey'),
377
+ launchTs: 11699265968000,
378
+ oracleSource: OracleSource.PYTH,
379
+ },
360
380
  ];
361
381
 
362
382
  export const PerpMarkets: { [key in DriftEnv]: PerpMarketConfig[] } = {
package/src/dlob/DLOB.ts CHANGED
@@ -2,9 +2,8 @@ import { getOrderSignature, getVammNodeGenerator, NodeList } from './NodeList';
2
2
  import {
3
3
  BASE_PRECISION,
4
4
  BN,
5
- calculateAskPrice,
6
- calculateBidPrice,
7
5
  convertToNumber,
6
+ decodeName,
8
7
  DLOBNode,
9
8
  DLOBNodeType,
10
9
  DriftClient,
@@ -1430,14 +1429,12 @@ export class DLOB {
1430
1429
 
1431
1430
  public getBestAsk(
1432
1431
  marketIndex: number,
1433
- fallbackAsk: BN | undefined,
1434
1432
  slot: number,
1435
1433
  marketType: MarketType,
1436
1434
  oraclePriceData: OraclePriceData
1437
1435
  ): BN {
1438
- return this.getAsks(
1436
+ return this.getRestingLimitAsks(
1439
1437
  marketIndex,
1440
- fallbackAsk,
1441
1438
  slot,
1442
1439
  marketType,
1443
1440
  oraclePriceData
@@ -1448,14 +1445,12 @@ export class DLOB {
1448
1445
 
1449
1446
  public getBestBid(
1450
1447
  marketIndex: number,
1451
- fallbackBid: BN | undefined,
1452
1448
  slot: number,
1453
1449
  marketType: MarketType,
1454
1450
  oraclePriceData: OraclePriceData
1455
1451
  ): BN {
1456
- return this.getBids(
1452
+ return this.getRestingLimitBids(
1457
1453
  marketIndex,
1458
- fallbackBid,
1459
1454
  slot,
1460
1455
  marketType,
1461
1456
  oraclePriceData
@@ -1464,6 +1459,108 @@ export class DLOB {
1464
1459
  .value.getPrice(oraclePriceData, slot);
1465
1460
  }
1466
1461
 
1462
+ public *getStopLosses(
1463
+ marketIndex: number,
1464
+ marketType: MarketType,
1465
+ direction: PositionDirection
1466
+ ): Generator<DLOBNode> {
1467
+ const marketTypeStr = getVariant(marketType) as MarketTypeStr;
1468
+ const marketNodeLists = this.orderLists.get(marketTypeStr).get(marketIndex);
1469
+
1470
+ if (isVariant(direction, 'long') && marketNodeLists.trigger.below) {
1471
+ for (const node of marketNodeLists.trigger.below.getGenerator()) {
1472
+ if (isVariant(node.order.direction, 'short')) {
1473
+ yield node;
1474
+ }
1475
+ }
1476
+ } else if (isVariant(direction, 'short') && marketNodeLists.trigger.above) {
1477
+ for (const node of marketNodeLists.trigger.above.getGenerator()) {
1478
+ if (isVariant(node.order.direction, 'long')) {
1479
+ yield node;
1480
+ }
1481
+ }
1482
+ }
1483
+ }
1484
+
1485
+ public *getStopLossMarkets(
1486
+ marketIndex: number,
1487
+ marketType: MarketType,
1488
+ direction: PositionDirection
1489
+ ): Generator<DLOBNode> {
1490
+ for (const node of this.getStopLosses(marketIndex, marketType, direction)) {
1491
+ if (isVariant(node.order.orderType, 'triggerMarket')) {
1492
+ yield node;
1493
+ }
1494
+ }
1495
+ }
1496
+
1497
+ public *getStopLossLimits(
1498
+ marketIndex: number,
1499
+ marketType: MarketType,
1500
+ direction: PositionDirection
1501
+ ): Generator<DLOBNode> {
1502
+ for (const node of this.getStopLosses(marketIndex, marketType, direction)) {
1503
+ if (isVariant(node.order.orderType, 'triggerLimit')) {
1504
+ yield node;
1505
+ }
1506
+ }
1507
+ }
1508
+
1509
+ public *getTakeProfits(
1510
+ marketIndex: number,
1511
+ marketType: MarketType,
1512
+ direction: PositionDirection
1513
+ ): Generator<DLOBNode> {
1514
+ const marketTypeStr = getVariant(marketType) as MarketTypeStr;
1515
+ const marketNodeLists = this.orderLists.get(marketTypeStr).get(marketIndex);
1516
+
1517
+ if (isVariant(direction, 'long') && marketNodeLists.trigger.above) {
1518
+ for (const node of marketNodeLists.trigger.above.getGenerator()) {
1519
+ if (isVariant(node.order.direction, 'short')) {
1520
+ yield node;
1521
+ }
1522
+ }
1523
+ } else if (isVariant(direction, 'short') && marketNodeLists.trigger.below) {
1524
+ for (const node of marketNodeLists.trigger.below.getGenerator()) {
1525
+ if (isVariant(node.order.direction, 'long')) {
1526
+ yield node;
1527
+ }
1528
+ }
1529
+ }
1530
+ }
1531
+
1532
+ public *getTakeProfitMarkets(
1533
+ marketIndex: number,
1534
+ marketType: MarketType,
1535
+ direction: PositionDirection
1536
+ ): Generator<DLOBNode> {
1537
+ for (const node of this.getTakeProfits(
1538
+ marketIndex,
1539
+ marketType,
1540
+ direction
1541
+ )) {
1542
+ if (isVariant(node.order.orderType, 'triggerMarket')) {
1543
+ yield node;
1544
+ }
1545
+ }
1546
+ }
1547
+
1548
+ public *getTakeProfitLimits(
1549
+ marketIndex: number,
1550
+ marketType: MarketType,
1551
+ direction: PositionDirection
1552
+ ): Generator<DLOBNode> {
1553
+ for (const node of this.getTakeProfits(
1554
+ marketIndex,
1555
+ marketType,
1556
+ direction
1557
+ )) {
1558
+ if (isVariant(node.order.orderType, 'triggerLimit')) {
1559
+ yield node;
1560
+ }
1561
+ }
1562
+ }
1563
+
1467
1564
  public findNodesToTrigger(
1468
1565
  marketIndex: number,
1469
1566
  slot: number,
@@ -1512,32 +1609,25 @@ export class DLOB {
1512
1609
  return nodesToTrigger;
1513
1610
  }
1514
1611
 
1515
- public printTopOfOrderLists(
1516
- sdkConfig: any,
1612
+ public printTop(
1517
1613
  driftClient: DriftClient,
1518
1614
  slotSubscriber: SlotSubscriber,
1519
1615
  marketIndex: number,
1520
1616
  marketType: MarketType
1521
1617
  ) {
1522
1618
  if (isVariant(marketType, 'perp')) {
1523
- const market = driftClient.getPerpMarketAccount(marketIndex);
1524
-
1525
1619
  const slot = slotSubscriber.getSlot();
1526
1620
  const oraclePriceData =
1527
1621
  driftClient.getOracleDataForPerpMarket(marketIndex);
1528
- const fallbackAsk = calculateAskPrice(market, oraclePriceData);
1529
- const fallbackBid = calculateBidPrice(market, oraclePriceData);
1530
1622
 
1531
1623
  const bestAsk = this.getBestAsk(
1532
1624
  marketIndex,
1533
- fallbackAsk,
1534
1625
  slot,
1535
1626
  marketType,
1536
1627
  oraclePriceData
1537
1628
  );
1538
1629
  const bestBid = this.getBestBid(
1539
1630
  marketIndex,
1540
- fallbackBid,
1541
1631
  slot,
1542
1632
  marketType,
1543
1633
  oraclePriceData
@@ -1555,7 +1645,10 @@ export class DLOB {
1555
1645
  1) *
1556
1646
  100.0;
1557
1647
 
1558
- console.log(`Market ${sdkConfig.MARKETS[marketIndex].symbol} Orders`);
1648
+ const name = decodeName(
1649
+ driftClient.getPerpMarketAccount(marketIndex).name
1650
+ );
1651
+ console.log(`Market ${name} Orders`);
1559
1652
  console.log(
1560
1653
  ` Ask`,
1561
1654
  convertToNumber(bestAsk, PRICE_PRECISION).toFixed(3),
@@ -1574,14 +1667,12 @@ export class DLOB {
1574
1667
 
1575
1668
  const bestAsk = this.getBestAsk(
1576
1669
  marketIndex,
1577
- undefined,
1578
1670
  slot,
1579
1671
  marketType,
1580
1672
  oraclePriceData
1581
1673
  );
1582
1674
  const bestBid = this.getBestBid(
1583
1675
  marketIndex,
1584
- undefined,
1585
1676
  slot,
1586
1677
  marketType,
1587
1678
  oraclePriceData
@@ -1599,7 +1690,10 @@ export class DLOB {
1599
1690
  1) *
1600
1691
  100.0;
1601
1692
 
1602
- console.log(`Market ${sdkConfig.MARKETS[marketIndex].symbol} Orders`);
1693
+ const name = decodeName(
1694
+ driftClient.getSpotMarketAccount(marketIndex).name
1695
+ );
1696
+ console.log(`Market ${name} Orders`);
1603
1697
  console.log(
1604
1698
  ` Ask`,
1605
1699
  convertToNumber(bestAsk, PRICE_PRECISION).toFixed(3),
@@ -365,6 +365,7 @@ export function groupL2(
365
365
  return {
366
366
  bids: groupL2Levels(l2.bids, grouping, PositionDirection.LONG, depth),
367
367
  asks: groupL2Levels(l2.asks, grouping, PositionDirection.SHORT, depth),
368
+ slot: l2.slot,
368
369
  };
369
370
  }
370
371