@drift-labs/sdk 0.2.0-master.13 → 0.2.0-master.16

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 (115) hide show
  1. package/lib/accounts/bulkUserStatsSubscription.d.ts +7 -0
  2. package/lib/accounts/bulkUserStatsSubscription.js +21 -0
  3. package/lib/accounts/bulkUserSubscription.js +0 -1
  4. package/lib/accounts/fetch.d.ts +2 -1
  5. package/lib/accounts/fetch.js +9 -1
  6. package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
  7. package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
  8. package/lib/accounts/types.d.ts +14 -2
  9. package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
  10. package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
  11. package/lib/addresses/pda.d.ts +1 -0
  12. package/lib/addresses/pda.js +8 -1
  13. package/lib/admin.d.ts +2 -0
  14. package/lib/admin.js +18 -0
  15. package/lib/clearingHouse.d.ts +17 -1
  16. package/lib/clearingHouse.js +195 -14
  17. package/lib/clearingHouseConfig.d.ts +1 -0
  18. package/lib/clearingHouseUser.d.ts +5 -0
  19. package/lib/clearingHouseUser.js +97 -3
  20. package/lib/clearingHouseUserStats.d.ts +17 -0
  21. package/lib/clearingHouseUserStats.js +36 -0
  22. package/lib/clearingHouseUserStatsConfig.d.ts +14 -0
  23. package/{src/clearingHouseConfig.js → lib/clearingHouseUserStatsConfig.js} +0 -0
  24. package/lib/config.js +1 -1
  25. package/lib/factory/bigNum.js +7 -9
  26. package/lib/idl/clearing_house.json +614 -64
  27. package/lib/math/bankBalance.d.ts +4 -0
  28. package/lib/math/bankBalance.js +24 -2
  29. package/lib/math/oracles.d.ts +3 -0
  30. package/lib/math/oracles.js +25 -5
  31. package/lib/math/position.js +2 -1
  32. package/lib/math/trade.js +2 -2
  33. package/lib/types.d.ts +59 -9
  34. package/lib/types.js +6 -0
  35. package/package.json +1 -1
  36. package/src/accounts/bulkUserStatsSubscription.ts +33 -0
  37. package/src/accounts/bulkUserSubscription.ts +0 -1
  38. package/src/accounts/fetch.ts +27 -2
  39. package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
  40. package/src/accounts/types.ts +18 -0
  41. package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
  42. package/src/addresses/pda.ts +13 -0
  43. package/src/admin.ts +29 -1
  44. package/src/clearingHouse.ts +318 -15
  45. package/src/clearingHouseConfig.ts +1 -0
  46. package/src/clearingHouseUser.ts +113 -10
  47. package/src/clearingHouseUserStats.ts +53 -0
  48. package/src/clearingHouseUserStatsConfig.ts +18 -0
  49. package/src/config.ts +1 -1
  50. package/src/factory/bigNum.ts +6 -7
  51. package/src/idl/clearing_house.json +614 -64
  52. package/src/math/bankBalance.ts +50 -1
  53. package/src/math/oracles.ts +42 -5
  54. package/src/math/position.ts +2 -1
  55. package/src/math/trade.ts +2 -2
  56. package/src/types.ts +63 -9
  57. package/tests/bn/test.ts +8 -0
  58. package/src/accounts/bulkAccountLoader.js +0 -197
  59. package/src/accounts/bulkUserSubscription.js +0 -33
  60. package/src/accounts/pollingClearingHouseAccountSubscriber.js +0 -311
  61. package/src/accounts/pollingOracleSubscriber.js +0 -93
  62. package/src/accounts/pollingTokenAccountSubscriber.js +0 -90
  63. package/src/accounts/pollingUserAccountSubscriber.js +0 -132
  64. package/src/accounts/types.js +0 -10
  65. package/src/accounts/utils.js +0 -7
  66. package/src/accounts/webSocketAccountSubscriber.js +0 -93
  67. package/src/accounts/webSocketClearingHouseAccountSubscriber.js +0 -233
  68. package/src/accounts/webSocketUserAccountSubscriber.js +0 -62
  69. package/src/addresses/marketAddresses.js +0 -26
  70. package/src/assert/assert.js +0 -9
  71. package/src/clearingHouseUserConfig.js +0 -2
  72. package/src/constants/banks.js +0 -42
  73. package/src/constants/markets.js +0 -42
  74. package/src/constants/numericConstants.js +0 -41
  75. package/src/events/eventList.js +0 -77
  76. package/src/events/eventSubscriber.js +0 -139
  77. package/src/events/fetchLogs.js +0 -50
  78. package/src/events/pollingLogProvider.js +0 -64
  79. package/src/events/sort.js +0 -44
  80. package/src/events/txEventCache.js +0 -71
  81. package/src/events/types.js +0 -20
  82. package/src/events/webSocketLogProvider.js +0 -41
  83. package/src/examples/makeTradeExample.js +0 -80
  84. package/src/factory/bigNum.js +0 -390
  85. package/src/factory/oracleClient.js +0 -20
  86. package/src/index.js +0 -69
  87. package/src/math/amm.js +0 -369
  88. package/src/math/auction.js +0 -42
  89. package/src/math/conversion.js +0 -11
  90. package/src/math/funding.js +0 -248
  91. package/src/math/oracles.js +0 -26
  92. package/src/math/repeg.js +0 -128
  93. package/src/math/state.js +0 -15
  94. package/src/math/trade.js +0 -253
  95. package/src/math/utils.js +0 -26
  96. package/src/math/utils.js.map +0 -1
  97. package/src/mockUSDCFaucet.js +0 -280
  98. package/src/oracles/oracleClientCache.js +0 -19
  99. package/src/oracles/pythClient.js +0 -46
  100. package/src/oracles/quoteAssetOracleClient.js +0 -32
  101. package/src/oracles/switchboardClient.js +0 -69
  102. package/src/oracles/types.js +0 -2
  103. package/src/orderParams.js +0 -20
  104. package/src/slot/SlotSubscriber.js +0 -39
  105. package/src/token/index.js +0 -38
  106. package/src/tokenFaucet.js +0 -189
  107. package/src/tx/types.js +0 -2
  108. package/src/tx/utils.js +0 -17
  109. package/src/types.js +0 -125
  110. package/src/userName.js +0 -20
  111. package/src/util/computeUnits.js +0 -27
  112. package/src/util/getTokenAddress.js +0 -9
  113. package/src/util/promiseTimeout.js +0 -14
  114. package/src/util/tps.js +0 -27
  115. package/src/wallet.js +0 -35
@@ -9,3 +9,7 @@ export declare function calculateInterestAccumulated(bank: BankAccount, now: BN)
9
9
  borrowInterest: BN;
10
10
  depositInterest: BN;
11
11
  };
12
+ export declare function calculateWithdrawLimit(bank: BankAccount, now: BN): {
13
+ borrowLimit: BN;
14
+ withdrawLimit: BN;
15
+ };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.calculateInterestAccumulated = exports.calculateLiabilityWeight = exports.calculateAssetWeight = exports.getTokenAmount = exports.getBalance = void 0;
3
+ exports.calculateWithdrawLimit = exports.calculateInterestAccumulated = exports.calculateLiabilityWeight = exports.calculateAssetWeight = exports.getTokenAmount = exports.getBalance = void 0;
4
4
  const types_1 = require("../types");
5
5
  const anchor_1 = require("@project-serum/anchor");
6
6
  const numericConstants_1 = require("../constants/numericConstants");
@@ -109,7 +109,7 @@ function calculateInterestAccumulated(bank, now) {
109
109
  .mul(borrowRateSlope)
110
110
  .div(numericConstants_1.BANK_UTILIZATION_PRECISION);
111
111
  }
112
- const timeSinceLastUpdate = now.sub(bank.lastUpdated);
112
+ const timeSinceLastUpdate = now.sub(bank.lastInterestTs);
113
113
  const modifiedBorrowRate = interest_rate.mul(timeSinceLastUpdate);
114
114
  const modifiedDepositRate = modifiedBorrowRate
115
115
  .mul(utilization)
@@ -126,3 +126,25 @@ function calculateInterestAccumulated(bank, now) {
126
126
  return { borrowInterest, depositInterest };
127
127
  }
128
128
  exports.calculateInterestAccumulated = calculateInterestAccumulated;
129
+ function calculateWithdrawLimit(bank, now) {
130
+ const bankDepositTokenAmount = getTokenAmount(bank.depositBalance, bank, types_1.BankBalanceType.DEPOSIT);
131
+ const bankBorrowTokenAmount = getTokenAmount(bank.borrowBalance, bank, types_1.BankBalanceType.BORROW);
132
+ const twentyFourHours = new anchor_1.BN(60 * 60 * 24);
133
+ const sinceLast = now.sub(bank.lastTwapTs);
134
+ const sinceStart = anchor_1.BN.max(numericConstants_1.ZERO, twentyFourHours.sub(sinceLast));
135
+ const borrowTokenTwapLive = bank.borrowTokenTwap
136
+ .mul(sinceStart)
137
+ .add(bankBorrowTokenAmount.mul(sinceLast))
138
+ .div(sinceLast.add(sinceLast));
139
+ const depositTokenTwapLive = bank.depositTokenTwap
140
+ .mul(sinceStart)
141
+ .add(bankDepositTokenAmount.mul(sinceLast))
142
+ .div(sinceLast.add(sinceLast));
143
+ const maxBorrowTokens = anchor_1.BN.min(anchor_1.BN.max(bankDepositTokenAmount.div(new anchor_1.BN(6)), borrowTokenTwapLive.add(borrowTokenTwapLive.div(new anchor_1.BN(5)))), bankDepositTokenAmount.sub(bankDepositTokenAmount.div(new anchor_1.BN(10)))); // between ~15-90% utilization with friction on twap
144
+ const minDepositTokens = depositTokenTwapLive.sub(anchor_1.BN.min(anchor_1.BN.max(depositTokenTwapLive.div(new anchor_1.BN(5)), bank.withdrawGuardThreshold), depositTokenTwapLive));
145
+ return {
146
+ borrowLimit: maxBorrowTokens.sub(bankBorrowTokenAmount),
147
+ withdrawLimit: bankDepositTokenAmount.sub(minDepositTokens),
148
+ };
149
+ }
150
+ exports.calculateWithdrawLimit = calculateWithdrawLimit;
@@ -1,3 +1,6 @@
1
+ /// <reference types="bn.js" />
1
2
  import { AMM, OracleGuardRails } from '../types';
2
3
  import { OraclePriceData } from '../oracles/types';
4
+ import { BN } from '../index';
3
5
  export declare function isOracleValid(amm: AMM, oraclePriceData: OraclePriceData, oracleGuardRails: OracleGuardRails, slot: number): boolean;
6
+ export declare function isOracleTooDivergent(amm: AMM, oraclePriceData: OraclePriceData, oracleGuardRails: OracleGuardRails, now: BN): boolean;
@@ -1,19 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isOracleValid = void 0;
3
+ exports.isOracleTooDivergent = exports.isOracleValid = void 0;
4
4
  const numericConstants_1 = require("../constants/numericConstants");
5
5
  const index_1 = require("../index");
6
6
  function isOracleValid(amm, oraclePriceData, oracleGuardRails, slot) {
7
- const isOraclePriceNonPositive = oraclePriceData.price.lt(numericConstants_1.ZERO);
7
+ const isOraclePriceNonPositive = oraclePriceData.price.lte(numericConstants_1.ZERO);
8
8
  const isOraclePriceTooVolatile = oraclePriceData.price
9
9
  .div(index_1.BN.max(numericConstants_1.ONE, amm.lastOraclePriceTwap))
10
10
  .gt(oracleGuardRails.validity.tooVolatileRatio) ||
11
11
  amm.lastOraclePriceTwap
12
12
  .div(index_1.BN.max(numericConstants_1.ONE, oraclePriceData.price))
13
13
  .gt(oracleGuardRails.validity.tooVolatileRatio);
14
- const isConfidenceTooLarge = oraclePriceData.price
15
- .div(index_1.BN.max(numericConstants_1.ONE, oraclePriceData.confidence))
16
- .lt(oracleGuardRails.validity.confidenceIntervalMaxSize);
14
+ const isConfidenceTooLarge = new index_1.BN(amm.baseSpread)
15
+ .add(index_1.BN.max(numericConstants_1.ONE, oraclePriceData.confidence))
16
+ .mul(numericConstants_1.BID_ASK_SPREAD_PRECISION)
17
+ .div(oraclePriceData.price)
18
+ .gt(new index_1.BN(amm.maxSpread));
17
19
  const oracleIsStale = oraclePriceData.slot
18
20
  .sub(new index_1.BN(slot))
19
21
  .gt(oracleGuardRails.validity.slotsBeforeStale);
@@ -24,3 +26,21 @@ function isOracleValid(amm, oraclePriceData, oracleGuardRails, slot) {
24
26
  isConfidenceTooLarge);
25
27
  }
26
28
  exports.isOracleValid = isOracleValid;
29
+ function isOracleTooDivergent(amm, oraclePriceData, oracleGuardRails, now) {
30
+ const sinceLastUpdate = now.sub(amm.lastOraclePriceTwapTs);
31
+ const sinceStart = index_1.BN.max(numericConstants_1.ZERO, new index_1.BN(60 * 5).sub(sinceLastUpdate));
32
+ const oracleTwap5min = amm.lastOraclePriceTwap5min
33
+ .mul(sinceStart)
34
+ .add(oraclePriceData.price)
35
+ .mul(sinceLastUpdate)
36
+ .div(sinceStart.add(sinceLastUpdate));
37
+ const oracleSpread = oracleTwap5min.sub(oraclePriceData.price);
38
+ const oracleSpreadPct = oracleSpread
39
+ .mul(numericConstants_1.MARK_PRICE_PRECISION)
40
+ .div(oracleTwap5min);
41
+ const tooDivergent = oracleSpreadPct
42
+ .abs()
43
+ .gte(numericConstants_1.BID_ASK_SPREAD_PRECISION.mul(oracleGuardRails.priceDivergence.markOracleDivergenceNumerator).div(oracleGuardRails.priceDivergence.markOracleDivergenceDenominator));
44
+ return tooDivergent;
45
+ }
46
+ exports.isOracleTooDivergent = isOracleTooDivergent;
@@ -117,7 +117,8 @@ exports.calculatePositionFundingPNL = calculatePositionFundingPNL;
117
117
  function positionIsAvailable(position) {
118
118
  return (position.baseAssetAmount.eq(numericConstants_1.ZERO) &&
119
119
  position.openOrders.eq(numericConstants_1.ZERO) &&
120
- position.quoteAssetAmount.eq(numericConstants_1.ZERO));
120
+ position.quoteAssetAmount.eq(numericConstants_1.ZERO) &&
121
+ position.lpShares.eq(numericConstants_1.ZERO));
121
122
  }
122
123
  exports.positionIsAvailable = positionIsAvailable;
123
124
  /**
package/lib/math/trade.js CHANGED
@@ -113,8 +113,8 @@ function calculateTradeAcquiredAmounts(direction, amount, market, inputAssetType
113
113
  const [newQuoteAssetReserve, newBaseAssetReserve] = (0, amm_1.calculateAmmReservesAfterSwap)(amm, inputAssetType, amount, swapDirection);
114
114
  const acquiredBase = amm.baseAssetReserve.sub(newBaseAssetReserve);
115
115
  const acquiredQuote = amm.quoteAssetReserve.sub(newQuoteAssetReserve);
116
- const acquiredQuoteAssetamount = (0, amm_1.calculateQuoteAssetAmountSwapped)(acquiredQuote.abs(), amm.pegMultiplier, swapDirection);
117
- return [acquiredBase, acquiredQuote, acquiredQuoteAssetamount];
116
+ const acquiredQuoteAssetAmount = (0, amm_1.calculateQuoteAssetAmountSwapped)(acquiredQuote.abs(), amm.pegMultiplier, swapDirection);
117
+ return [acquiredBase, acquiredQuote, acquiredQuoteAssetAmount];
118
118
  }
119
119
  exports.calculateTradeAcquiredAmounts = calculateTradeAcquiredAmounts;
120
120
  /**
package/lib/types.d.ts CHANGED
@@ -203,6 +203,8 @@ export declare type LiquidationRecord = {
203
203
  liquidateBorrow: LiquidateBorrowRecord;
204
204
  liquidateBorrowForPerpPnl: LiquidateBorrowForPerpPnlRecord;
205
205
  liquidatePerpPnlForDeposit: LiquidatePerpPnlForDepositRecord;
206
+ perpBankruptcy: PerpBankruptcyRecord;
207
+ borrowBankruptcy: BorrowBankruptcyRecord;
206
208
  };
207
209
  export declare class LiquidationType {
208
210
  static readonly LIQUIDATE_PERP: {
@@ -217,6 +219,12 @@ export declare class LiquidationType {
217
219
  static readonly LIQUIDATE_PERP_PNL_FOR_DEPOSIT: {
218
220
  liquidatePerpPnlForDeposit: {};
219
221
  };
222
+ static readonly PERP_BANKRUPTCY: {
223
+ perpBankruptcy: {};
224
+ };
225
+ static readonly BORROW_BANKRUPTCY: {
226
+ borrowBankruptcy: {};
227
+ };
220
228
  }
221
229
  export declare type LiquidatePerpRecord = {
222
230
  marketIndex: BN;
@@ -255,14 +263,25 @@ export declare type LiquidatePerpPnlForDepositRecord = {
255
263
  assetPrice: BN;
256
264
  assetTransfer: BN;
257
265
  };
266
+ export declare type PerpBankruptcyRecord = {
267
+ marketIndex: BN;
268
+ pnl: BN;
269
+ cumulativeFundingRateDelta: BN;
270
+ };
271
+ export declare type BorrowBankruptcyRecord = {
272
+ bankIndex: BN;
273
+ borrowAmount: BN;
274
+ cumulativeDepositInterestDelta: BN;
275
+ };
258
276
  export declare type SettlePnlRecord = {
259
277
  ts: BN;
278
+ user: PublicKey;
260
279
  marketIndex: BN;
261
280
  pnl: BN;
262
281
  baseAssetAmount: BN;
263
282
  quoteAssetAmountAfter: BN;
264
283
  quoteEntryamount: BN;
265
- oraclePrice: BN;
284
+ settlePrice: BN;
266
285
  };
267
286
  export declare type OrderRecord = {
268
287
  ts: BN;
@@ -349,7 +368,8 @@ export declare type BankAccount = {
349
368
  cumulativeBorrowInterest: BN;
350
369
  depositBalance: BN;
351
370
  borrowBalance: BN;
352
- lastUpdated: BN;
371
+ lastInterestTs: BN;
372
+ lastTwapTs: BN;
353
373
  oracle: PublicKey;
354
374
  initialAssetWeight: BN;
355
375
  maintenanceAssetWeight: BN;
@@ -357,6 +377,10 @@ export declare type BankAccount = {
357
377
  maintenanceLiabilityWeight: BN;
358
378
  liquidationFee: BN;
359
379
  imfFactor: BN;
380
+ withdrawGuardThreshold: BN;
381
+ depositTokenTwap: BN;
382
+ borrowTokenTwap: BN;
383
+ utilizationTwap: BN;
360
384
  };
361
385
  export declare type PoolBalance = {
362
386
  balance: BN;
@@ -368,8 +392,10 @@ export declare type AMM = {
368
392
  lastFundingRate: BN;
369
393
  lastFundingRateTs: BN;
370
394
  lastMarkPriceTwap: BN;
395
+ lastMarkPriceTwap5min: BN;
371
396
  lastMarkPriceTwapTs: BN;
372
397
  lastOraclePriceTwap: BN;
398
+ lastOraclePriceTwap5min: BN;
373
399
  lastOraclePriceTwapTs: BN;
374
400
  lastOracleMarkSpreadPct: BN;
375
401
  lastOracleConfPct: BN;
@@ -380,11 +406,16 @@ export declare type AMM = {
380
406
  pegMultiplier: BN;
381
407
  cumulativeFundingRateLong: BN;
382
408
  cumulativeFundingRateShort: BN;
409
+ cumulativeFundingRateLp: BN;
383
410
  cumulativeRepegRebateLong: BN;
384
411
  cumulativeRepegRebateShort: BN;
385
412
  totalFeeMinusDistributions: BN;
386
413
  totalFeeWithdrawn: BN;
387
414
  totalFee: BN;
415
+ cumulativeFundingPaymentPerLp: BN;
416
+ cumulativeFeePerLp: BN;
417
+ cumulativeNetBaseAssetAmountPerLp: BN;
418
+ userLpShares: BN;
388
419
  minimumQuoteAssetTradeSize: BN;
389
420
  baseAssetAmountStepSize: BN;
390
421
  maxBaseAssetAmountRatio: number;
@@ -406,6 +437,8 @@ export declare type AMM = {
406
437
  longSpread: BN;
407
438
  shortSpread: BN;
408
439
  maxSpread: number;
440
+ marketPosition: UserPosition;
441
+ marketPositionPerLp: UserPosition;
409
442
  };
410
443
  export declare type UserPosition = {
411
444
  baseAssetAmount: BN;
@@ -416,14 +449,20 @@ export declare type UserPosition = {
416
449
  openOrders: BN;
417
450
  openBids: BN;
418
451
  openAsks: BN;
452
+ realizedPnl: BN;
453
+ lpShares: BN;
454
+ lastFeePerLp: BN;
455
+ lastNetBaseAssetAmountPerLp: BN;
456
+ lastNetQuoteAssetAmountPerLp: BN;
419
457
  };
420
- export declare type UserAccount = {
421
- authority: PublicKey;
422
- name: number[];
423
- userId: number;
424
- bankBalances: UserBankBalance[];
425
- collateral: BN;
426
- cumulativeDeposits: BN;
458
+ export declare type UserStatsAccount = {
459
+ numberOfUsers: number;
460
+ makerVolume30D: BN;
461
+ takerVolume30D: BN;
462
+ fillerVolume30D: BN;
463
+ lastMakerVolume30DTs: BN;
464
+ lastTakerVolume30DTs: BN;
465
+ lastFillerVolume30DTs: BN;
427
466
  fees: {
428
467
  totalFeePaid: BN;
429
468
  totalFeeRebate: BN;
@@ -431,9 +470,18 @@ export declare type UserAccount = {
431
470
  totalReferralReward: BN;
432
471
  totalRefereeDiscount: BN;
433
472
  };
473
+ authority: PublicKey;
474
+ referrer: PublicKey;
475
+ };
476
+ export declare type UserAccount = {
477
+ authority: PublicKey;
478
+ name: number[];
479
+ userId: number;
480
+ bankBalances: UserBankBalance[];
434
481
  positions: UserPosition[];
435
482
  orders: Order[];
436
483
  beingLiquidated: boolean;
484
+ bankrupt: boolean;
437
485
  nextLiquidationId: number;
438
486
  };
439
487
  export declare type UserBankBalance = {
@@ -529,10 +577,12 @@ export declare const DefaultOrderParams: {
529
577
  };
530
578
  export declare type MakerInfo = {
531
579
  maker: PublicKey;
580
+ makerStats: PublicKey;
532
581
  order: Order;
533
582
  };
534
583
  export declare type TakerInfo = {
535
584
  taker: PublicKey;
585
+ takerStats: PublicKey;
536
586
  order: Order;
537
587
  };
538
588
  export interface IWallet {
package/lib/types.js CHANGED
@@ -108,6 +108,12 @@ LiquidationType.LIQUIDATE_BORROW_FOR_PERP_PNL = {
108
108
  LiquidationType.LIQUIDATE_PERP_PNL_FOR_DEPOSIT = {
109
109
  liquidatePerpPnlForDeposit: {},
110
110
  };
111
+ LiquidationType.PERP_BANKRUPTCY = {
112
+ perpBankruptcy: {},
113
+ };
114
+ LiquidationType.BORROW_BANKRUPTCY = {
115
+ borrowBankruptcy: {},
116
+ };
111
117
  exports.DefaultOrderParams = {
112
118
  orderType: OrderType.MARKET,
113
119
  userOrderId: 0,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "0.2.0-master.13",
3
+ "version": "0.2.0-master.16",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -0,0 +1,33 @@
1
+ import { ClearingHouseUserStats } from '../clearingHouseUserStats';
2
+ import { BulkAccountLoader } from './bulkAccountLoader';
3
+ import { PollingUserStatsAccountSubscriber } from './pollingUserStatsAccountSubscriber';
4
+
5
+ /**
6
+ * @param userStats
7
+ * @param accountLoader
8
+ */
9
+ export async function bulkPollingUserStatsSubscribe(
10
+ userStats: ClearingHouseUserStats[],
11
+ accountLoader: BulkAccountLoader
12
+ ): Promise<void> {
13
+ if (userStats.length === 0) {
14
+ await accountLoader.load();
15
+ return;
16
+ }
17
+
18
+ await Promise.all(
19
+ userStats.map((userStat) => {
20
+ return (
21
+ userStat.accountSubscriber as PollingUserStatsAccountSubscriber
22
+ ).addToAccountLoader();
23
+ })
24
+ );
25
+
26
+ await accountLoader.load();
27
+
28
+ await Promise.all(
29
+ userStats.map(async (userStat) => {
30
+ return userStat.subscribe();
31
+ })
32
+ );
33
+ }
@@ -17,7 +17,6 @@ export async function bulkPollingUserSubscribe(
17
17
 
18
18
  await Promise.all(
19
19
  users.map((user) => {
20
- // Pull the keys from the authority map so we can skip fetching them in addToAccountLoader
21
20
  return (
22
21
  user.accountSubscriber as PollingUserAccountSubscriber
23
22
  ).addToAccountLoader();
@@ -1,6 +1,9 @@
1
1
  import { Connection, PublicKey } from '@solana/web3.js';
2
- import { UserAccount } from '../types';
3
- import { getUserAccountPublicKey } from '../addresses/pda';
2
+ import { UserAccount, UserStatsAccount } from '../types';
3
+ import {
4
+ getUserAccountPublicKey,
5
+ getUserStatsAccountPublicKey,
6
+ } from '../addresses/pda';
4
7
  import { Program } from '@project-serum/anchor';
5
8
 
6
9
  export async function fetchUserAccounts(
@@ -31,3 +34,25 @@ export async function fetchUserAccounts(
31
34
  ) as UserAccount;
32
35
  });
33
36
  }
37
+
38
+ export async function fetchUserStatsAccount(
39
+ connection: Connection,
40
+ program: Program,
41
+ authority: PublicKey
42
+ ): Promise<UserStatsAccount | undefined> {
43
+ const userStatsPublicKey = getUserStatsAccountPublicKey(
44
+ program.programId,
45
+ authority
46
+ );
47
+ const accountInfo = await connection.getAccountInfo(
48
+ userStatsPublicKey,
49
+ 'confirmed'
50
+ );
51
+
52
+ return accountInfo
53
+ ? (program.account.user.coder.accounts.decode(
54
+ 'UserStats',
55
+ accountInfo.data
56
+ ) as UserStatsAccount)
57
+ : undefined;
58
+ }
@@ -0,0 +1,172 @@
1
+ import {
2
+ DataAndSlot,
3
+ AccountToPoll,
4
+ NotSubscribedError,
5
+ UserStatsAccountSubscriber,
6
+ UserStatsAccountEvents,
7
+ } from './types';
8
+ import { Program } from '@project-serum/anchor';
9
+ import StrictEventEmitter from 'strict-event-emitter-types';
10
+ import { EventEmitter } from 'events';
11
+ import { PublicKey } from '@solana/web3.js';
12
+ import { UserStatsAccount } from '../types';
13
+ import { BulkAccountLoader } from './bulkAccountLoader';
14
+ import { capitalize } from './utils';
15
+
16
+ export class PollingUserStatsAccountSubscriber
17
+ implements UserStatsAccountSubscriber
18
+ {
19
+ isSubscribed: boolean;
20
+ program: Program;
21
+ eventEmitter: StrictEventEmitter<EventEmitter, UserStatsAccountEvents>;
22
+ userStatsAccountPublicKey: PublicKey;
23
+
24
+ accountLoader: BulkAccountLoader;
25
+ accountsToPoll = new Map<string, AccountToPoll>();
26
+ errorCallbackId?: string;
27
+
28
+ userStats?: DataAndSlot<UserStatsAccount>;
29
+
30
+ public constructor(
31
+ program: Program,
32
+ userStatsAccountPublicKey: PublicKey,
33
+ accountLoader: BulkAccountLoader
34
+ ) {
35
+ this.isSubscribed = false;
36
+ this.program = program;
37
+ this.accountLoader = accountLoader;
38
+ this.eventEmitter = new EventEmitter();
39
+ this.userStatsAccountPublicKey = userStatsAccountPublicKey;
40
+ }
41
+
42
+ async subscribe(): Promise<boolean> {
43
+ if (this.isSubscribed) {
44
+ return true;
45
+ }
46
+
47
+ await this.addToAccountLoader();
48
+
49
+ let subscriptionSucceeded = false;
50
+ let retries = 0;
51
+ while (!subscriptionSucceeded && retries < 5) {
52
+ await this.fetchIfUnloaded();
53
+ subscriptionSucceeded = this.didSubscriptionSucceed();
54
+ retries++;
55
+ }
56
+
57
+ if (subscriptionSucceeded) {
58
+ this.eventEmitter.emit('update');
59
+ }
60
+
61
+ this.isSubscribed = subscriptionSucceeded;
62
+ return subscriptionSucceeded;
63
+ }
64
+
65
+ async addToAccountLoader(): Promise<void> {
66
+ if (this.accountsToPoll.size > 0) {
67
+ return;
68
+ }
69
+
70
+ this.accountsToPoll.set(this.userStatsAccountPublicKey.toString(), {
71
+ key: 'userStats',
72
+ publicKey: this.userStatsAccountPublicKey,
73
+ eventType: 'userStatsAccountUpdate',
74
+ });
75
+
76
+ for (const [_, accountToPoll] of this.accountsToPoll) {
77
+ accountToPoll.callbackId = this.accountLoader.addAccount(
78
+ accountToPoll.publicKey,
79
+ (buffer, slot) => {
80
+ if (!buffer) {
81
+ return;
82
+ }
83
+
84
+ const account = this.program.account[
85
+ accountToPoll.key
86
+ ].coder.accounts.decode(capitalize(accountToPoll.key), buffer);
87
+ this[accountToPoll.key] = { data: account, slot };
88
+ // @ts-ignore
89
+ this.eventEmitter.emit(accountToPoll.eventType, account);
90
+ this.eventEmitter.emit('update');
91
+ }
92
+ );
93
+ }
94
+
95
+ this.errorCallbackId = this.accountLoader.addErrorCallbacks((error) => {
96
+ this.eventEmitter.emit('error', error);
97
+ });
98
+ }
99
+
100
+ async fetchIfUnloaded(): Promise<void> {
101
+ let shouldFetch = false;
102
+ for (const [_, accountToPoll] of this.accountsToPoll) {
103
+ if (this[accountToPoll.key] === undefined) {
104
+ shouldFetch = true;
105
+ break;
106
+ }
107
+ }
108
+
109
+ if (shouldFetch) {
110
+ await this.fetch();
111
+ }
112
+ }
113
+
114
+ async fetch(): Promise<void> {
115
+ await this.accountLoader.load();
116
+ for (const [_, accountToPoll] of this.accountsToPoll) {
117
+ const { buffer, slot } = this.accountLoader.getBufferAndSlot(
118
+ accountToPoll.publicKey
119
+ );
120
+ if (buffer) {
121
+ const account = this.program.account[
122
+ accountToPoll.key
123
+ ].coder.accounts.decode(capitalize(accountToPoll.key), buffer);
124
+ this[accountToPoll.key] = { data: account, slot };
125
+ }
126
+ }
127
+ }
128
+
129
+ didSubscriptionSucceed(): boolean {
130
+ let success = true;
131
+ for (const [_, accountToPoll] of this.accountsToPoll) {
132
+ if (!this[accountToPoll.key]) {
133
+ success = false;
134
+ break;
135
+ }
136
+ }
137
+ return success;
138
+ }
139
+
140
+ async unsubscribe(): Promise<void> {
141
+ if (!this.isSubscribed) {
142
+ return;
143
+ }
144
+
145
+ for (const [_, accountToPoll] of this.accountsToPoll) {
146
+ this.accountLoader.removeAccount(
147
+ accountToPoll.publicKey,
148
+ accountToPoll.callbackId
149
+ );
150
+ }
151
+
152
+ this.accountLoader.removeErrorCallbacks(this.errorCallbackId);
153
+ this.errorCallbackId = undefined;
154
+
155
+ this.accountsToPoll.clear();
156
+
157
+ this.isSubscribed = false;
158
+ }
159
+
160
+ assertIsSubscribed(): void {
161
+ if (!this.isSubscribed) {
162
+ throw new NotSubscribedError(
163
+ 'You must call `subscribe` before using this function'
164
+ );
165
+ }
166
+ }
167
+
168
+ public getUserStatsAccountAndSlot(): DataAndSlot<UserStatsAccount> {
169
+ this.assertIsSubscribed();
170
+ return this.userStats;
171
+ }
172
+ }
@@ -4,6 +4,7 @@ import {
4
4
  OracleSource,
5
5
  StateAccount,
6
6
  UserAccount,
7
+ UserStatsAccount,
7
8
  } from '../types';
8
9
  import StrictEventEmitter from 'strict-event-emitter-types';
9
10
  import { EventEmitter } from 'events';
@@ -130,3 +131,20 @@ export type DataAndSlot<T> = {
130
131
  data: T;
131
132
  slot: number;
132
133
  };
134
+
135
+ export interface UserStatsAccountEvents {
136
+ userStatsAccountUpdate: (payload: UserStatsAccount) => void;
137
+ update: void;
138
+ error: (e: Error) => void;
139
+ }
140
+
141
+ export interface UserStatsAccountSubscriber {
142
+ eventEmitter: StrictEventEmitter<EventEmitter, UserStatsAccountEvents>;
143
+ isSubscribed: boolean;
144
+
145
+ subscribe(): Promise<boolean>;
146
+ fetch(): Promise<void>;
147
+ unsubscribe(): Promise<void>;
148
+
149
+ getUserStatsAccountAndSlot(): DataAndSlot<UserStatsAccount>;
150
+ }
@@ -0,0 +1,80 @@
1
+ import {
2
+ DataAndSlot,
3
+ AccountSubscriber,
4
+ NotSubscribedError,
5
+ UserStatsAccountSubscriber,
6
+ UserStatsAccountEvents,
7
+ } from './types';
8
+ import { Program } from '@project-serum/anchor';
9
+ import StrictEventEmitter from 'strict-event-emitter-types';
10
+ import { EventEmitter } from 'events';
11
+ import { PublicKey } from '@solana/web3.js';
12
+ import { WebSocketAccountSubscriber } from './webSocketAccountSubscriber';
13
+ import { UserStatsAccount } from '../types';
14
+
15
+ export class WebSocketUserStatsAccountSubscriber
16
+ implements UserStatsAccountSubscriber
17
+ {
18
+ isSubscribed: boolean;
19
+ program: Program;
20
+ eventEmitter: StrictEventEmitter<EventEmitter, UserStatsAccountEvents>;
21
+ userStatsAccountPublicKey: PublicKey;
22
+
23
+ userStatsAccountSubscriber: AccountSubscriber<UserStatsAccount>;
24
+
25
+ public constructor(program: Program, userStatsAccountPublicKey: PublicKey) {
26
+ this.isSubscribed = false;
27
+ this.program = program;
28
+ this.userStatsAccountPublicKey = userStatsAccountPublicKey;
29
+ this.eventEmitter = new EventEmitter();
30
+ }
31
+
32
+ async subscribe(): Promise<boolean> {
33
+ if (this.isSubscribed) {
34
+ return true;
35
+ }
36
+
37
+ this.userStatsAccountSubscriber = new WebSocketAccountSubscriber(
38
+ 'userStats',
39
+ this.program,
40
+ this.userStatsAccountPublicKey
41
+ );
42
+ await this.userStatsAccountSubscriber.subscribe(
43
+ (data: UserStatsAccount) => {
44
+ this.eventEmitter.emit('userStatsAccountUpdate', data);
45
+ this.eventEmitter.emit('update');
46
+ }
47
+ );
48
+
49
+ this.eventEmitter.emit('update');
50
+ this.isSubscribed = true;
51
+ return true;
52
+ }
53
+
54
+ async fetch(): Promise<void> {
55
+ await Promise.all([this.userStatsAccountSubscriber.fetch()]);
56
+ }
57
+
58
+ async unsubscribe(): Promise<void> {
59
+ if (!this.isSubscribed) {
60
+ return;
61
+ }
62
+
63
+ await Promise.all([this.userStatsAccountSubscriber.unsubscribe()]);
64
+
65
+ this.isSubscribed = false;
66
+ }
67
+
68
+ assertIsSubscribed(): void {
69
+ if (!this.isSubscribed) {
70
+ throw new NotSubscribedError(
71
+ 'You must call `subscribe` before using this function'
72
+ );
73
+ }
74
+ }
75
+
76
+ public getUserStatsAccountAndSlot(): DataAndSlot<UserStatsAccount> {
77
+ this.assertIsSubscribed();
78
+ return this.userStatsAccountSubscriber.dataAndSlot;
79
+ }
80
+ }