@drift-labs/sdk 2.43.0-beta.0 → 2.43.0-beta.10

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/README.md CHANGED
@@ -244,3 +244,4 @@ Drift Protocol v2 is licensed under [Apache 2.0](./LICENSE).
244
244
  Unless you explicitly state otherwise, any contribution intentionally submitted
245
245
  for inclusion in Drift SDK by you, as defined in the Apache-2.0 license, shall be
246
246
  licensed as above, without any additional terms or conditions.
247
+
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.43.0-beta.0
1
+ 2.43.0-beta.10
package/bun.lockb CHANGED
Binary file
package/get_events.ts ADDED
@@ -0,0 +1,47 @@
1
+ import { Connection, Keypair, PublicKey } from '@solana/web3.js';
2
+ import {
3
+ configs,
4
+ DriftClient,
5
+ Wallet,
6
+ } from "@drift-labs/sdk";
7
+
8
+
9
+ async function main() {
10
+
11
+ const driftConfig = configs['mainnet-beta'];
12
+ const connection = new Connection('https://api.mainnet-beta.solana.com');
13
+
14
+ const driftClient = new DriftClient({
15
+ connection: connection,
16
+ wallet: new Wallet(new Keypair()),
17
+ programID: new PublicKey(driftConfig.DRIFT_PROGRAM_ID),
18
+ userStats: true,
19
+ env: 'mainnet-beta',
20
+ });
21
+ console.log(`driftClientSubscribed: ${await driftClient.subscribe()}`);
22
+
23
+ const txHash = "3gvGQufckXGHrFDv4dNWEXuXKRMy3NZkKHMyFrAhLoYScaXXTGCp9vq58kWkfyJ8oDYZrz4bTyGayjUy9PKigeLS";
24
+
25
+ const tx = await driftClient.connection.getParsedTransaction(txHash, {
26
+ commitment: "confirmed",
27
+ maxSupportedTransactionVersion: 0,
28
+ });
29
+
30
+ let logIdx = 0;
31
+ // @ts-ignore
32
+ for (const event of driftClient.program._events._eventParser.parseLogs(tx!.meta!.logMessages)) {
33
+ console.log("----------------------------------------");
34
+ console.log(`Log ${logIdx++}`);
35
+ console.log("----------------------------------------");
36
+ console.log(`${JSON.stringify(event, null, 2)}`);
37
+ }
38
+
39
+ console.log("========================================");
40
+ console.log("Raw transaction logs");
41
+ console.log("========================================");
42
+ console.log(JSON.stringify(tx!.meta!.logMessages, null, 2));
43
+
44
+ process.exit(0);
45
+ }
46
+
47
+ main().catch(console.error);
@@ -174,6 +174,16 @@ exports.DevnetPerpMarkets = [
174
174
  launchTs: 1698074659000,
175
175
  oracleSource: __1.OracleSource.PYTH,
176
176
  },
177
+ {
178
+ fullName: 'Rollbit',
179
+ category: ['Exchange'],
180
+ symbol: 'RLB-PERP',
181
+ baseAssetSymbol: 'RLB',
182
+ marketIndex: 17,
183
+ oracle: new web3_js_1.PublicKey('6BmJozusMugAySsfNfMFsU1YRWcGwyP3oycNX9Pv9oCz'),
184
+ launchTs: 11699265968000,
185
+ oracleSource: __1.OracleSource.PYTH,
186
+ },
177
187
  ];
178
188
  exports.MainnetPerpMarkets = [
179
189
  {
@@ -346,6 +356,16 @@ exports.MainnetPerpMarkets = [
346
356
  launchTs: 1698074659000,
347
357
  oracleSource: __1.OracleSource.PYTH,
348
358
  },
359
+ {
360
+ fullName: 'Rollbit',
361
+ category: ['Exchange'],
362
+ symbol: 'RLB-PERP',
363
+ baseAssetSymbol: 'RLB',
364
+ marketIndex: 17,
365
+ oracle: new web3_js_1.PublicKey('4BA3RcS4zE32WWgp49vvvre2t6nXY1W1kMyKZxeeuUey'),
366
+ launchTs: 11699265968000,
367
+ oracleSource: __1.OracleSource.PYTH,
368
+ },
349
369
  ];
350
370
  exports.PerpMarkets = {
351
371
  devnet: exports.DevnetPerpMarkets,
@@ -107,7 +107,7 @@ exports.MainnetSpotMarkets = [
107
107
  mint: new web3_js_1.PublicKey('J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn'),
108
108
  precision: new __1.BN(10).pow(numericConstants_1.NINE),
109
109
  precisionExp: numericConstants_1.NINE,
110
- serumMarket: new web3_js_1.PublicKey('JAmhJbmBzLp2aTp9mNJodPsTcpCJsmq5jpr6CuCbWHvR'),
110
+ serumMarket: new web3_js_1.PublicKey('DkbVbMhFxswS32xnn1K2UY4aoBugXooBTxdzkWWDWRkH'),
111
111
  },
112
112
  ];
113
113
  exports.SpotMarkets = {
package/lib/dlob/DLOB.js CHANGED
@@ -600,7 +600,7 @@ class DLOB {
600
600
  bestGenerator.next = bestGenerator.generator.next();
601
601
  continue;
602
602
  }
603
- if (filterFcn && filterFcn(bestGenerator.next.value)) {
603
+ if (filterFcn && !filterFcn(bestGenerator.next.value)) {
604
604
  bestGenerator.next = bestGenerator.generator.next();
605
605
  continue;
606
606
  }
@@ -956,6 +956,7 @@ class DLOB {
956
956
  return {
957
957
  bids,
958
958
  asks,
959
+ slot,
959
960
  };
960
961
  }
961
962
  /**
@@ -990,6 +991,7 @@ class DLOB {
990
991
  return {
991
992
  bids,
992
993
  asks,
994
+ slot,
993
995
  };
994
996
  }
995
997
  estimateFillExactBaseAmountInForSide(baseAmountIn, oraclePriceData, slot, dlobSide) {
@@ -12,6 +12,7 @@ export type L2Level = {
12
12
  export type L2OrderBook = {
13
13
  asks: L2Level[];
14
14
  bids: L2Level[];
15
+ slot?: number;
15
16
  };
16
17
  export interface L2OrderBookGenerator {
17
18
  getL2Asks(): Generator<L2Level>;
@@ -26,6 +27,7 @@ export type L3Level = {
26
27
  export type L3OrderBook = {
27
28
  asks: L3Level[];
28
29
  bids: L3Level[];
30
+ slot?: number;
29
31
  };
30
32
  export declare const DEFAULT_TOP_OF_BOOK_QUOTE_AMOUNTS: BN[];
31
33
  /**
@@ -92,7 +92,14 @@ function getVammL2Generator({ marketAccount, oraclePriceData, numOrders, now, to
92
92
  (0, assert_1.assert)(topOfBookQuoteAmounts.length < numOrders);
93
93
  }
94
94
  const updatedAmm = (0, __1.calculateUpdatedAMM)(marketAccount.amm, oraclePriceData);
95
- const [openBids, openAsks] = (0, __1.calculateMarketOpenBidAsk)(updatedAmm.baseAssetReserve, updatedAmm.minBaseAssetReserve, updatedAmm.maxBaseAssetReserve, updatedAmm.orderStepSize);
95
+ let [openBids, openAsks] = (0, __1.calculateMarketOpenBidAsk)(updatedAmm.baseAssetReserve, updatedAmm.minBaseAssetReserve, updatedAmm.maxBaseAssetReserve, updatedAmm.orderStepSize);
96
+ const minOrderSize = marketAccount.amm.orderStepSize;
97
+ if (openBids.lt(minOrderSize.muln(2))) {
98
+ openBids = __1.ZERO;
99
+ }
100
+ if (openAsks.abs().lt(minOrderSize.muln(2))) {
101
+ openAsks = __1.ZERO;
102
+ }
96
103
  now = now !== null && now !== void 0 ? now : new __1.BN(Date.now() / 1000);
97
104
  const [bidReserves, askReserves] = (0, __1.calculateSpreadReserves)(updatedAmm, oraclePriceData, now);
98
105
  let numBids = 0;
@@ -202,6 +209,7 @@ function groupL2(l2, grouping, depth) {
202
209
  return {
203
210
  bids: groupL2Levels(l2.bids, grouping, __1.PositionDirection.LONG, depth),
204
211
  asks: groupL2Levels(l2.asks, grouping, __1.PositionDirection.SHORT, depth),
212
+ slot: l2.slot,
205
213
  };
206
214
  }
207
215
  exports.groupL2 = groupL2;
package/lib/user.js CHANGED
@@ -1564,7 +1564,10 @@ class User {
1564
1564
  this.getEmptyPosition(targetMarketIndex);
1565
1565
  const oracleData = this.getOracleDataForPerpMarket(targetMarketIndex);
1566
1566
  let currentPositionQuoteAmount = this.getPerpPositionValue(targetMarketIndex, oracleData, includeOpenOrders);
1567
- const currentSide = currentPosition && currentPosition.baseAssetAmount.isNeg()
1567
+ const worstCaseBase = (0, margin_1.calculateWorstCaseBaseAssetAmount)(currentPosition);
1568
+ // current side is short if position base asset amount is negative OR there is no position open but open orders are short
1569
+ const currentSide = currentPosition.baseAssetAmount.isNeg() ||
1570
+ (currentPosition.baseAssetAmount.eq(numericConstants_1.ZERO) && worstCaseBase.isNeg())
1568
1571
  ? _1.PositionDirection.SHORT
1569
1572
  : _1.PositionDirection.LONG;
1570
1573
  if (currentSide === _1.PositionDirection.SHORT)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.43.0-beta.0",
3
+ "version": "2.43.0-beta.10",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -52,6 +52,7 @@
52
52
  "@typescript-eslint/eslint-plugin": "^4.28.0",
53
53
  "@typescript-eslint/parser": "^4.28.0",
54
54
  "chai": "^4.3.6",
55
+ "encoding": "^0.1.13",
55
56
  "eslint": "^7.29.0",
56
57
  "eslint-config-prettier": "^8.3.0",
57
58
  "eslint-plugin-prettier": "^3.4.0",
@@ -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[] } = {
@@ -135,7 +135,7 @@ export const MainnetSpotMarkets: SpotMarketConfig[] = [
135
135
  mint: new PublicKey('J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn'),
136
136
  precision: new BN(10).pow(NINE),
137
137
  precisionExp: NINE,
138
- serumMarket: new PublicKey('JAmhJbmBzLp2aTp9mNJodPsTcpCJsmq5jpr6CuCbWHvR'),
138
+ serumMarket: new PublicKey('DkbVbMhFxswS32xnn1K2UY4aoBugXooBTxdzkWWDWRkH'),
139
139
  },
140
140
  ];
141
141
 
package/src/dlob/DLOB.ts CHANGED
@@ -1111,7 +1111,7 @@ export class DLOB {
1111
1111
  continue;
1112
1112
  }
1113
1113
 
1114
- if (filterFcn && filterFcn(bestGenerator.next.value)) {
1114
+ if (filterFcn && !filterFcn(bestGenerator.next.value)) {
1115
1115
  bestGenerator.next = bestGenerator.generator.next();
1116
1116
  continue;
1117
1117
  }
@@ -1725,6 +1725,7 @@ export class DLOB {
1725
1725
  return {
1726
1726
  bids,
1727
1727
  asks,
1728
+ slot,
1728
1729
  };
1729
1730
  }
1730
1731
 
@@ -1785,6 +1786,7 @@ export class DLOB {
1785
1786
  return {
1786
1787
  bids,
1787
1788
  asks,
1789
+ slot,
1788
1790
  };
1789
1791
  }
1790
1792
 
@@ -29,6 +29,7 @@ export type L2Level = {
29
29
  export type L2OrderBook = {
30
30
  asks: L2Level[];
31
31
  bids: L2Level[];
32
+ slot?: number;
32
33
  };
33
34
 
34
35
  export interface L2OrderBookGenerator {
@@ -46,6 +47,7 @@ export type L3Level = {
46
47
  export type L3OrderBook = {
47
48
  asks: L3Level[];
48
49
  bids: L3Level[];
50
+ slot?: number;
49
51
  };
50
52
 
51
53
  export const DEFAULT_TOP_OF_BOOK_QUOTE_AMOUNTS = [
@@ -164,13 +166,22 @@ export function getVammL2Generator({
164
166
 
165
167
  const updatedAmm = calculateUpdatedAMM(marketAccount.amm, oraclePriceData);
166
168
 
167
- const [openBids, openAsks] = calculateMarketOpenBidAsk(
169
+ let [openBids, openAsks] = calculateMarketOpenBidAsk(
168
170
  updatedAmm.baseAssetReserve,
169
171
  updatedAmm.minBaseAssetReserve,
170
172
  updatedAmm.maxBaseAssetReserve,
171
173
  updatedAmm.orderStepSize
172
174
  );
173
175
 
176
+ const minOrderSize = marketAccount.amm.orderStepSize;
177
+ if (openBids.lt(minOrderSize.muln(2))) {
178
+ openBids = ZERO;
179
+ }
180
+
181
+ if (openAsks.abs().lt(minOrderSize.muln(2))) {
182
+ openAsks = ZERO;
183
+ }
184
+
174
185
  now = now ?? new BN(Date.now() / 1000);
175
186
  const [bidReserves, askReserves] = calculateSpreadReserves(
176
187
  updatedAmm,
@@ -354,6 +365,7 @@ export function groupL2(
354
365
  return {
355
366
  bids: groupL2Levels(l2.bids, grouping, PositionDirection.LONG, depth),
356
367
  asks: groupL2Levels(l2.asks, grouping, PositionDirection.SHORT, depth),
368
+ slot: l2.slot,
357
369
  };
358
370
  }
359
371
 
package/src/user.ts CHANGED
@@ -2884,8 +2884,12 @@ export class User {
2884
2884
  includeOpenOrders
2885
2885
  );
2886
2886
 
2887
+ const worstCaseBase = calculateWorstCaseBaseAssetAmount(currentPosition);
2888
+
2889
+ // current side is short if position base asset amount is negative OR there is no position open but open orders are short
2887
2890
  const currentSide =
2888
- currentPosition && currentPosition.baseAssetAmount.isNeg()
2891
+ currentPosition.baseAssetAmount.isNeg() ||
2892
+ (currentPosition.baseAssetAmount.eq(ZERO) && worstCaseBase.isNeg())
2889
2893
  ? PositionDirection.SHORT
2890
2894
  : PositionDirection.LONG;
2891
2895
 
package/tests/amm/test.ts CHANGED
@@ -956,4 +956,82 @@ describe('AMM Tests', () => {
956
956
  );
957
957
  assert(totalAskSize.sub(openAsks.abs()).lte(new BN(5))); // only tiny rounding errors
958
958
  });
959
+
960
+ it('orderbook L2 gen (no topOfBookQuoteAmounts, 10 numOrders, no liquidity)', async () => {
961
+ const myMockPerpMarkets = _.cloneDeep(mockPerpMarkets);
962
+
963
+ const mockMarket1: PerpMarketAccount = myMockPerpMarkets[0];
964
+ const cc = 38104569;
965
+ mockMarket1.amm.baseAssetReserve = new BN(cc).mul(BASE_PRECISION);
966
+ mockMarket1.amm.minOrderSize = new BN(5);
967
+ mockMarket1.amm.maxBaseAssetReserve = mockMarket1.amm.baseAssetReserve.add(
968
+ new BN(9)
969
+ );
970
+ mockMarket1.amm.minBaseAssetReserve =
971
+ mockMarket1.amm.baseAssetReserve.sub(new BN(9));
972
+ mockMarket1.amm.quoteAssetReserve = new BN(cc).mul(BASE_PRECISION);
973
+ mockMarket1.amm.pegMultiplier = new BN(18.32 * PEG_PRECISION.toNumber());
974
+ mockMarket1.amm.sqrtK = new BN(cc).mul(BASE_PRECISION);
975
+
976
+ const now = new BN(1688881915);
977
+
978
+ const oraclePriceData: OraclePriceData = {
979
+ price: new BN(18.624 * PRICE_PRECISION.toNumber()),
980
+ slot: new BN(0),
981
+ confidence: new BN(1),
982
+ hasSufficientNumberOfDataPoints: true,
983
+ };
984
+ mockMarket1.amm.historicalOracleData.lastOraclePrice = new BN(
985
+ 18.5535 * PRICE_PRECISION.toNumber()
986
+ );
987
+
988
+ const updatedAmm = calculateUpdatedAMM(mockMarket1.amm, oraclePriceData);
989
+
990
+ const [openBids, openAsks] = calculateMarketOpenBidAsk(
991
+ updatedAmm.baseAssetReserve,
992
+ updatedAmm.minBaseAssetReserve,
993
+ updatedAmm.maxBaseAssetReserve,
994
+ updatedAmm.orderStepSize
995
+ );
996
+
997
+ const generator = getVammL2Generator({
998
+ marketAccount: mockMarket1,
999
+ oraclePriceData,
1000
+ numOrders: 10,
1001
+ now,
1002
+ topOfBookQuoteAmounts: [],
1003
+ });
1004
+
1005
+ const bids = Array.from(generator.getL2Bids());
1006
+ // console.log(bids);
1007
+
1008
+ const totalBidSize = bids.reduce((total: BN, order: L2Level) => {
1009
+ return total.add(order.size);
1010
+ }, ZERO);
1011
+
1012
+ console.log(
1013
+ 'totalBidSize:',
1014
+ totalBidSize.toString(),
1015
+ 'openBids:',
1016
+ openBids.toString()
1017
+ );
1018
+ assert(openBids.eq(new BN(9)));
1019
+ assert(totalBidSize.eq(ZERO));
1020
+
1021
+ const asks = Array.from(generator.getL2Asks());
1022
+ // console.log(asks);
1023
+
1024
+ const totalAskSize = asks.reduce((total: BN, order: L2Level) => {
1025
+ return total.add(order.size);
1026
+ }, ZERO);
1027
+ console.log(
1028
+ 'totalAskSize:',
1029
+ totalAskSize.toString(),
1030
+ 'openAsks:',
1031
+ openAsks.toString()
1032
+ );
1033
+
1034
+ assert(openAsks.eq(new BN(-9)));
1035
+ assert(totalAskSize.eq(ZERO));
1036
+ });
959
1037
  });
@@ -289,8 +289,9 @@ describe('User Tests', () => {
289
289
  mockUser.getMaxLeverageForPerp(0).toString()
290
290
  );
291
291
  assert(mockUser.getMaxLeverageForPerp(0).eq(new BN('50000'))); // 5x
292
- assert(mockUser.getMaxLeverageForPerp(0, 'Maintenance').eq(new BN('100000'))); // 10x
293
-
292
+ assert(
293
+ mockUser.getMaxLeverageForPerp(0, 'Maintenance').eq(new BN('100000'))
294
+ ); // 10x
294
295
  });
295
296
 
296
297
  it('worst case token amount', async () => {
@@ -399,8 +400,7 @@ describe('User Tests', () => {
399
400
  ); // -$2k
400
401
  });
401
402
 
402
-
403
- it('custom margin ratio (sol spot)', async() => {
403
+ it('custom margin ratio (sol spot)', async () => {
404
404
  const myMockUserAccount = _.cloneDeep(mockUserAccount);
405
405
 
406
406
  const solMarket = Object.assign({}, _.cloneDeep(mockSpotMarkets[1]), {
@@ -427,12 +427,10 @@ describe('User Tests', () => {
427
427
  );
428
428
 
429
429
  console.log(worstCase);
430
- assert(worstCase.weight.eq(new BN(8000)));
431
-
430
+ assert(worstCase.weight.eq(new BN(8000)));
432
431
 
433
432
  myMockUserAccount.maxMarginRatio = MARGIN_PRECISION.toNumber(); // max 1x pls
434
433
 
435
-
436
434
  const worstCaseAfter = getWorstCaseTokenAmounts(
437
435
  spotPosition,
438
436
  solMarket,
@@ -443,10 +441,9 @@ describe('User Tests', () => {
443
441
 
444
442
  console.log(worstCaseAfter);
445
443
  assert(worstCaseAfter.weight.eq(new BN(0))); // not allowed to increase exposure
446
-
447
444
  });
448
445
 
449
- it('custom margin ratio (sol perp)', async() => {
446
+ it('custom margin ratio (sol perp)', async () => {
450
447
  const myMockPerpMarkets = _.cloneDeep(mockPerpMarkets);
451
448
  const myMockSpotMarkets = _.cloneDeep(mockSpotMarkets);
452
449
  const myMockUserAccount = _.cloneDeep(mockUserAccount);
@@ -469,7 +466,6 @@ describe('User Tests', () => {
469
466
  [1, 1, 1, 1, 1, 1, 1, 1]
470
467
  );
471
468
 
472
-
473
469
  assert(mockUser.getTokenAmount(0).eq(new BN('10000000000')));
474
470
  assert(mockUser.getNetSpotMarketValue().eq(new BN('10000000000')));
475
471
  assert(
@@ -486,7 +482,9 @@ describe('User Tests', () => {
486
482
  assert(iLev == 5000);
487
483
  assert(mLev == 10000);
488
484
 
489
- myMockUserAccount.maxMarginRatio = MARGIN_PRECISION.div(new BN(2)).toNumber(); // 2x max pls
485
+ myMockUserAccount.maxMarginRatio = MARGIN_PRECISION.div(
486
+ new BN(2)
487
+ ).toNumber(); // 2x max pls
490
488
 
491
489
  const mockUser2: User = await makeMockUser(
492
490
  myMockPerpMarkets,
@@ -498,9 +496,8 @@ describe('User Tests', () => {
498
496
  iLev = mockUser2.getMaxLeverageForPerp(0, 'Initial').toNumber();
499
497
  mLev = mockUser2.getMaxLeverageForPerp(0, 'Maintenance').toNumber();
500
498
  console.log(iLev, mLev);
501
-
499
+
502
500
  assert(iLev == 2000);
503
501
  assert(mLev == 10000);
504
-
505
502
  });
506
503
  });