@drift-labs/sdk 0.2.0-master.0 → 0.2.0-master.11

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 (121) hide show
  1. package/lib/admin.d.ts +8 -5
  2. package/lib/admin.js +43 -11
  3. package/lib/clearingHouse.d.ts +28 -18
  4. package/lib/clearingHouse.js +366 -143
  5. package/lib/clearingHouseUser.d.ts +2 -2
  6. package/lib/clearingHouseUser.js +8 -17
  7. package/lib/config.js +1 -1
  8. package/lib/constants/banks.js +9 -2
  9. package/lib/constants/numericConstants.d.ts +2 -0
  10. package/lib/constants/numericConstants.js +3 -1
  11. package/lib/factory/bigNum.d.ts +8 -2
  12. package/lib/factory/bigNum.js +14 -6
  13. package/lib/idl/clearing_house.json +805 -202
  14. package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  15. package/lib/index.d.ts +3 -2
  16. package/lib/index.js +7 -2
  17. package/lib/math/amm.d.ts +6 -1
  18. package/lib/math/amm.js +124 -41
  19. package/lib/math/auction.js +4 -1
  20. package/lib/math/orders.d.ts +2 -2
  21. package/lib/math/orders.js +18 -11
  22. package/lib/math/position.js +3 -1
  23. package/lib/math/repeg.js +1 -1
  24. package/lib/math/trade.d.ts +1 -1
  25. package/lib/math/trade.js +7 -10
  26. package/lib/orderParams.d.ts +14 -5
  27. package/lib/orderParams.js +8 -96
  28. package/lib/orders.d.ts +1 -2
  29. package/lib/orders.js +6 -85
  30. package/lib/slot/SlotSubscriber.d.ts +7 -0
  31. package/lib/slot/SlotSubscriber.js +3 -0
  32. package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +7 -5
  33. package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +41 -40
  34. package/lib/tx/utils.js +1 -1
  35. package/lib/types.d.ts +137 -14
  36. package/lib/types.js +53 -1
  37. package/lib/util/computeUnits.js +1 -1
  38. package/package.json +3 -3
  39. package/src/accounts/bulkAccountLoader.js +197 -0
  40. package/src/accounts/bulkUserSubscription.js +33 -0
  41. package/src/accounts/fetch.js +29 -0
  42. package/src/accounts/pollingClearingHouseAccountSubscriber.js +311 -0
  43. package/src/accounts/pollingOracleSubscriber.js +93 -0
  44. package/src/accounts/pollingTokenAccountSubscriber.js +90 -0
  45. package/src/accounts/pollingUserAccountSubscriber.js +132 -0
  46. package/src/accounts/types.js +10 -0
  47. package/src/accounts/utils.js +7 -0
  48. package/src/accounts/webSocketAccountSubscriber.js +93 -0
  49. package/src/accounts/webSocketClearingHouseAccountSubscriber.js +233 -0
  50. package/src/accounts/webSocketUserAccountSubscriber.js +62 -0
  51. package/src/addresses/marketAddresses.js +26 -0
  52. package/src/addresses/pda.js +104 -0
  53. package/src/admin.ts +66 -14
  54. package/src/assert/assert.js +9 -0
  55. package/src/clearingHouse.ts +558 -230
  56. package/src/clearingHouseUser.ts +12 -23
  57. package/src/config.ts +1 -1
  58. package/src/constants/banks.ts +9 -2
  59. package/src/constants/numericConstants.ts +2 -0
  60. package/src/events/eventList.js +77 -0
  61. package/src/events/eventSubscriber.js +139 -0
  62. package/src/events/fetchLogs.js +50 -0
  63. package/src/events/pollingLogProvider.js +64 -0
  64. package/src/events/sort.js +44 -0
  65. package/src/events/txEventCache.js +71 -0
  66. package/src/events/types.js +20 -0
  67. package/src/events/webSocketLogProvider.js +41 -0
  68. package/src/examples/makeTradeExample.js +80 -0
  69. package/src/factory/bigNum.js +364 -0
  70. package/src/factory/bigNum.ts +26 -9
  71. package/src/factory/oracleClient.js +20 -0
  72. package/src/idl/clearing_house.json +805 -202
  73. package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  74. package/src/index.js +100 -0
  75. package/src/index.ts +3 -2
  76. package/src/math/amm.js +369 -0
  77. package/src/math/amm.ts +207 -52
  78. package/src/math/auction.js +42 -0
  79. package/src/math/auction.ts +5 -1
  80. package/src/math/bankBalance.js +75 -0
  81. package/src/math/conversion.js +11 -0
  82. package/src/math/funding.js +248 -0
  83. package/src/math/market.js +57 -0
  84. package/src/math/oracles.js +26 -0
  85. package/src/math/orders.js +110 -0
  86. package/src/math/orders.ts +17 -13
  87. package/src/math/position.js +140 -0
  88. package/src/math/position.ts +5 -1
  89. package/src/math/repeg.js +128 -0
  90. package/src/math/repeg.ts +2 -1
  91. package/src/math/state.js +15 -0
  92. package/src/math/trade.js +253 -0
  93. package/src/math/trade.ts +23 -25
  94. package/src/math/utils.js +0 -1
  95. package/src/mockUSDCFaucet.js +280 -0
  96. package/src/oracles/oracleClientCache.js +19 -0
  97. package/src/oracles/pythClient.js +46 -0
  98. package/src/oracles/quoteAssetOracleClient.js +32 -0
  99. package/src/oracles/switchboardClient.js +69 -0
  100. package/src/oracles/types.js +2 -0
  101. package/src/orderParams.js +20 -0
  102. package/src/orderParams.ts +20 -141
  103. package/src/orders.js +134 -0
  104. package/src/orders.ts +7 -131
  105. package/src/slot/SlotSubscriber.js +39 -0
  106. package/src/slot/SlotSubscriber.ts +11 -1
  107. package/src/token/index.js +38 -0
  108. package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +48 -59
  109. package/src/tx/retryTxSender.js +188 -0
  110. package/src/tx/types.js +2 -0
  111. package/src/tx/utils.js +17 -0
  112. package/src/tx/utils.ts +1 -1
  113. package/src/types.js +114 -0
  114. package/src/types.ts +132 -16
  115. package/src/userName.js +20 -0
  116. package/src/util/computeUnits.ts +1 -1
  117. package/src/util/promiseTimeout.js +14 -0
  118. package/src/util/tps.js +27 -0
  119. package/src/wallet.js +35 -0
  120. package/src/util/computeUnits.js +0 -17
  121. package/src/util/computeUnits.js.map +0 -1
package/lib/types.d.ts CHANGED
@@ -25,6 +25,14 @@ export declare class PositionDirection {
25
25
  short: {};
26
26
  };
27
27
  }
28
+ export declare class DepositDirection {
29
+ static readonly DEPOSIT: {
30
+ deposit: {};
31
+ };
32
+ static readonly WITHDRAW: {
33
+ withdraw: {};
34
+ };
35
+ }
28
36
  export declare class OracleSource {
29
37
  static readonly PYTH: {
30
38
  pyth: {};
@@ -88,6 +96,23 @@ export declare class OrderAction {
88
96
  static readonly FILL: {
89
97
  fill: {};
90
98
  };
99
+ static readonly TRIGGER: {
100
+ trigger: {};
101
+ };
102
+ }
103
+ export declare class OrderActionExplanation {
104
+ static readonly NONE: {
105
+ none: {};
106
+ };
107
+ static readonly BREACHED_MARGIN_REQUIREMENT: {
108
+ breachedMarginRequirement: {};
109
+ };
110
+ static readonly ORACLE_PRICE_BREACHED_LIMIT_PRICE: {
111
+ oraclePriceBreachedLimitPrice: {};
112
+ };
113
+ static readonly MARKET_ORDER_FILLED_TO_LIMIT_PRICE: {
114
+ marketOrderFilledToLimitPrice: {};
115
+ };
91
116
  }
92
117
  export declare class OrderTriggerCondition {
93
118
  static readonly ABOVE: {
@@ -115,6 +140,7 @@ export declare type DepositRecord = {
115
140
  };
116
141
  bankIndex: BN;
117
142
  amount: BN;
143
+ oraclePrice: BN;
118
144
  from?: PublicKey;
119
145
  to?: PublicKey;
120
146
  };
@@ -161,20 +187,66 @@ export declare type FundingPaymentRecord = {
161
187
  };
162
188
  export declare type LiquidationRecord = {
163
189
  ts: BN;
164
- recordId: BN;
165
- userAuthority: PublicKey;
166
190
  user: PublicKey;
167
- partial: boolean;
168
- baseAssetValue: BN;
169
- baseAssetValueClosed: BN;
170
- liquidationFee: BN;
171
- feeToLiquidator: BN;
172
- feeToInsuranceFund: BN;
173
191
  liquidator: PublicKey;
192
+ liquidationType: LiquidationType;
193
+ marginRequirement: BN;
174
194
  totalCollateral: BN;
175
- collateral: BN;
176
- unrealizedPnl: BN;
177
- marginRatio: BN;
195
+ liquidatePerp: LiquidatePerpRecord;
196
+ liquidateBorrow: LiquidateBorrowRecord;
197
+ liquidateBorrowForPerpPnl: LiquidateBorrowForPerpPnlRecord;
198
+ liquidatePerpPnlForDeposit: LiquidatePerpPnlForDepositRecord;
199
+ };
200
+ export declare class LiquidationType {
201
+ static readonly LIQUIDATE_PERP: {
202
+ liquidatePerp: {};
203
+ };
204
+ static readonly LIQUIDATE_BORROW: {
205
+ liquidateBorrow: {};
206
+ };
207
+ static readonly LIQUIDATE_BORROW_FOR_PERP_PNL: {
208
+ liquidateBorrowForPerpPnl: {};
209
+ };
210
+ static readonly LIQUIDATE_PERP_PNL_FOR_DEPOSIT: {
211
+ liquidatePerpPnlForDeposit: {};
212
+ };
213
+ }
214
+ export declare type LiquidatePerpRecord = {
215
+ marketIndex: BN;
216
+ orderIds: BN[];
217
+ oraclePrice: BN;
218
+ baseAssetAmount: BN;
219
+ quoteAssetAmount: BN;
220
+ userPnl: BN;
221
+ liquidatorPnl: BN;
222
+ canceledOrdersFee: BN;
223
+ userOrderId: BN;
224
+ liquidatorOrderId: BN;
225
+ fillRecordId: BN;
226
+ };
227
+ export declare type LiquidateBorrowRecord = {
228
+ assetBankIndex: BN;
229
+ assetPrice: BN;
230
+ assetTransfer: BN;
231
+ liabilityBankIndex: BN;
232
+ liabilityPrice: BN;
233
+ liabilityTransfer: BN;
234
+ };
235
+ export declare type LiquidateBorrowForPerpPnlRecord = {
236
+ marketIndex: BN;
237
+ marketOraclePrice: BN;
238
+ pnlTransfer: BN;
239
+ liabilityBankIndex: BN;
240
+ liabilityPrice: BN;
241
+ liabilityTransfer: BN;
242
+ };
243
+ export declare type LiquidatePerpPnlForDepositRecord = {
244
+ marketIndex: BN;
245
+ marketOraclePrice: BN;
246
+ pnlTransfer: BN;
247
+ assetBankIndex: BN;
248
+ assetPrice: BN;
249
+ assetTransfer: BN;
178
250
  };
179
251
  export declare type OrderRecord = {
180
252
  ts: BN;
@@ -182,7 +254,10 @@ export declare type OrderRecord = {
182
254
  maker: PublicKey;
183
255
  takerOrder: Order;
184
256
  makerOrder: Order;
257
+ takerUnsettledPnl: BN;
258
+ makerUnsettledPnl: BN;
185
259
  action: OrderAction;
260
+ actionExplanation: OrderActionExplanation;
186
261
  filler: PublicKey;
187
262
  fillRecordId: BN;
188
263
  marketIndex: BN;
@@ -235,9 +310,9 @@ export declare type MarketAccount = {
235
310
  openInterest: BN;
236
311
  marginRatioInitial: number;
237
312
  marginRatioMaintenance: number;
238
- marginRatioPartial: number;
239
313
  nextFillRecordId: BN;
240
314
  pnlPool: PoolBalance;
315
+ liquidationFee: BN;
241
316
  };
242
317
  export declare type BankAccount = {
243
318
  bankIndex: BN;
@@ -260,6 +335,7 @@ export declare type BankAccount = {
260
335
  maintenanceAssetWeight: BN;
261
336
  initialLiabilityWeight: BN;
262
337
  maintenanceLiabilityWeight: BN;
338
+ liquidationFee: BN;
263
339
  };
264
340
  export declare type PoolBalance = {
265
341
  balance: BN;
@@ -274,6 +350,8 @@ export declare type AMM = {
274
350
  lastMarkPriceTwapTs: BN;
275
351
  lastOraclePriceTwap: BN;
276
352
  lastOraclePriceTwapTs: BN;
353
+ lastOracleMarkSpreadPct: BN;
354
+ lastOracleConfPct: BN;
277
355
  oracle: PublicKey;
278
356
  oracleSource: OracleSource;
279
357
  fundingPeriod: BN;
@@ -288,6 +366,8 @@ export declare type AMM = {
288
366
  totalFee: BN;
289
367
  minimumQuoteAssetTradeSize: BN;
290
368
  baseAssetAmountStepSize: BN;
369
+ maxBaseAssetAmountRatio: number;
370
+ maxSlippageRatio: number;
291
371
  lastOraclePrice: BN;
292
372
  baseSpread: number;
293
373
  curveUpdateIntensity: number;
@@ -304,6 +384,7 @@ export declare type AMM = {
304
384
  lastAskPriceTwap: BN;
305
385
  longSpread: BN;
306
386
  shortSpread: BN;
387
+ maxSpread: number;
307
388
  };
308
389
  export declare type UserPosition = {
309
390
  baseAssetAmount: BN;
@@ -332,6 +413,7 @@ export declare type UserAccount = {
332
413
  };
333
414
  positions: UserPosition[];
334
415
  orders: Order[];
416
+ beingLiquidated: boolean;
335
417
  };
336
418
  export declare type UserBankBalance = {
337
419
  bankIndex: BN;
@@ -356,6 +438,7 @@ export declare type Order = {
356
438
  reduceOnly: boolean;
357
439
  triggerPrice: BN;
358
440
  triggerCondition: OrderTriggerCondition;
441
+ triggered: boolean;
359
442
  discountTier: OrderDiscountTier;
360
443
  existingPositionDirection: PositionDirection;
361
444
  referrer: PublicKey;
@@ -370,7 +453,6 @@ export declare type OrderParams = {
370
453
  orderType: OrderType;
371
454
  userOrderId: number;
372
455
  direction: PositionDirection;
373
- quoteAssetAmount: BN;
374
456
  baseAssetAmount: BN;
375
457
  price: BN;
376
458
  marketIndex: BN;
@@ -388,10 +470,50 @@ export declare type OrderParams = {
388
470
  referrer: boolean;
389
471
  };
390
472
  };
473
+ export declare type NecessaryOrderParams = {
474
+ orderType: OrderType;
475
+ marketIndex: BN;
476
+ baseAssetAmount: BN;
477
+ direction: PositionDirection;
478
+ };
479
+ export declare type OptionalOrderParams = {
480
+ [Property in keyof OrderParams]?: OrderParams[Property];
481
+ } & NecessaryOrderParams;
482
+ export declare const DefaultOrderParams: {
483
+ orderType: {
484
+ market: {};
485
+ };
486
+ userOrderId: number;
487
+ direction: {
488
+ long: {};
489
+ };
490
+ baseAssetAmount: BN;
491
+ price: BN;
492
+ marketIndex: BN;
493
+ reduceOnly: boolean;
494
+ postOnly: boolean;
495
+ immediateOrCancel: boolean;
496
+ triggerPrice: BN;
497
+ triggerCondition: {
498
+ above: {};
499
+ };
500
+ positionLimit: BN;
501
+ oraclePriceOffset: BN;
502
+ padding0: BN;
503
+ padding1: BN;
504
+ optionalAccounts: {
505
+ discountToken: boolean;
506
+ referrer: boolean;
507
+ };
508
+ };
391
509
  export declare type MakerInfo = {
392
510
  maker: PublicKey;
393
511
  order: Order;
394
512
  };
513
+ export declare type TakerInfo = {
514
+ taker: PublicKey;
515
+ order: Order;
516
+ };
395
517
  export interface IWallet {
396
518
  signTransaction(tx: Transaction): Promise<Transaction>;
397
519
  signAllTransactions(txs: Transaction[]): Promise<Transaction[]>;
@@ -431,6 +553,7 @@ export declare type FeeStructure = {
431
553
  makerRebateNumerator: BN;
432
554
  makerRebateDenominator: BN;
433
555
  fillerRewardStructure: OrderFillerRewardStructure;
556
+ cancelOrderFee: BN;
434
557
  };
435
558
  export declare type OracleGuardRails = {
436
559
  priceDivergence: {
@@ -449,4 +572,4 @@ export declare type OrderFillerRewardStructure = {
449
572
  rewardDenominator: BN;
450
573
  timeBasedRewardLowerBound: BN;
451
574
  };
452
- export declare type MarginCategory = 'Initial' | 'Partial' | 'Maintenance';
575
+ export declare type MarginCategory = 'Initial' | 'Maintenance';
package/lib/types.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TradeSide = exports.isOneOfVariant = exports.isVariant = exports.OrderTriggerCondition = exports.OrderAction = exports.OrderDiscountTier = exports.OrderStatus = exports.OrderType = exports.OracleSource = exports.PositionDirection = exports.BankBalanceType = exports.SwapDirection = void 0;
3
+ exports.DefaultOrderParams = exports.LiquidationType = exports.TradeSide = exports.isOneOfVariant = exports.isVariant = exports.OrderTriggerCondition = exports.OrderActionExplanation = exports.OrderAction = exports.OrderDiscountTier = exports.OrderStatus = exports.OrderType = exports.OracleSource = exports.DepositDirection = exports.PositionDirection = exports.BankBalanceType = exports.SwapDirection = void 0;
4
+ const _1 = require(".");
4
5
  // # Utility Types / Enums / Constants
5
6
  class SwapDirection {
6
7
  }
@@ -17,6 +18,11 @@ class PositionDirection {
17
18
  exports.PositionDirection = PositionDirection;
18
19
  PositionDirection.LONG = { long: {} };
19
20
  PositionDirection.SHORT = { short: {} };
21
+ class DepositDirection {
22
+ }
23
+ exports.DepositDirection = DepositDirection;
24
+ DepositDirection.DEPOSIT = { deposit: {} };
25
+ DepositDirection.WITHDRAW = { withdraw: {} };
20
26
  class OracleSource {
21
27
  }
22
28
  exports.OracleSource = OracleSource;
@@ -50,6 +56,20 @@ OrderAction.PLACE = { place: {} };
50
56
  OrderAction.CANCEL = { cancel: {} };
51
57
  OrderAction.EXPIRE = { expire: {} };
52
58
  OrderAction.FILL = { fill: {} };
59
+ OrderAction.TRIGGER = { trigger: {} };
60
+ class OrderActionExplanation {
61
+ }
62
+ exports.OrderActionExplanation = OrderActionExplanation;
63
+ OrderActionExplanation.NONE = { none: {} };
64
+ OrderActionExplanation.BREACHED_MARGIN_REQUIREMENT = {
65
+ breachedMarginRequirement: {},
66
+ };
67
+ OrderActionExplanation.ORACLE_PRICE_BREACHED_LIMIT_PRICE = {
68
+ oraclePriceBreachedLimitPrice: {},
69
+ };
70
+ OrderActionExplanation.MARKET_ORDER_FILLED_TO_LIMIT_PRICE = {
71
+ marketOrderFilledToLimitPrice: {},
72
+ };
53
73
  class OrderTriggerCondition {
54
74
  }
55
75
  exports.OrderTriggerCondition = OrderTriggerCondition;
@@ -71,3 +91,35 @@ var TradeSide;
71
91
  TradeSide[TradeSide["Buy"] = 1] = "Buy";
72
92
  TradeSide[TradeSide["Sell"] = 2] = "Sell";
73
93
  })(TradeSide = exports.TradeSide || (exports.TradeSide = {}));
94
+ class LiquidationType {
95
+ }
96
+ exports.LiquidationType = LiquidationType;
97
+ LiquidationType.LIQUIDATE_PERP = { liquidatePerp: {} };
98
+ LiquidationType.LIQUIDATE_BORROW = { liquidateBorrow: {} };
99
+ LiquidationType.LIQUIDATE_BORROW_FOR_PERP_PNL = {
100
+ liquidateBorrowForPerpPnl: {},
101
+ };
102
+ LiquidationType.LIQUIDATE_PERP_PNL_FOR_DEPOSIT = {
103
+ liquidatePerpPnlForDeposit: {},
104
+ };
105
+ exports.DefaultOrderParams = {
106
+ orderType: OrderType.MARKET,
107
+ userOrderId: 0,
108
+ direction: PositionDirection.LONG,
109
+ baseAssetAmount: _1.ZERO,
110
+ price: _1.ZERO,
111
+ marketIndex: _1.ZERO,
112
+ reduceOnly: false,
113
+ postOnly: false,
114
+ immediateOrCancel: false,
115
+ triggerPrice: _1.ZERO,
116
+ triggerCondition: OrderTriggerCondition.ABOVE,
117
+ positionLimit: _1.ZERO,
118
+ oraclePriceOffset: _1.ZERO,
119
+ padding0: _1.ZERO,
120
+ padding1: _1.ZERO,
121
+ optionalAccounts: {
122
+ discountToken: false,
123
+ referrer: false,
124
+ },
125
+ };
@@ -4,7 +4,7 @@ exports.findComputeUnitConsumption = void 0;
4
4
  async function findComputeUnitConsumption(programId, connection, txSignature, commitment = 'confirmed') {
5
5
  const tx = await connection.getTransaction(txSignature, { commitment });
6
6
  const computeUnits = [];
7
- const regex = new RegExp(`Program ${programId.toString()} consumed ([0-9]{0,6}) of 200000 compute units`);
7
+ const regex = new RegExp(`Program ${programId.toString()} consumed ([0-9]{0,6}) of ([0-9]{0,7}) compute units`);
8
8
  tx.meta.logMessages.forEach((logMessage) => {
9
9
  const match = logMessage.match(regex);
10
10
  if (match && match[1]) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "0.2.0-master.0",
3
+ "version": "0.2.0-master.11",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@project-serum/anchor": "0.24.2",
33
- "@pythnetwork/client": "^2.5.1",
33
+ "@pythnetwork/client": "2.5.3",
34
34
  "@solana/spl-token": "^0.1.6",
35
35
  "@solana/web3.js": "1.41.0",
36
36
  "@switchboard-xyz/switchboard-v2": "^0.0.67",
@@ -39,10 +39,10 @@
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/chai": "^4.3.1",
42
+ "@types/jest": "^28.1.3",
42
43
  "@types/mocha": "^9.1.1",
43
44
  "@typescript-eslint/eslint-plugin": "^4.28.0",
44
45
  "@typescript-eslint/parser": "^4.28.0",
45
- "@types/jest": "^28.1.3",
46
46
  "chai": "^4.3.6",
47
47
  "eslint": "^7.29.0",
48
48
  "eslint-config-prettier": "^8.3.0",
@@ -0,0 +1,197 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.BulkAccountLoader = void 0;
13
+ const uuid_1 = require("uuid");
14
+ const promiseTimeout_1 = require("../util/promiseTimeout");
15
+ const GET_MULTIPLE_ACCOUNTS_CHUNK_SIZE = 99;
16
+ const oneMinute = 60 * 1000;
17
+ class BulkAccountLoader {
18
+ constructor(connection, commitment, pollingFrequency) {
19
+ this.accountsToLoad = new Map();
20
+ this.bufferAndSlotMap = new Map();
21
+ this.errorCallbacks = new Map();
22
+ this.lastTimeLoadingPromiseCleared = Date.now();
23
+ this.mostRecentSlot = 0;
24
+ this.connection = connection;
25
+ this.commitment = commitment;
26
+ this.pollingFrequency = pollingFrequency;
27
+ }
28
+ addAccount(publicKey, callback) {
29
+ const existingSize = this.accountsToLoad.size;
30
+ const callbackId = uuid_1.v4();
31
+ const existingAccountToLoad = this.accountsToLoad.get(publicKey.toString());
32
+ if (existingAccountToLoad) {
33
+ existingAccountToLoad.callbacks.set(callbackId, callback);
34
+ }
35
+ else {
36
+ const callbacks = new Map();
37
+ callbacks.set(callbackId, callback);
38
+ const newAccountToLoad = {
39
+ publicKey,
40
+ callbacks,
41
+ };
42
+ this.accountsToLoad.set(publicKey.toString(), newAccountToLoad);
43
+ }
44
+ if (existingSize === 0) {
45
+ this.startPolling();
46
+ }
47
+ // if a new account needs to be polled, remove the cached loadPromise in case client calls load immediately after
48
+ this.loadPromise = undefined;
49
+ return callbackId;
50
+ }
51
+ removeAccount(publicKey, callbackId) {
52
+ const existingAccountToLoad = this.accountsToLoad.get(publicKey.toString());
53
+ if (existingAccountToLoad) {
54
+ existingAccountToLoad.callbacks.delete(callbackId);
55
+ if (existingAccountToLoad.callbacks.size === 0) {
56
+ this.accountsToLoad.delete(existingAccountToLoad.publicKey.toString());
57
+ }
58
+ }
59
+ if (this.accountsToLoad.size === 0) {
60
+ this.stopPolling();
61
+ }
62
+ }
63
+ addErrorCallbacks(callback) {
64
+ const callbackId = uuid_1.v4();
65
+ this.errorCallbacks.set(callbackId, callback);
66
+ return callbackId;
67
+ }
68
+ removeErrorCallbacks(callbackId) {
69
+ this.errorCallbacks.delete(callbackId);
70
+ }
71
+ chunks(array, size) {
72
+ return new Array(Math.ceil(array.length / size))
73
+ .fill(null)
74
+ .map((_, index) => index * size)
75
+ .map((begin) => array.slice(begin, begin + size));
76
+ }
77
+ load() {
78
+ return __awaiter(this, void 0, void 0, function* () {
79
+ if (this.loadPromise) {
80
+ const now = Date.now();
81
+ if (now - this.lastTimeLoadingPromiseCleared > oneMinute) {
82
+ this.loadPromise = undefined;
83
+ }
84
+ else {
85
+ return this.loadPromise;
86
+ }
87
+ }
88
+ this.loadPromise = new Promise((resolver) => {
89
+ this.loadPromiseResolver = resolver;
90
+ });
91
+ this.lastTimeLoadingPromiseCleared = Date.now();
92
+ try {
93
+ const chunks = this.chunks(Array.from(this.accountsToLoad.values()), GET_MULTIPLE_ACCOUNTS_CHUNK_SIZE);
94
+ yield Promise.all(chunks.map((chunk) => {
95
+ return this.loadChunk(chunk);
96
+ }));
97
+ }
98
+ catch (e) {
99
+ console.error(`Error in bulkAccountLoader.load()`);
100
+ console.error(e);
101
+ for (const [_, callback] of this.errorCallbacks) {
102
+ callback(e);
103
+ }
104
+ }
105
+ finally {
106
+ this.loadPromiseResolver();
107
+ this.loadPromise = undefined;
108
+ }
109
+ });
110
+ }
111
+ loadChunk(accountsToLoad) {
112
+ return __awaiter(this, void 0, void 0, function* () {
113
+ if (accountsToLoad.length === 0) {
114
+ return;
115
+ }
116
+ const args = [
117
+ accountsToLoad.map((accountToLoad) => {
118
+ return accountToLoad.publicKey.toBase58();
119
+ }),
120
+ { commitment: this.commitment },
121
+ ];
122
+ const rpcResponse = yield promiseTimeout_1.promiseTimeout(
123
+ // @ts-ignore
124
+ this.connection._rpcRequest('getMultipleAccounts', args), 10 * 1000 // 30 second timeout
125
+ );
126
+ if (rpcResponse === null) {
127
+ this.log('request to rpc timed out');
128
+ return;
129
+ }
130
+ const newSlot = rpcResponse.result.context.slot;
131
+ if (newSlot > this.mostRecentSlot) {
132
+ this.mostRecentSlot = newSlot;
133
+ }
134
+ for (const i in accountsToLoad) {
135
+ const accountToLoad = accountsToLoad[i];
136
+ const key = accountToLoad.publicKey.toString();
137
+ const oldRPCResponse = this.bufferAndSlotMap.get(key);
138
+ let newBuffer = undefined;
139
+ if (rpcResponse.result.value[i]) {
140
+ const raw = rpcResponse.result.value[i].data[0];
141
+ const dataType = rpcResponse.result.value[i].data[1];
142
+ newBuffer = Buffer.from(raw, dataType);
143
+ }
144
+ if (!oldRPCResponse) {
145
+ this.bufferAndSlotMap.set(key, {
146
+ slot: newSlot,
147
+ buffer: newBuffer,
148
+ });
149
+ this.handleAccountCallbacks(accountToLoad, newBuffer, newSlot);
150
+ continue;
151
+ }
152
+ if (newSlot <= oldRPCResponse.slot) {
153
+ continue;
154
+ }
155
+ const oldBuffer = oldRPCResponse.buffer;
156
+ if (newBuffer && (!oldBuffer || !newBuffer.equals(oldBuffer))) {
157
+ this.bufferAndSlotMap.set(key, {
158
+ slot: newSlot,
159
+ buffer: newBuffer,
160
+ });
161
+ this.handleAccountCallbacks(accountToLoad, newBuffer, newSlot);
162
+ }
163
+ }
164
+ });
165
+ }
166
+ handleAccountCallbacks(accountToLoad, buffer, slot) {
167
+ for (const [_, callback] of accountToLoad.callbacks) {
168
+ callback(buffer, slot);
169
+ }
170
+ }
171
+ getBufferAndSlot(publicKey) {
172
+ return this.bufferAndSlotMap.get(publicKey.toString());
173
+ }
174
+ startPolling() {
175
+ if (this.intervalId) {
176
+ return;
177
+ }
178
+ this.intervalId = setInterval(this.load.bind(this), this.pollingFrequency);
179
+ }
180
+ stopPolling() {
181
+ if (this.intervalId) {
182
+ clearInterval(this.intervalId);
183
+ this.intervalId = undefined;
184
+ }
185
+ }
186
+ log(msg) {
187
+ console.log(msg);
188
+ }
189
+ updatePollingFrequency(pollingFrequency) {
190
+ this.stopPolling();
191
+ this.pollingFrequency = pollingFrequency;
192
+ if (this.accountsToLoad.size > 0) {
193
+ this.startPolling();
194
+ }
195
+ }
196
+ }
197
+ exports.BulkAccountLoader = BulkAccountLoader;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.bulkPollingUserSubscribe = void 0;
13
+ /**
14
+ * @param users
15
+ * @param accountLoader
16
+ */
17
+ function bulkPollingUserSubscribe(users, accountLoader) {
18
+ return __awaiter(this, void 0, void 0, function* () {
19
+ if (users.length === 0) {
20
+ yield accountLoader.load();
21
+ return;
22
+ }
23
+ yield Promise.all(users.map((user) => {
24
+ // Pull the keys from the authority map so we can skip fetching them in addToAccountLoader
25
+ return user.accountSubscriber.addToAccountLoader();
26
+ }));
27
+ yield accountLoader.load();
28
+ yield Promise.all(users.map((user) => __awaiter(this, void 0, void 0, function* () {
29
+ return user.subscribe();
30
+ })));
31
+ });
32
+ }
33
+ exports.bulkPollingUserSubscribe = bulkPollingUserSubscribe;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.fetchUserAccounts = void 0;
13
+ const pda_1 = require("../addresses/pda");
14
+ function fetchUserAccounts(connection, program, authority, limit = 8) {
15
+ return __awaiter(this, void 0, void 0, function* () {
16
+ const userAccountPublicKeys = new Array();
17
+ for (let i = 0; i < limit; i++) {
18
+ userAccountPublicKeys.push(yield pda_1.getUserAccountPublicKey(program.programId, authority, i));
19
+ }
20
+ const accountInfos = yield connection.getMultipleAccountsInfo(userAccountPublicKeys, 'confirmed');
21
+ return accountInfos.map((accountInfo) => {
22
+ if (!accountInfo) {
23
+ return undefined;
24
+ }
25
+ return program.account.user.coder.accounts.decode('User', accountInfo.data);
26
+ });
27
+ });
28
+ }
29
+ exports.fetchUserAccounts = fetchUserAccounts;