@drift-labs/sdk 0.2.0-master.22 → 0.2.0-master.25

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 (58) hide show
  1. package/lib/addresses/pda.d.ts +4 -0
  2. package/lib/addresses/pda.js +27 -1
  3. package/lib/admin.d.ts +3 -0
  4. package/lib/admin.js +36 -10
  5. package/lib/clearingHouse.d.ts +11 -2
  6. package/lib/clearingHouse.js +140 -5
  7. package/lib/clearingHouseUser.d.ts +3 -1
  8. package/lib/clearingHouseUser.js +11 -9
  9. package/lib/config.js +1 -1
  10. package/lib/constants/banks.d.ts +2 -0
  11. package/lib/constants/banks.js +9 -0
  12. package/lib/constants/numericConstants.d.ts +2 -0
  13. package/lib/constants/numericConstants.js +4 -1
  14. package/lib/events/eventSubscriber.d.ts +4 -2
  15. package/lib/events/eventSubscriber.js +16 -9
  16. package/lib/events/fetchLogs.d.ts +10 -1
  17. package/lib/events/fetchLogs.js +27 -7
  18. package/lib/events/pollingLogProvider.d.ts +2 -1
  19. package/lib/events/pollingLogProvider.js +6 -2
  20. package/lib/events/sort.js +7 -10
  21. package/lib/events/types.d.ts +4 -2
  22. package/lib/events/types.js +2 -0
  23. package/lib/examples/makeTradeExample.js +13 -1
  24. package/lib/idl/clearing_house.json +1081 -173
  25. package/lib/index.d.ts +2 -0
  26. package/lib/index.js +2 -0
  27. package/lib/math/amm.d.ts +3 -1
  28. package/lib/math/amm.js +41 -3
  29. package/lib/math/insurance.d.ts +4 -0
  30. package/lib/math/insurance.js +27 -0
  31. package/lib/math/margin.d.ts +1 -1
  32. package/lib/math/margin.js +5 -7
  33. package/lib/math/position.js +1 -1
  34. package/lib/types.d.ts +79 -24
  35. package/lib/types.js +7 -4
  36. package/package.json +1 -1
  37. package/src/addresses/pda.ts +56 -0
  38. package/src/admin.ts +64 -18
  39. package/src/clearingHouse.ts +230 -10
  40. package/src/clearingHouseUser.ts +16 -11
  41. package/src/config.ts +1 -1
  42. package/src/constants/banks.ts +16 -0
  43. package/src/constants/numericConstants.ts +4 -0
  44. package/src/events/eventSubscriber.ts +20 -12
  45. package/src/events/fetchLogs.ts +35 -8
  46. package/src/events/pollingLogProvider.ts +10 -2
  47. package/src/events/sort.ts +10 -14
  48. package/src/events/types.ts +7 -1
  49. package/src/examples/makeTradeExample.ts +20 -1
  50. package/src/idl/clearing_house.json +1081 -173
  51. package/src/index.ts +2 -0
  52. package/src/math/amm.ts +67 -2
  53. package/src/math/insurance.ts +35 -0
  54. package/src/math/margin.ts +3 -10
  55. package/src/math/position.ts +2 -2
  56. package/src/types.ts +83 -24
  57. package/src/events/eventSubscriber.js +0 -139
  58. package/src/events/sort.js +0 -44
@@ -39,7 +39,9 @@ import { TokenFaucet } from './tokenFaucet';
39
39
  import { EventEmitter } from 'events';
40
40
  import StrictEventEmitter from 'strict-event-emitter-types';
41
41
  import {
42
+ getClearingHouseSignerPublicKey,
42
43
  getClearingHouseStateAccountPublicKey,
44
+ getInsuranceFundStakeAccountPublicKey,
43
45
  getMarketPublicKey,
44
46
  getUserAccountPublicKey,
45
47
  getUserAccountPublicKeySync,
@@ -259,6 +261,17 @@ export class ClearingHouse {
259
261
  return this.statePublicKey;
260
262
  }
261
263
 
264
+ signerPublicKey?: PublicKey;
265
+ public getSignerPublicKey(): PublicKey {
266
+ if (this.signerPublicKey) {
267
+ return this.signerPublicKey;
268
+ }
269
+ this.signerPublicKey = getClearingHouseSignerPublicKey(
270
+ this.program.programId
271
+ );
272
+ return this.signerPublicKey;
273
+ }
274
+
262
275
  public getStateAccount(): StateAccount {
263
276
  return this.accountSubscriber.getStateAccountAndSlot().data;
264
277
  }
@@ -1063,7 +1076,7 @@ export class ClearingHouse {
1063
1076
  state: await this.getStatePublicKey(),
1064
1077
  bank: bank.pubkey,
1065
1078
  bankVault: bank.vault,
1066
- bankVaultAuthority: bank.vaultAuthority,
1079
+ clearingHouseSigner: this.getSignerPublicKey(),
1067
1080
  user: userAccountPublicKey,
1068
1081
  userStats: this.getUserStatsAccountPublicKey(),
1069
1082
  userTokenAccount: userTokenAccount,
@@ -2175,6 +2188,7 @@ export class ClearingHouse {
2175
2188
  public async resolvePerpBankruptcy(
2176
2189
  userAccountPublicKey: PublicKey,
2177
2190
  userAccount: UserAccount,
2191
+ bankIndex: BN,
2178
2192
  marketIndex: BN
2179
2193
  ): Promise<TransactionSignature> {
2180
2194
  const { txSig } = await this.txSender.send(
@@ -2182,6 +2196,7 @@ export class ClearingHouse {
2182
2196
  await this.getResolvePerpBankruptcyIx(
2183
2197
  userAccountPublicKey,
2184
2198
  userAccount,
2199
+ bankIndex,
2185
2200
  marketIndex
2186
2201
  )
2187
2202
  ),
@@ -2194,24 +2209,36 @@ export class ClearingHouse {
2194
2209
  public async getResolvePerpBankruptcyIx(
2195
2210
  userAccountPublicKey: PublicKey,
2196
2211
  userAccount: UserAccount,
2212
+ bankIndex: BN,
2197
2213
  marketIndex: BN
2198
2214
  ): Promise<TransactionInstruction> {
2199
2215
  const liquidatorPublicKey = await this.getUserAccountPublicKey();
2200
2216
 
2201
2217
  const remainingAccounts = this.getRemainingAccountsWithCounterparty({
2202
2218
  writableMarketIndex: marketIndex,
2219
+ writableBankIndexes: [bankIndex],
2203
2220
  counterPartyUserAccount: userAccount,
2204
2221
  });
2205
2222
 
2206
- return await this.program.instruction.resolvePerpBankruptcy(marketIndex, {
2207
- accounts: {
2208
- state: await this.getStatePublicKey(),
2209
- authority: this.wallet.publicKey,
2210
- user: userAccountPublicKey,
2211
- liquidator: liquidatorPublicKey,
2212
- },
2213
- remainingAccounts: remainingAccounts,
2214
- });
2223
+ const bank = this.getBankAccount(bankIndex);
2224
+
2225
+ return await this.program.instruction.resolvePerpBankruptcy(
2226
+ bankIndex,
2227
+ marketIndex,
2228
+ {
2229
+ accounts: {
2230
+ state: await this.getStatePublicKey(),
2231
+ authority: this.wallet.publicKey,
2232
+ user: userAccountPublicKey,
2233
+ liquidator: liquidatorPublicKey,
2234
+ bankVault: bank.vault,
2235
+ insuranceFundVault: bank.insuranceFundVault,
2236
+ clearingHouseSigner: this.getSignerPublicKey(),
2237
+ tokenProgram: TOKEN_PROGRAM_ID,
2238
+ },
2239
+ remainingAccounts: remainingAccounts,
2240
+ }
2241
+ );
2215
2242
  }
2216
2243
 
2217
2244
  public async resolveBorrowBankruptcy(
@@ -2245,12 +2272,18 @@ export class ClearingHouse {
2245
2272
  counterPartyUserAccount: userAccount,
2246
2273
  });
2247
2274
 
2275
+ const bank = this.getBankAccount(bankIndex);
2276
+
2248
2277
  return await this.program.instruction.resolveBorrowBankruptcy(bankIndex, {
2249
2278
  accounts: {
2250
2279
  state: await this.getStatePublicKey(),
2251
2280
  authority: this.wallet.publicKey,
2252
2281
  user: userAccountPublicKey,
2253
2282
  liquidator: liquidatorPublicKey,
2283
+ bankVault: bank.vault,
2284
+ insuranceFundVault: bank.insuranceFundVault,
2285
+ clearingHouseSigner: this.getSignerPublicKey(),
2286
+ tokenProgram: TOKEN_PROGRAM_ID,
2254
2287
  },
2255
2288
  remainingAccounts: remainingAccounts,
2256
2289
  });
@@ -2480,4 +2513,191 @@ export class ClearingHouse {
2480
2513
 
2481
2514
  return oracleData;
2482
2515
  }
2516
+
2517
+ public async initializeInsuranceFundStake(
2518
+ bankIndex: BN
2519
+ ): Promise<TransactionSignature> {
2520
+ const { txSig } = await this.txSender.send(
2521
+ wrapInTx(await this.getInitializeInsuranceFundStakeIx(bankIndex)),
2522
+ [],
2523
+ this.opts
2524
+ );
2525
+ return txSig;
2526
+ }
2527
+
2528
+ public async getInitializeInsuranceFundStakeIx(
2529
+ bankIndex: BN
2530
+ ): Promise<TransactionInstruction> {
2531
+ const ifStakeAccountPublicKey = getInsuranceFundStakeAccountPublicKey(
2532
+ this.program.programId,
2533
+ this.wallet.publicKey,
2534
+ bankIndex
2535
+ );
2536
+
2537
+ return await this.program.instruction.initializeInsuranceFundStake(
2538
+ bankIndex,
2539
+ {
2540
+ accounts: {
2541
+ insuranceFundStake: ifStakeAccountPublicKey,
2542
+ bank: this.getBankAccount(bankIndex).pubkey,
2543
+ userStats: this.getUserStatsAccountPublicKey(),
2544
+ authority: this.wallet.publicKey,
2545
+ payer: this.wallet.publicKey,
2546
+ rent: anchor.web3.SYSVAR_RENT_PUBKEY,
2547
+ systemProgram: anchor.web3.SystemProgram.programId,
2548
+ state: await this.getStatePublicKey(),
2549
+ },
2550
+ }
2551
+ );
2552
+ }
2553
+
2554
+ public async addInsuranceFundStake(
2555
+ bankIndex: BN,
2556
+ amount: BN,
2557
+ collateralAccountPublicKey: PublicKey
2558
+ ): Promise<TransactionSignature> {
2559
+ const bank = this.getBankAccount(bankIndex);
2560
+ const ifStakeAccountPublicKey = getInsuranceFundStakeAccountPublicKey(
2561
+ this.program.programId,
2562
+ this.wallet.publicKey,
2563
+ bankIndex
2564
+ );
2565
+
2566
+ const remainingAccounts = this.getRemainingAccounts({
2567
+ writableBankIndex: bankIndex,
2568
+ });
2569
+
2570
+ return await this.program.rpc.addInsuranceFundStake(bankIndex, amount, {
2571
+ accounts: {
2572
+ state: await this.getStatePublicKey(),
2573
+ bank: bank.pubkey,
2574
+ insuranceFundStake: ifStakeAccountPublicKey,
2575
+ userStats: this.getUserStatsAccountPublicKey(),
2576
+ authority: this.wallet.publicKey,
2577
+ insuranceFundVault: bank.insuranceFundVault,
2578
+ userTokenAccount: collateralAccountPublicKey,
2579
+ tokenProgram: TOKEN_PROGRAM_ID,
2580
+ },
2581
+ remainingAccounts,
2582
+ });
2583
+ }
2584
+
2585
+ public async requestRemoveInsuranceFundStake(
2586
+ bankIndex: BN,
2587
+ amount: BN
2588
+ ): Promise<TransactionSignature> {
2589
+ const bank = this.getBankAccount(bankIndex);
2590
+ const ifStakeAccountPublicKey = getInsuranceFundStakeAccountPublicKey(
2591
+ this.program.programId,
2592
+ this.wallet.publicKey,
2593
+ bankIndex
2594
+ );
2595
+
2596
+ const remainingAccounts = this.getRemainingAccounts({
2597
+ writableBankIndex: bankIndex,
2598
+ });
2599
+
2600
+ return await this.program.rpc.requestRemoveInsuranceFundStake(
2601
+ bankIndex,
2602
+ amount,
2603
+ {
2604
+ accounts: {
2605
+ state: await this.getStatePublicKey(),
2606
+ bank: bank.pubkey,
2607
+ insuranceFundStake: ifStakeAccountPublicKey,
2608
+ userStats: this.getUserStatsAccountPublicKey(),
2609
+ authority: this.wallet.publicKey,
2610
+ insuranceFundVault: bank.insuranceFundVault,
2611
+ // userTokenAccount: collateralAccountPublicKey,
2612
+ // tokenProgram: TOKEN_PROGRAM_ID,
2613
+ },
2614
+ remainingAccounts,
2615
+ }
2616
+ );
2617
+ }
2618
+
2619
+ public async cancelRequestRemoveInsuranceFundStake(
2620
+ bankIndex: BN
2621
+ ): Promise<TransactionSignature> {
2622
+ const bank = this.getBankAccount(bankIndex);
2623
+ const ifStakeAccountPublicKey = getInsuranceFundStakeAccountPublicKey(
2624
+ this.program.programId,
2625
+ this.wallet.publicKey,
2626
+ bankIndex
2627
+ );
2628
+
2629
+ const remainingAccounts = this.getRemainingAccounts({
2630
+ writableBankIndex: bankIndex,
2631
+ });
2632
+
2633
+ return await this.program.rpc.cancelRequestRemoveInsuranceFundStake(
2634
+ bankIndex,
2635
+ {
2636
+ accounts: {
2637
+ state: await this.getStatePublicKey(),
2638
+ bank: bank.pubkey,
2639
+ insuranceFundStake: ifStakeAccountPublicKey,
2640
+ userStats: this.getUserStatsAccountPublicKey(),
2641
+ authority: this.wallet.publicKey,
2642
+ insuranceFundVault: bank.insuranceFundVault,
2643
+ // userTokenAccount: collateralAccountPublicKey,
2644
+ // tokenProgram: TOKEN_PROGRAM_ID,
2645
+ },
2646
+ remainingAccounts,
2647
+ }
2648
+ );
2649
+ }
2650
+
2651
+ public async removeInsuranceFundStake(
2652
+ bankIndex: BN,
2653
+ collateralAccountPublicKey: PublicKey
2654
+ ): Promise<TransactionSignature> {
2655
+ const bank = this.getBankAccount(bankIndex);
2656
+ const ifStakeAccountPublicKey = getInsuranceFundStakeAccountPublicKey(
2657
+ this.program.programId,
2658
+ this.wallet.publicKey,
2659
+ bankIndex
2660
+ );
2661
+
2662
+ const remainingAccounts = this.getRemainingAccounts({
2663
+ writableBankIndex: bankIndex,
2664
+ });
2665
+
2666
+ return await this.program.rpc.removeInsuranceFundStake(bankIndex, {
2667
+ accounts: {
2668
+ state: await this.getStatePublicKey(),
2669
+ bank: bank.pubkey,
2670
+ insuranceFundStake: ifStakeAccountPublicKey,
2671
+ userStats: this.getUserStatsAccountPublicKey(),
2672
+ authority: this.wallet.publicKey,
2673
+ insuranceFundVault: bank.insuranceFundVault,
2674
+ clearingHouseSigner: this.getSignerPublicKey(),
2675
+ userTokenAccount: collateralAccountPublicKey,
2676
+ tokenProgram: TOKEN_PROGRAM_ID,
2677
+ },
2678
+ remainingAccounts,
2679
+ });
2680
+ }
2681
+
2682
+ public async settleRevenueToInsuranceFund(
2683
+ bankIndex: BN
2684
+ ): Promise<TransactionSignature> {
2685
+ const bank = this.getBankAccount(bankIndex);
2686
+
2687
+ const remainingAccounts = this.getRemainingAccounts({
2688
+ writableBankIndex: bankIndex,
2689
+ });
2690
+
2691
+ return await this.program.rpc.settleRevenueToInsuranceFund(bankIndex, {
2692
+ accounts: {
2693
+ state: await this.getStatePublicKey(),
2694
+ bank: bank.pubkey,
2695
+ bankVault: bank.vault,
2696
+ clearingHouseSigner: this.getSignerPublicKey(),
2697
+ insuranceFundVault: bank.insuranceFundVault,
2698
+ tokenProgram: TOKEN_PROGRAM_ID,
2699
+ },
2700
+ remainingAccounts,
2701
+ });
2702
+ }
2483
2703
  }
@@ -46,7 +46,7 @@ import {
46
46
  calculateLiabilityWeight,
47
47
  } from './math/bankBalance';
48
48
  import {
49
- calculateMarginBaseAssetValue,
49
+ calculateBaseAssetValueWithOracle,
50
50
  calculateWorstCaseBaseAssetAmount,
51
51
  } from './math/margin';
52
52
  import { OraclePriceData } from './oracles/types';
@@ -183,7 +183,9 @@ export class ClearingHouseUser {
183
183
 
184
184
  /**
185
185
  * calculates the market position if the lp position was settled
186
- * @returns : userPosition
186
+ * @returns : the settled userPosition
187
+ * @returns : the dust base asset amount (ie, < stepsize)
188
+ * @returns : pnl from settle
187
189
  */
188
190
  public getSettledLPPosition(marketIndex: BN): [UserPosition, BN, BN] {
189
191
  const _position = this.getUserPosition(marketIndex);
@@ -224,9 +226,6 @@ export class ClearingHouseUser {
224
226
 
225
227
  const reaminderPerLP = remainderBaa.mul(AMM_RESERVE_PRECISION).div(nShares);
226
228
 
227
- position.baseAssetAmount = position.baseAssetAmount.add(standardizedBaa);
228
- position.quoteAssetAmount = position.quoteAssetAmount.add(deltaQaa);
229
-
230
229
  position.lastNetBaseAssetAmountPerLp =
231
230
  market.amm.marketPositionPerLp.baseAssetAmount.sub(reaminderPerLP);
232
231
 
@@ -254,7 +253,7 @@ export class ClearingHouseUser {
254
253
  .mul(deltaBaa.abs())
255
254
  .div(position.baseAssetAmount.abs())
256
255
  );
257
- pnl = position.quoteEntryAmount.sub(newQuoteEntry);
256
+ pnl = position.quoteEntryAmount.sub(newQuoteEntry).add(deltaQaa);
258
257
  } else {
259
258
  newQuoteEntry = deltaQaa.sub(
260
259
  deltaQaa.mul(position.baseAssetAmount.abs()).div(deltaBaa.abs())
@@ -262,6 +261,8 @@ export class ClearingHouseUser {
262
261
  pnl = position.quoteEntryAmount.add(deltaQaa.sub(newQuoteEntry));
263
262
  }
264
263
  position.quoteEntryAmount = newQuoteEntry;
264
+ position.baseAssetAmount = position.baseAssetAmount.add(standardizedBaa);
265
+ position.quoteAssetAmount = position.quoteAssetAmount.add(deltaQaa);
265
266
 
266
267
  if (position.baseAssetAmount.gt(ZERO)) {
267
268
  position.lastCumulativeFundingRate = market.amm.cumulativeFundingRateLong;
@@ -568,7 +569,7 @@ export class ClearingHouseUser {
568
569
  const market = this.clearingHouse.getMarketAccount(
569
570
  marketPosition.marketIndex
570
571
  );
571
- const posVal = calculateMarginBaseAssetValue(
572
+ const posVal = calculateBaseAssetValueWithOracle(
572
573
  market,
573
574
  marketPosition,
574
575
  this.getOracleDataForMarket(market.marketIndex)
@@ -593,7 +594,11 @@ export class ClearingHouseUser {
593
594
  const market = this.clearingHouse.getMarketAccount(
594
595
  userPosition.marketIndex
595
596
  );
596
- return calculateMarginBaseAssetValue(market, userPosition, oraclePriceData);
597
+ return calculateBaseAssetValueWithOracle(
598
+ market,
599
+ userPosition,
600
+ oraclePriceData
601
+ );
597
602
  }
598
603
 
599
604
  public getPositionSide(
@@ -644,7 +649,7 @@ export class ClearingHouseUser {
644
649
  oraclePriceData
645
650
  );
646
651
  } else {
647
- baseAssetValue = calculateMarginBaseAssetValue(
652
+ baseAssetValue = calculateBaseAssetValueWithOracle(
648
653
  market,
649
654
  position,
650
655
  oraclePriceData
@@ -818,7 +823,7 @@ export class ClearingHouseUser {
818
823
  proposedMarketPosition.marketIndex
819
824
  );
820
825
 
821
- const proposedMarketPositionValue = calculateMarginBaseAssetValue(
826
+ const proposedMarketPositionValue = calculateBaseAssetValueWithOracle(
822
827
  market,
823
828
  proposedMarketPosition,
824
829
  this.getOracleDataForMarket(market.marketIndex)
@@ -835,7 +840,7 @@ export class ClearingHouseUser {
835
840
  const market = this.clearingHouse.getMarketAccount(
836
841
  position.marketIndex
837
842
  );
838
- const positionValue = calculateMarginBaseAssetValue(
843
+ const positionValue = calculateBaseAssetValueWithOracle(
839
844
  market,
840
845
  position,
841
846
  this.getOracleDataForMarket(market.marketIndex)
package/src/config.ts CHANGED
@@ -28,7 +28,7 @@ export const configs: { [key in DriftEnv]: DriftConfig } = {
28
28
  devnet: {
29
29
  ENV: 'devnet',
30
30
  PYTH_ORACLE_MAPPING_ADDRESS: 'BmA9Z6FjioHJPpjT39QazZyhDRUdZy2ezwx4GiDdE2u2',
31
- CLEARING_HOUSE_PROGRAM_ID: '65sz7dRiWDRPZjiRxcTxPM7AE6VK4Nag9HEK6oBJXhJn',
31
+ CLEARING_HOUSE_PROGRAM_ID: '3v1iEjbSSLSSYyt1pmx4UB5rqJGurmz71RibXF7X6UF3',
32
32
  USDC_MINT_ADDRESS: '8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2',
33
33
  MARKETS: DevnetMarkets,
34
34
  BANKS: DevnetBanks,
@@ -1,5 +1,11 @@
1
1
  import { PublicKey } from '@solana/web3.js';
2
2
  import { BN, DriftEnv, OracleSource } from '../';
3
+ import {
4
+ BANK_BALANCE_PRECISION,
5
+ BANK_BALANCE_PRECISION_EXP,
6
+ LAMPORTS_EXP,
7
+ LAMPORTS_PRECISION,
8
+ } from './numericConstants';
3
9
 
4
10
  export type BankConfig = {
5
11
  symbol: string;
@@ -7,6 +13,8 @@ export type BankConfig = {
7
13
  oracle: PublicKey;
8
14
  mint: PublicKey;
9
15
  oracleSource: OracleSource;
16
+ precision: BN;
17
+ precisionExp: BN;
10
18
  };
11
19
 
12
20
  export const WRAPPED_SOL_MINT = new PublicKey(
@@ -20,6 +28,8 @@ export const DevnetBanks: BankConfig[] = [
20
28
  oracle: PublicKey.default,
21
29
  oracleSource: OracleSource.QUOTE_ASSET,
22
30
  mint: new PublicKey('8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2'),
31
+ precision: BANK_BALANCE_PRECISION,
32
+ precisionExp: BANK_BALANCE_PRECISION_EXP,
23
33
  },
24
34
  {
25
35
  symbol: 'SOL',
@@ -27,6 +37,8 @@ export const DevnetBanks: BankConfig[] = [
27
37
  oracle: new PublicKey('J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix'),
28
38
  oracleSource: OracleSource.PYTH,
29
39
  mint: new PublicKey(WRAPPED_SOL_MINT),
40
+ precision: LAMPORTS_PRECISION,
41
+ precisionExp: LAMPORTS_EXP,
30
42
  },
31
43
  {
32
44
  symbol: 'BTC',
@@ -34,6 +46,8 @@ export const DevnetBanks: BankConfig[] = [
34
46
  oracle: new PublicKey('HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J'),
35
47
  oracleSource: OracleSource.PYTH,
36
48
  mint: new PublicKey('3BZPwbcqB5kKScF3TEXxwNfx5ipV13kbRVDvfVp5c6fv'),
49
+ precision: BANK_BALANCE_PRECISION,
50
+ precisionExp: BANK_BALANCE_PRECISION_EXP,
37
51
  },
38
52
  ];
39
53
 
@@ -44,6 +58,8 @@ export const MainnetBanks: BankConfig[] = [
44
58
  oracle: PublicKey.default,
45
59
  oracleSource: OracleSource.QUOTE_ASSET,
46
60
  mint: new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'),
61
+ precision: BANK_BALANCE_PRECISION,
62
+ precisionExp: BANK_BALANCE_PRECISION_EXP,
47
63
  },
48
64
  ];
49
65
 
@@ -1,3 +1,4 @@
1
+ import { LAMPORTS_PER_SOL } from '@solana/web3.js';
1
2
  import { BN } from '../';
2
3
 
3
4
  export const ZERO = new BN(0);
@@ -66,3 +67,6 @@ export const BID_ASK_SPREAD_PRECISION = new BN(1000000);
66
67
  export const ONE_YEAR = new BN(31536000);
67
68
 
68
69
  export const QUOTE_ASSET_BANK_INDEX = new BN(0);
70
+
71
+ export const LAMPORTS_PRECISION = new BN(LAMPORTS_PER_SOL);
72
+ export const LAMPORTS_EXP = new BN(Math.log10(LAMPORTS_PER_SOL));
@@ -25,6 +25,8 @@ export class EventSubscriber {
25
25
  private awaitTxResolver = new Map<string, () => void>();
26
26
  private logProvider: LogProvider;
27
27
  public eventEmitter: StrictEventEmitter<EventEmitter, EventSubscriberEvents>;
28
+ private lastSeenSlot: number;
29
+ public lastSeenTxSig: string;
28
30
 
29
31
  public constructor(
30
32
  private connection: Connection,
@@ -62,19 +64,22 @@ export class EventSubscriber {
62
64
  }
63
65
  }
64
66
 
65
- public subscribe(): boolean {
66
- if (this.logProvider.isSubscribed()) {
67
- return true;
68
- }
67
+ public async subscribe(): Promise<boolean> {
68
+ try {
69
+ if (this.logProvider.isSubscribed()) {
70
+ return true;
71
+ }
69
72
 
70
- this.fetchPreviousTx().catch((e) => {
73
+ this.logProvider.subscribe((txSig, slot, logs) => {
74
+ this.handleTxLogs(txSig, slot, logs);
75
+ }, true);
76
+
77
+ return true;
78
+ } catch (e) {
71
79
  console.error('Error fetching previous txs in event subscriber');
72
80
  console.error(e);
73
- });
74
-
75
- return this.logProvider.subscribe((txSig, slot, logs) => {
76
- this.handleTxLogs(txSig, slot, logs);
77
- });
81
+ return false;
82
+ }
78
83
  }
79
84
 
80
85
  private handleTxLogs(
@@ -98,11 +103,14 @@ export class EventSubscriber {
98
103
  this.awaitTxResolver.delete(txSig);
99
104
  }
100
105
 
106
+ if (slot > this.lastSeenSlot) {
107
+ this.lastSeenTxSig = txSig;
108
+ }
101
109
  this.txEventCache.add(txSig, wrappedEvents);
102
110
  }
103
111
 
104
- private async fetchPreviousTx(): Promise<void> {
105
- if (!this.options.untilTx) {
112
+ public async fetchPreviousTx(fetchMax?: boolean): Promise<void> {
113
+ if (!this.options.untilTx && !fetchMax) {
106
114
  return;
107
115
  }
108
116
 
@@ -1,14 +1,18 @@
1
+ import { Program } from '@project-serum/anchor';
1
2
  import {
2
3
  Connection,
3
4
  Finality,
4
5
  PublicKey,
5
6
  TransactionSignature,
6
7
  } from '@solana/web3.js';
8
+ import { WrappedEvents } from './types';
7
9
 
8
10
  type Log = { txSig: TransactionSignature; slot: number; logs: string[] };
9
11
  type FetchLogsResponse = {
10
12
  earliestTx: string;
11
13
  mostRecentTx: string;
14
+ earliestSlot: number;
15
+ mostRecentSlot: number;
12
16
  transactionLogs: Log[];
13
17
  };
14
18
 
@@ -17,19 +21,21 @@ export async function fetchLogs(
17
21
  programId: PublicKey,
18
22
  finality: Finality,
19
23
  beforeTx?: TransactionSignature,
20
- untilTx?: TransactionSignature
21
- ): Promise<FetchLogsResponse | undefined> {
24
+ untilTx?: TransactionSignature,
25
+ limit?: number
26
+ ): Promise<FetchLogsResponse> {
22
27
  const signatures = await connection.getSignaturesForAddress(
23
28
  programId,
24
29
  {
25
30
  before: beforeTx,
26
31
  until: untilTx,
32
+ limit,
27
33
  },
28
34
  finality
29
35
  );
30
36
 
31
37
  const sortedSignatures = signatures.sort((a, b) =>
32
- a.slot < b.slot ? -1 : 1
38
+ a.slot === b.slot ? 0 : a.slot < b.slot ? -1 : 1
33
39
  );
34
40
 
35
41
  const filteredSignatures = sortedSignatures.filter(
@@ -61,14 +67,15 @@ export async function fetchLogs(
61
67
  )
62
68
  ).flat();
63
69
 
64
- const earliestTx = filteredSignatures[0].signature;
65
- const mostRecentTx =
66
- filteredSignatures[filteredSignatures.length - 1].signature;
70
+ const earliest = filteredSignatures[0];
71
+ const mostRecent = filteredSignatures[filteredSignatures.length - 1];
67
72
 
68
73
  return {
69
74
  transactionLogs: transactionLogs,
70
- earliestTx: earliestTx,
71
- mostRecentTx: mostRecentTx,
75
+ earliestTx: earliest.signature,
76
+ mostRecentTx: mostRecent.signature,
77
+ earliestSlot: earliest.slot,
78
+ mostRecentSlot: mostRecent.slot,
72
79
  };
73
80
  }
74
81
 
@@ -78,3 +85,23 @@ function chunk<T>(array: readonly T[], size: number): T[][] {
78
85
  .map((_, index) => index * size)
79
86
  .map((begin) => array.slice(begin, begin + size));
80
87
  }
88
+
89
+ export class LogParser {
90
+ private program: Program;
91
+
92
+ constructor(program: Program) {
93
+ this.program = program;
94
+ }
95
+
96
+ public parseEventsFromLogs(event: Log): WrappedEvents {
97
+ const records: WrappedEvents = [];
98
+ // @ts-ignore
99
+ this.program._events._eventParser.parseLogs(event.logs, (eventLog) => {
100
+ eventLog.data.txSig = event.txSig;
101
+ eventLog.data.slot = event.slot;
102
+ eventLog.data.eventType = eventLog.name;
103
+ records.push(eventLog.data);
104
+ });
105
+ return records;
106
+ }
107
+ }
@@ -13,6 +13,7 @@ export class PollingLogProvider implements LogProvider {
13
13
  private intervalId: NodeJS.Timer;
14
14
  private mostRecentSeenTx?: TransactionSignature;
15
15
  private mutex: number;
16
+ private firstFetch = true;
16
17
 
17
18
  public constructor(
18
19
  private connection: Connection,
@@ -23,7 +24,10 @@ export class PollingLogProvider implements LogProvider {
23
24
  this.finality = commitment === 'finalized' ? 'finalized' : 'confirmed';
24
25
  }
25
26
 
26
- public subscribe(callback: logProviderCallback): boolean {
27
+ public subscribe(
28
+ callback: logProviderCallback,
29
+ skipHistory?: boolean
30
+ ): boolean {
27
31
  if (this.intervalId) {
28
32
  return true;
29
33
  }
@@ -40,9 +44,13 @@ export class PollingLogProvider implements LogProvider {
40
44
  this.programId,
41
45
  this.finality,
42
46
  undefined,
43
- this.mostRecentSeenTx
47
+ this.mostRecentSeenTx,
48
+ // If skipping history, only fetch one log back, not the maximum amount available
49
+ skipHistory && this.firstFetch ? 1 : undefined
44
50
  );
45
51
 
52
+ this.firstFetch = false;
53
+
46
54
  if (response === undefined) {
47
55
  return;
48
56
  }