@drift-labs/sdk 2.52.0-beta.0 → 2.52.0-beta.2

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.
Files changed (60) hide show
  1. package/VERSION +1 -1
  2. package/lib/accounts/basicUserAccountSubscriber.d.ts +4 -0
  3. package/lib/accounts/basicUserAccountSubscriber.js +4 -0
  4. package/lib/accounts/bulkAccountLoader.js +7 -1
  5. package/lib/accounts/oneShotUserAccountSubscriber.d.ts +17 -0
  6. package/lib/accounts/oneShotUserAccountSubscriber.js +48 -0
  7. package/lib/accounts/pollingInsuranceFundStakeAccountSubscriber.js +1 -0
  8. package/lib/accounts/webSocketAccountSubscriber.d.ts +1 -1
  9. package/lib/accounts/webSocketAccountSubscriber.js +7 -4
  10. package/lib/accounts/webSocketProgramAccountSubscriber.d.ts +1 -1
  11. package/lib/accounts/webSocketProgramAccountSubscriber.js +7 -4
  12. package/lib/adminClient.d.ts +1 -0
  13. package/lib/adminClient.js +9 -0
  14. package/lib/constants/numericConstants.d.ts +3 -0
  15. package/lib/constants/numericConstants.js +4 -1
  16. package/lib/dlob/orderBookLevels.d.ts +22 -0
  17. package/lib/dlob/orderBookLevels.js +115 -1
  18. package/lib/driftClient.d.ts +1 -0
  19. package/lib/driftClient.js +14 -5
  20. package/lib/events/webSocketLogProvider.js +3 -3
  21. package/lib/factory/bigNum.d.ts +1 -1
  22. package/lib/factory/bigNum.js +5 -2
  23. package/lib/idl/drift.json +13 -1
  24. package/lib/index.d.ts +1 -0
  25. package/lib/index.js +1 -0
  26. package/lib/math/amm.d.ts +5 -1
  27. package/lib/math/amm.js +62 -13
  28. package/lib/phoenix/phoenixSubscriber.js +2 -2
  29. package/lib/slot/SlotSubscriber.d.ts +11 -3
  30. package/lib/slot/SlotSubscriber.js +40 -4
  31. package/lib/types.d.ts +1 -1
  32. package/lib/userMap/userMap.d.ts +3 -0
  33. package/lib/userMap/userMap.js +10 -1
  34. package/lib/userStats.d.ts +1 -0
  35. package/lib/userStats.js +3 -0
  36. package/package.json +1 -1
  37. package/src/accounts/basicUserAccountSubscriber.ts +4 -0
  38. package/src/accounts/bulkAccountLoader.ts +10 -3
  39. package/src/accounts/oneShotUserAccountSubscriber.ts +64 -0
  40. package/src/accounts/pollingInsuranceFundStakeAccountSubscriber.ts +1 -0
  41. package/src/accounts/webSocketAccountSubscriber.ts +7 -4
  42. package/src/accounts/webSocketProgramAccountSubscriber.ts +7 -4
  43. package/src/adminClient.ts +13 -0
  44. package/src/constants/numericConstants.ts +4 -0
  45. package/src/dlob/orderBookLevels.ts +136 -0
  46. package/src/driftClient.ts +21 -10
  47. package/src/events/webSocketLogProvider.ts +3 -3
  48. package/src/factory/bigNum.ts +11 -2
  49. package/src/idl/drift.json +13 -1
  50. package/src/index.ts +1 -0
  51. package/src/math/amm.ts +159 -25
  52. package/src/phoenix/phoenixSubscriber.ts +2 -2
  53. package/src/slot/SlotSubscriber.ts +52 -5
  54. package/src/types.ts +1 -1
  55. package/src/userMap/userMap.ts +17 -3
  56. package/src/userStats.ts +8 -0
  57. package/tests/amm/test.ts +219 -11
  58. package/tests/bn/test.ts +27 -0
  59. package/tests/dlob/helpers.ts +1 -1
  60. package/tests/dlob/test.ts +372 -2
@@ -13,7 +13,7 @@ import {
13
13
  LPRecord,
14
14
  StateAccount,
15
15
  DLOB,
16
- BasicUserAccountSubscriber,
16
+ OneShotUserAccountSubscriber,
17
17
  BN,
18
18
  } from '..';
19
19
 
@@ -60,6 +60,7 @@ export class UserMap implements UserMapInterface {
60
60
  }
61
61
  };
62
62
  private decode;
63
+ private mostRecentSlot = 0;
63
64
 
64
65
  private syncPromise?: Promise<void>;
65
66
  private syncPromiseResolver: () => void;
@@ -132,10 +133,12 @@ export class UserMap implements UserMapInterface {
132
133
  userAccountPublicKey,
133
134
  accountSubscription: {
134
135
  type: 'custom',
135
- userAccountSubscriber: new BasicUserAccountSubscriber(
136
+ userAccountSubscriber: new OneShotUserAccountSubscriber(
137
+ this.driftClient.program,
136
138
  userAccountPublicKey,
137
139
  userAccount,
138
- slot
140
+ slot,
141
+ this.commitment
139
142
  ),
140
143
  },
141
144
  });
@@ -310,6 +313,8 @@ export class UserMap implements UserMapInterface {
310
313
 
311
314
  const slot = rpcResponseAndContext.context.slot;
312
315
 
316
+ this.updateLatestSlot(slot);
317
+
313
318
  const programAccountBufferMap = new Map<string, Buffer>();
314
319
  for (const programAccount of rpcResponseAndContext.value) {
315
320
  programAccountBufferMap.set(
@@ -371,6 +376,7 @@ export class UserMap implements UserMapInterface {
371
376
  userAccount: UserAccount,
372
377
  slot: number
373
378
  ) {
379
+ this.updateLatestSlot(slot);
374
380
  if (!this.userMap.has(key)) {
375
381
  this.addPubkey(new PublicKey(key), userAccount, slot);
376
382
  } else {
@@ -378,4 +384,12 @@ export class UserMap implements UserMapInterface {
378
384
  user.accountSubscriber.updateData(userAccount, slot);
379
385
  }
380
386
  }
387
+
388
+ updateLatestSlot(slot: number): void {
389
+ this.mostRecentSlot = Math.max(slot, this.mostRecentSlot);
390
+ }
391
+
392
+ public getSlot(): number {
393
+ return this.mostRecentSlot;
394
+ }
381
395
  }
package/src/userStats.ts CHANGED
@@ -82,4 +82,12 @@ export class UserStats {
82
82
  };
83
83
  }
84
84
  }
85
+
86
+ public static getOldestActionTs(account: UserStatsAccount): number {
87
+ return Math.min(
88
+ account.lastFillerVolume30DTs.toNumber(),
89
+ account.lastMakerVolume30DTs.toNumber(),
90
+ account.lastTakerVolume30DTs.toNumber()
91
+ );
92
+ }
85
93
  }
package/tests/amm/test.ts CHANGED
@@ -4,6 +4,8 @@ import {
4
4
  PRICE_PRECISION,
5
5
  AMM_RESERVE_PRECISION,
6
6
  QUOTE_PRECISION,
7
+ PERCENTAGE_PRECISION,
8
+ calculateSpread,
7
9
  calculateSpreadBN,
8
10
  ZERO,
9
11
  ONE,
@@ -19,6 +21,12 @@ import {
19
21
  L2Level,
20
22
  calculateUpdatedAMM,
21
23
  calculateMarketOpenBidAsk,
24
+ calculateSpreadReserves,
25
+ calculatePrice,
26
+ BID_ASK_SPREAD_PRECISION,
27
+ squareRootBN,
28
+ calculateReferencePriceOffset,
29
+ calculateInventoryLiquidityRatio,
22
30
  } from '../../src';
23
31
  import { mockPerpMarkets } from '../dlob/helpers';
24
32
 
@@ -293,7 +301,7 @@ describe('AMM Tests', () => {
293
301
  volume24H,
294
302
  true
295
303
  );
296
- console.log(terms1);
304
+ // console.log(terms1);
297
305
 
298
306
  console.log('long/short spread:', l1, s1);
299
307
  assert(l1 == 14864);
@@ -326,11 +334,77 @@ describe('AMM Tests', () => {
326
334
  true
327
335
  );
328
336
 
329
- console.log(terms2);
337
+ // console.log(terms2);
330
338
  assert(terms2.effectiveLeverageCapped >= 1.0002);
331
339
  assert(terms2.inventorySpreadScale == 1.73492);
332
340
  assert(terms2.longSpread == 4262);
333
341
  assert(terms2.shortSpread == 43238);
342
+
343
+ // add spread offset
344
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
345
+ // @ts-ignore
346
+ const terms3: AMMSpreadTerms = calculateSpreadBN(
347
+ 300,
348
+ new BN(0),
349
+ new BN(484),
350
+ 47500,
351
+ new BN(923807816209694),
352
+ new BN(925117623772584),
353
+ new BN(13731157),
354
+ new BN(-1314027016625),
355
+ new BN(13667686),
356
+ new BN(115876379475),
357
+ new BN(91316628),
358
+ new BN(928097825691666),
359
+ new BN(907979542352912),
360
+ new BN(945977491145601),
361
+ new BN(161188),
362
+ new BN(1459632439),
363
+ new BN(12358265776),
364
+ new BN(72230366233),
365
+ new BN(432067603632),
366
+ true
367
+ );
368
+
369
+ console.log(terms3);
370
+ assert(terms3.effectiveLeverageCapped >= 1.0002);
371
+ assert(terms3.inventorySpreadScale == 1.73492);
372
+ assert(terms3.longSpread == 4262);
373
+ assert(terms3.shortSpread == 43238);
374
+ assert(terms3.longSpread + terms3.shortSpread == 47500);
375
+
376
+ // add spread offset
377
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
378
+ // @ts-ignore
379
+ const terms4: AMMSpreadTerms = calculateSpreadBN(
380
+ 300,
381
+ new BN(0),
382
+ new BN(484),
383
+ 47500,
384
+ new BN(923807816209694),
385
+ new BN(925117623772584),
386
+ new BN(13731157),
387
+ new BN(-1314027016625),
388
+ new BN(13667686),
389
+ new BN(115876379475),
390
+ new BN(91316628),
391
+ new BN(928097825691666),
392
+ new BN(907979542352912),
393
+ new BN(945977491145601),
394
+ new BN(161188),
395
+ new BN(1459632439),
396
+ new BN(12358265776),
397
+ new BN(72230366233),
398
+ new BN(432067603632),
399
+ true
400
+ );
401
+
402
+ console.log(terms4);
403
+ assert(terms4.effectiveLeverageCapped >= 1.0002);
404
+ assert(terms4.inventorySpreadScale == 1.73492);
405
+ assert(terms4.longSpread == 4262);
406
+ assert(terms4.shortSpread == 43238);
407
+ assert(terms4.longSpread + terms4.shortSpread == 47500);
334
408
  });
335
409
 
336
410
  it('Corner Case Spreads', () => {
@@ -361,16 +435,150 @@ describe('AMM Tests', () => {
361
435
 
362
436
  console.log(terms2);
363
437
  assert(terms2.effectiveLeverageCapped <= 1.000001);
364
- assert(
365
- terms2.inventorySpreadScale == 1.013527,
366
- `got: ${terms2.inventorySpreadScale}`
438
+ assert(terms2.inventorySpreadScale == 1.0306);
439
+ assert(terms2.longSpread == 515);
440
+ assert(terms2.shortSpread == 5668);
441
+ });
442
+
443
+ it('Spread Reserves (with offset)', () => {
444
+ const myMockPerpMarkets = _.cloneDeep(mockPerpMarkets);
445
+ const mockMarket1 = myMockPerpMarkets[0];
446
+ const mockAmm = mockMarket1.amm;
447
+ const now = new BN(new Date().getTime() / 1000); //todo
448
+
449
+ const oraclePriceData = {
450
+ price: new BN(13.553 * PRICE_PRECISION.toNumber()),
451
+ slot: new BN(68 + 1),
452
+ confidence: new BN(1),
453
+ hasSufficientNumberOfDataPoints: true,
454
+ };
455
+
456
+ const reserves = calculateSpreadReserves(mockAmm, oraclePriceData, now);
457
+ assert(reserves[0].baseAssetReserve.eq(new BN('1000000000')));
458
+ assert(reserves[0].quoteAssetReserve.eq(new BN('12000000000')));
459
+ assert(reserves[1].baseAssetReserve.eq(new BN('1000000000')));
460
+ assert(reserves[1].quoteAssetReserve.eq(new BN('12000000000')));
461
+
462
+ mockAmm.baseAssetReserve = new BN(1000000000);
463
+ mockAmm.quoteAssetReserve = new BN(1000000000);
464
+ mockAmm.sqrtK = new BN(1000000000);
465
+
466
+ mockAmm.baseAssetAmountWithAmm = new BN(0);
467
+ mockAmm.pegMultiplier = new BN(13.553 * PEG_PRECISION.toNumber());
468
+ mockAmm.ammJitIntensity = 100;
469
+ mockAmm.curveUpdateIntensity = 200;
470
+ mockAmm.baseSpread = 2500;
471
+ mockAmm.maxSpread = 25000;
472
+
473
+ mockAmm.last24HAvgFundingRate = new BN(7590328523);
474
+
475
+ mockAmm.lastMarkPriceTwap = new BN(
476
+ (oraclePriceData.price.toNumber() / 1e6 - 0.01) * 1e6
477
+ );
478
+ mockAmm.historicalOracleData.lastOraclePriceTwap = new BN(
479
+ (oraclePriceData.price.toNumber() / 1e6 + 0.015) * 1e6
367
480
  );
368
- assert(terms2.longSpread == 1146);
369
- assert(terms2.shortSpread == 6686);
481
+
482
+ mockAmm.historicalOracleData.lastOraclePriceTwap5Min = new BN(
483
+ (oraclePriceData.price.toNumber() / 1e6 + 0.005) * 1e6
484
+ );
485
+ mockAmm.lastMarkPriceTwap5Min = new BN(
486
+ (oraclePriceData.price.toNumber() / 1e6 - 0.005) * 1e6
487
+ );
488
+
489
+ console.log('starting rr:');
490
+ let reservePrice = undefined;
491
+ if (!reservePrice) {
492
+ reservePrice = calculatePrice(
493
+ mockAmm.baseAssetReserve,
494
+ mockAmm.quoteAssetReserve,
495
+ mockAmm.pegMultiplier
496
+ );
497
+ }
498
+
499
+ const targetPrice = oraclePriceData?.price || reservePrice;
500
+ const confInterval = oraclePriceData.confidence || ZERO;
501
+ const targetMarkSpreadPct = reservePrice
502
+ .sub(targetPrice)
503
+ .mul(BID_ASK_SPREAD_PRECISION)
504
+ .div(reservePrice);
505
+
506
+ const confIntervalPct = confInterval
507
+ .mul(BID_ASK_SPREAD_PRECISION)
508
+ .div(reservePrice);
509
+
510
+ // now = now || new BN(new Date().getTime() / 1000); //todo
511
+ const liveOracleStd = calculateLiveOracleStd(mockAmm, oraclePriceData, now);
512
+ console.log('reservePrice:', reservePrice.toString());
513
+ console.log('targetMarkSpreadPct:', targetMarkSpreadPct.toString());
514
+ console.log('confIntervalPct:', confIntervalPct.toString());
515
+
516
+ console.log('liveOracleStd:', liveOracleStd.toString());
517
+
518
+ const tt = calculateSpread(mockAmm, oraclePriceData, now);
519
+ console.log(tt);
520
+
521
+ console.log('amm.baseAssetReserve:', mockAmm.baseAssetReserve.toString());
522
+ assert(mockAmm.baseAssetReserve.eq(new BN('1000000000')));
523
+ const reserves2 = calculateSpreadReserves(mockAmm, oraclePriceData, now);
524
+ console.log(reserves2[1].baseAssetReserve.toString());
525
+ console.log(reserves2[1].quoteAssetReserve.toString());
526
+
527
+ assert(reserves2[0].baseAssetReserve.eq(new BN('1006711408')));
528
+ assert(reserves2[0].quoteAssetReserve.eq(new BN('993333334')));
529
+ assert(reserves2[1].baseAssetReserve.eq(new BN('993377484')));
530
+ assert(reserves2[1].quoteAssetReserve.eq(new BN('1006666666')));
531
+
532
+ // create imbalance for reference price offset
533
+ mockAmm.baseAssetReserve = new BN(1000000000 * 1.1);
534
+ mockAmm.quoteAssetReserve = new BN(1000000000 / 1.1);
535
+ mockAmm.sqrtK = squareRootBN(
536
+ mockAmm.baseAssetReserve.mul(mockAmm.quoteAssetReserve)
537
+ );
538
+
539
+ mockAmm.baseAssetAmountWithAmm = new BN(-1000000000 * 0.1);
540
+
541
+ const maxOffset = Math.max(
542
+ mockAmm.maxSpread / 5,
543
+ PERCENTAGE_PRECISION.toNumber() / 1000
544
+ );
545
+ const liquidityFraction = calculateInventoryLiquidityRatio(
546
+ mockAmm.baseAssetAmountWithAmm,
547
+ mockAmm.baseAssetReserve,
548
+ mockAmm.minBaseAssetReserve,
549
+ mockAmm.maxBaseAssetReserve
550
+ );
551
+ console.log('liquidityFraction:', liquidityFraction.toString());
552
+ assert(liquidityFraction.eq(new BN(1000000))); // full
553
+
554
+ const referencePriceOffset = calculateReferencePriceOffset(
555
+ reservePrice,
556
+ mockAmm.last24HAvgFundingRate,
557
+ liquidityFraction,
558
+ mockAmm.historicalOracleData.lastOraclePriceTwap5Min,
559
+ mockAmm.lastMarkPriceTwap5Min,
560
+ mockAmm.historicalOracleData.lastOraclePriceTwap,
561
+ mockAmm.lastMarkPriceTwap,
562
+ maxOffset
563
+ );
564
+ console.log('referencePriceOffset:', referencePriceOffset.toString());
565
+ assert(referencePriceOffset.eq(new BN(5000)));
566
+ assert(referencePriceOffset.eq(new BN(maxOffset)));
567
+
568
+ const reserves3 = calculateSpreadReserves(mockAmm, oraclePriceData, now);
569
+ console.log(reserves3[1].baseAssetReserve.toString());
570
+ console.log(reserves3[1].quoteAssetReserve.toString());
571
+
572
+ assert(reserves3[0].baseAssetReserve.eq(new BN('1164705879')));
573
+ assert(reserves3[0].quoteAssetReserve.eq(new BN('858585859')));
574
+ assert(reserves3[1].baseAssetReserve.eq(new BN('1042105261')));
575
+ assert(reserves3[1].quoteAssetReserve.eq(new BN('959595959')));
370
576
  });
371
577
 
372
578
  it('live update functions', () => {
373
- const mockAmm = mockPerpMarkets[0].amm;
579
+ const myMockPerpMarkets = _.cloneDeep(mockPerpMarkets);
580
+ const mockMarket1 = myMockPerpMarkets[0];
581
+ const mockAmm = mockMarket1.amm;
374
582
  const now = new BN(new Date().getTime() / 1000); //todo
375
583
 
376
584
  const oraclePriceData = {
@@ -469,8 +677,8 @@ describe('AMM Tests', () => {
469
677
 
470
678
  assert(markTwapLive.eq(new BN('1949826')));
471
679
  assert(oracleTwapLive.eq(new BN('1942510')));
472
- assert(est1.eq(new BN('15692')), `got: ${est1}`);
473
- assert(est2.eq(new BN('15692')));
680
+ assert(est1.eq(new BN('16525')));
681
+ assert(est2.eq(new BN('16525')));
474
682
  });
475
683
 
476
684
  it('predicted funding rate mock2', async () => {
@@ -559,7 +767,7 @@ describe('AMM Tests', () => {
559
767
  assert(markTwapLive.eq(new BN('1222131')));
560
768
  assert(oracleTwapLive.eq(new BN('1222586')));
561
769
  assert(est1.eq(est2));
562
- assert(est2.eq(new BN('-1550')), `got: ${est2}`);
770
+ assert(est2.eq(new BN('-719')));
563
771
  });
564
772
 
565
773
  it('orderbook L2 gen (no topOfBookQuoteAmounts, 10 numOrders, low liquidity)', async () => {
package/tests/bn/test.ts CHANGED
@@ -147,6 +147,33 @@ describe('BigNum Tests', () => {
147
147
  '-1.0000000000000'
148
148
  );
149
149
  expect(BigNum.from('-100', 6).print()).to.equal('-0.000100');
150
+
151
+ // Case 7: really large numbers + switching between scientific/financial
152
+ expect(BigNum.fromPrint('123000000000').toMillified(3)).to.equal('123B');
153
+ expect(
154
+ BigNum.fromPrint('123000000000').toMillified(3, undefined, 'scientific')
155
+ ).to.equal('123G'); // (G = Giga)
156
+ expect(BigNum.fromPrint('123000000000000').toMillified(3)).to.equal('123T');
157
+ expect(
158
+ BigNum.fromPrint('123000000000000').toMillified(
159
+ 3,
160
+ undefined,
161
+ 'scientific'
162
+ )
163
+ ).to.equal('123T'); // (T = Tera)
164
+ expect(BigNum.fromPrint('123000000000000000').toMillified(3)).to.equal(
165
+ '123Q'
166
+ );
167
+ expect(
168
+ BigNum.fromPrint('123000000000000000').toMillified(
169
+ 3,
170
+ undefined,
171
+ 'scientific'
172
+ )
173
+ ).to.equal('123P'); // (P = Peta)
174
+
175
+ // TODO : Need to make the appropriate changes for the next line to pass
176
+ // expect(BigNum.fromPrint('123000000000000000000').toMillified(3)).to.equal('123000Q');
150
177
  });
151
178
 
152
179
  it('can initialise from string values correctly', () => {
@@ -84,7 +84,7 @@ export const mockAMM: AMM = {
84
84
  baseAssetAmountWithUnsettledLp: new BN(0),
85
85
  orderStepSize: new BN(0),
86
86
  orderTickSize: new BN(1),
87
- last24hAvgFundingRate: new BN(0),
87
+ last24HAvgFundingRate: new BN(0),
88
88
  lastFundingRateShort: new BN(0),
89
89
  lastFundingRateLong: new BN(0),
90
90
  concentrationCoef: new BN(0),