@drift-labs/sdk 2.26.0-beta.1 → 2.26.0-beta.3

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 (42) hide show
  1. package/lib/config.d.ts +1 -0
  2. package/lib/config.js +2 -0
  3. package/lib/constants/spotMarkets.d.ts +1 -0
  4. package/lib/constants/spotMarkets.js +1 -0
  5. package/lib/dlob/DLOB.d.ts +38 -2
  6. package/lib/dlob/DLOB.js +69 -0
  7. package/lib/dlob/DLOBApiClient.js +1 -1
  8. package/lib/dlob/DLOBSubscriber.d.ts +34 -0
  9. package/lib/dlob/DLOBSubscriber.js +100 -0
  10. package/lib/dlob/orderBookLevels.d.ts +44 -0
  11. package/lib/dlob/orderBookLevels.js +137 -0
  12. package/lib/dlob/types.d.ts +2 -0
  13. package/lib/driftClient.d.ts +28 -10
  14. package/lib/driftClient.js +158 -55
  15. package/lib/driftClientConfig.d.ts +3 -0
  16. package/lib/idl/drift.json +1 -1
  17. package/lib/index.d.ts +1 -0
  18. package/lib/index.js +1 -0
  19. package/lib/serum/serumSubscriber.d.ts +5 -1
  20. package/lib/serum/serumSubscriber.js +22 -0
  21. package/lib/types.d.ts +1 -0
  22. package/package.json +1 -1
  23. package/src/assert/assert.js +9 -0
  24. package/src/config.ts +3 -0
  25. package/src/constants/spotMarkets.ts +4 -0
  26. package/src/dlob/DLOB.ts +177 -17
  27. package/src/dlob/DLOBApiClient.ts +3 -1
  28. package/src/dlob/DLOBSubscriber.ts +141 -0
  29. package/src/dlob/orderBookLevels.ts +243 -0
  30. package/src/dlob/types.ts +2 -0
  31. package/src/driftClient.ts +231 -66
  32. package/src/driftClientConfig.ts +3 -0
  33. package/src/idl/drift.json +1 -1
  34. package/src/index.ts +1 -0
  35. package/src/serum/serumSubscriber.ts +29 -1
  36. package/src/token/index.js +38 -0
  37. package/src/types.ts +1 -0
  38. package/src/util/computeUnits.js +27 -0
  39. package/src/util/getTokenAddress.js +9 -0
  40. package/src/util/promiseTimeout.js +14 -0
  41. package/src/util/tps.js +27 -0
  42. package/tests/dlob/helpers.ts +3 -0
@@ -85,7 +85,7 @@ import { wrapInTx } from './tx/utils';
85
85
  import { QUOTE_SPOT_MARKET_INDEX, ZERO } from './constants/numericConstants';
86
86
  import { findDirectionToClose, positionIsAvailable } from './math/position';
87
87
  import { getTokenAmount } from './math/spotBalance';
88
- import { DEFAULT_USER_NAME, encodeName } from './userName';
88
+ import { decodeName, DEFAULT_USER_NAME, encodeName } from './userName';
89
89
  import { OraclePriceData } from './oracles/types';
90
90
  import { DriftClientConfig } from './driftClientConfig';
91
91
  import { PollingDriftClientAccountSubscriber } from './accounts/pollingDriftClientAccountSubscriber';
@@ -118,9 +118,10 @@ export class DriftClient {
118
118
  public program: Program;
119
119
  provider: AnchorProvider;
120
120
  opts?: ConfirmOptions;
121
- users = new Map<number, User>();
121
+ users = new Map<string, User>();
122
122
  userStats?: UserStats;
123
123
  activeSubAccountId: number;
124
+ activeAuthority: PublicKey;
124
125
  userAccountSubscriptionConfig: UserSubscriptionConfig;
125
126
  accountSubscriber: DriftClientAccountSubscriber;
126
127
  eventEmitter: StrictEventEmitter<EventEmitter, DriftClientAccountEvents>;
@@ -131,6 +132,9 @@ export class DriftClient {
131
132
  authority: PublicKey;
132
133
  marketLookupTable: PublicKey;
133
134
  lookupTableAccount: AddressLookupTableAccount;
135
+ includeDelegates?: boolean;
136
+ authoritySubaccountMap?: Map<string, number[]>;
137
+ skipLoadUsers?: boolean;
134
138
 
135
139
  public get isSubscribed() {
136
140
  return this._isSubscribed && this.accountSubscriber.isSubscribed;
@@ -156,8 +160,35 @@ export class DriftClient {
156
160
  );
157
161
 
158
162
  this.authority = config.authority ?? this.wallet.publicKey;
159
- const subAccountIds = config.subAccountIds ?? [0];
160
- this.activeSubAccountId = config.activeSubAccountId ?? subAccountIds[0];
163
+ this.activeSubAccountId = config.activeSubAccountId ?? 0;
164
+ this.skipLoadUsers = config.skipLoadUsers ?? false;
165
+
166
+ if (config.includeDelegates && config.subAccountIds) {
167
+ throw new Error(
168
+ 'Can only pass one of includeDelegates or subAccountIds. If you want to specify subaccount ids for multiple authorities, pass authoritySubaccountMap instead'
169
+ );
170
+ }
171
+
172
+ if (config.authoritySubaccountMap && config.subAccountIds) {
173
+ throw new Error(
174
+ 'Can only pass one of authoritySubaccountMap or subAccountIds'
175
+ );
176
+ }
177
+
178
+ if (config.authoritySubaccountMap && config.includeDelegates) {
179
+ throw new Error(
180
+ 'Can only pass one of authoritySubaccountMap or includeDelegates'
181
+ );
182
+ }
183
+
184
+ this.authoritySubaccountMap = config.authoritySubaccountMap
185
+ ? config.authoritySubaccountMap
186
+ : config.subAccountIds
187
+ ? new Map([[this.authority.toString(), config.subAccountIds]])
188
+ : new Map<string, number[]>();
189
+
190
+ this.includeDelegates = config.includeDelegates ?? false;
191
+ this.activeAuthority = this.authority;
161
192
  this.userAccountSubscriptionConfig =
162
193
  config.accountSubscription?.type === 'polling'
163
194
  ? {
@@ -167,7 +198,7 @@ export class DriftClient {
167
198
  : {
168
199
  type: 'websocket',
169
200
  };
170
- this.createUsers(subAccountIds, this.userAccountSubscriptionConfig);
201
+
171
202
  if (config.userStats) {
172
203
  this.userStats = new UserStats({
173
204
  driftClient: this,
@@ -229,23 +260,18 @@ export class DriftClient {
229
260
  );
230
261
  }
231
262
 
232
- createUsers(
233
- subAccountIds: number[],
234
- accountSubscriptionConfig: UserSubscriptionConfig
235
- ): void {
236
- for (const subAccountId of subAccountIds) {
237
- const user = this.createUser(subAccountId, accountSubscriptionConfig);
238
- this.users.set(subAccountId, user);
239
- }
263
+ public getUserMapKey(subAccountId: number, authority: PublicKey): string {
264
+ return `${subAccountId}_${authority.toString()}`;
240
265
  }
241
266
 
242
267
  createUser(
243
268
  subAccountId: number,
244
- accountSubscriptionConfig: UserSubscriptionConfig
269
+ accountSubscriptionConfig: UserSubscriptionConfig,
270
+ authority?: PublicKey
245
271
  ): User {
246
272
  const userAccountPublicKey = getUserAccountPublicKeySync(
247
273
  this.program.programId,
248
- this.authority,
274
+ authority ?? this.authority,
249
275
  subAccountId
250
276
  );
251
277
 
@@ -257,15 +283,17 @@ export class DriftClient {
257
283
  }
258
284
 
259
285
  public async subscribe(): Promise<boolean> {
260
- let subscribePromises = this.subscribeUsers().concat(
286
+ let subscribePromises = [this.addAndSubscribeToUsers()].concat(
261
287
  this.accountSubscriber.subscribe()
262
288
  );
289
+
263
290
  if (this.userStats !== undefined) {
264
291
  subscribePromises = subscribePromises.concat(this.userStats.subscribe());
265
292
  }
266
293
  this.isSubscribed = (await Promise.all(subscribePromises)).reduce(
267
294
  (success, prevSuccess) => success && prevSuccess
268
295
  );
296
+
269
297
  return this.isSubscribed;
270
298
  }
271
299
 
@@ -448,12 +476,15 @@ export class DriftClient {
448
476
  * @param newWallet
449
477
  * @param subAccountIds
450
478
  * @param activeSubAccountId
479
+ * @param includeDelegates
451
480
  */
452
481
  public async updateWallet(
453
482
  newWallet: IWallet,
454
- subAccountIds = [0],
455
- activeSubAccountId = 0
456
- ): Promise<void> {
483
+ subAccountIds?: number[],
484
+ activeSubAccountId?: number,
485
+ includeDelegates?: boolean,
486
+ authoritySubaccountMap?: Map<string, number[]>
487
+ ): Promise<boolean> {
457
488
  const newProvider = new AnchorProvider(
458
489
  this.connection,
459
490
  newWallet,
@@ -465,13 +496,42 @@ export class DriftClient {
465
496
  newProvider
466
497
  );
467
498
 
499
+ this.skipLoadUsers = false;
468
500
  // Update provider for txSender with new wallet details
469
501
  this.txSender.provider = newProvider;
470
-
471
502
  this.wallet = newWallet;
472
503
  this.provider = newProvider;
473
504
  this.program = newProgram;
474
505
  this.authority = newWallet.publicKey;
506
+ this.activeSubAccountId = activeSubAccountId;
507
+ this.userStatsAccountPublicKey = undefined;
508
+ this.includeDelegates = includeDelegates ?? false;
509
+
510
+ if (includeDelegates && subAccountIds) {
511
+ throw new Error(
512
+ 'Can only pass one of includeDelegates or subAccountIds. If you want to specify subaccount ids for multiple authorities, pass authoritySubaccountMap instead'
513
+ );
514
+ }
515
+
516
+ if (authoritySubaccountMap && subAccountIds) {
517
+ throw new Error(
518
+ 'Can only pass one of authoritySubaccountMap or subAccountIds'
519
+ );
520
+ }
521
+
522
+ if (authoritySubaccountMap && includeDelegates) {
523
+ throw new Error(
524
+ 'Can only pass one of authoritySubaccountMap or includeDelegates'
525
+ );
526
+ }
527
+
528
+ this.authoritySubaccountMap = authoritySubaccountMap
529
+ ? authoritySubaccountMap
530
+ : subAccountIds
531
+ ? new Map([[this.authority.toString(), subAccountIds]])
532
+ : new Map<string, number[]>();
533
+
534
+ let success = true;
475
535
 
476
536
  if (this.isSubscribed) {
477
537
  await Promise.all(this.unsubscribeUsers());
@@ -481,50 +541,103 @@ export class DriftClient {
481
541
 
482
542
  this.userStats = new UserStats({
483
543
  driftClient: this,
484
- userStatsAccountPublicKey: getUserStatsAccountPublicKey(
485
- this.program.programId,
486
- this.authority
487
- ),
544
+ userStatsAccountPublicKey: this.getUserStatsAccountPublicKey(),
488
545
  accountSubscription: this.userAccountSubscriptionConfig,
489
546
  });
490
- }
491
- }
492
- this.users.clear();
493
- this.createUsers(subAccountIds, this.userAccountSubscriptionConfig);
494
- if (this.isSubscribed) {
495
- await Promise.all(this.subscribeUsers());
496
547
 
497
- if (this.userStats) {
498
548
  await this.userStats.subscribe();
499
549
  }
550
+
551
+ this.users.clear();
552
+ success = await this.addAndSubscribeToUsers();
500
553
  }
501
554
 
502
- this.activeSubAccountId = activeSubAccountId;
503
- this.userStatsAccountPublicKey = undefined;
555
+ return success;
504
556
  }
505
557
 
506
- public switchActiveUser(subAccountId: number) {
558
+ public switchActiveUser(subAccountId: number, authority?: PublicKey) {
507
559
  this.activeSubAccountId = subAccountId;
560
+ this.activeAuthority = authority ?? this.authority;
508
561
  }
509
562
 
510
- public async addUser(subAccountId: number): Promise<void> {
511
- if (this.users.has(subAccountId)) {
512
- return;
563
+ public async addUser(
564
+ subAccountId: number,
565
+ authority?: PublicKey
566
+ ): Promise<boolean> {
567
+ authority = authority ?? this.authority;
568
+ const userKey = this.getUserMapKey(subAccountId, authority);
569
+
570
+ if (this.users.has(userKey) && this.users.get(userKey).isSubscribed) {
571
+ return true;
513
572
  }
514
573
 
515
574
  const user = this.createUser(
516
575
  subAccountId,
517
- this.userAccountSubscriptionConfig
576
+ this.userAccountSubscriptionConfig,
577
+ authority
518
578
  );
519
- await user.subscribe();
520
- this.users.set(subAccountId, user);
579
+
580
+ const result = await user.subscribe();
581
+
582
+ if (result) {
583
+ this.users.set(userKey, user);
584
+ return true;
585
+ } else {
586
+ return false;
587
+ }
521
588
  }
522
589
 
523
- public async addAllUsers(): Promise<void> {
524
- const userAccounts = await this.getUserAccountsForAuthority(this.authority);
525
- for (const userAccount of userAccounts) {
526
- await this.addUser(userAccount.subAccountId);
590
+ /**
591
+ * Adds and subscribes to users based on params set by the constructor or by updateWallet.
592
+ */
593
+ public async addAndSubscribeToUsers(): Promise<boolean> {
594
+ // save the rpc calls if driftclient is initialized without a real wallet
595
+ if (this.skipLoadUsers) return true;
596
+
597
+ let result = true;
598
+
599
+ if (this.authoritySubaccountMap && this.authoritySubaccountMap.size > 0) {
600
+ this.authoritySubaccountMap.forEach(async (value, key) => {
601
+ for (const subAccountId of value) {
602
+ result =
603
+ result && (await this.addUser(subAccountId, new PublicKey(key)));
604
+ }
605
+ });
606
+
607
+ if (this.activeSubAccountId == undefined) {
608
+ this.switchActiveUser(
609
+ [...this.authoritySubaccountMap.values()][0][0] ?? 0,
610
+ new PublicKey(
611
+ [...this.authoritySubaccountMap.keys()][0] ??
612
+ this.authority.toString()
613
+ )
614
+ );
615
+ }
616
+ } else {
617
+ const userAccounts =
618
+ (await this.getUserAccountsForAuthority(this.authority)) ?? [];
619
+ let delegatedAccounts = [];
620
+
621
+ if (this.includeDelegates) {
622
+ delegatedAccounts =
623
+ (await this.getUserAccountsForDelegate(this.authority)) ?? [];
624
+ }
625
+
626
+ for (const account of userAccounts.concat(delegatedAccounts)) {
627
+ result =
628
+ result &&
629
+ (await this.addUser(account.subAccountId, account.authority));
630
+ }
631
+
632
+ if (this.activeSubAccountId == undefined) {
633
+ this.switchActiveUser(
634
+ userAccounts.concat(delegatedAccounts)[0]?.subAccountId ?? 0,
635
+ userAccounts.concat(delegatedAccounts)[0]?.authority ?? this.authority
636
+ );
637
+ }
527
638
  }
639
+
640
+ return result;
528
641
  }
529
642
 
530
643
  public async initializeUserAccount(
@@ -710,7 +823,7 @@ export class DriftClient {
710
823
  subAccountId
711
824
  );
712
825
 
713
- await this.addUser(subAccountId);
826
+ await this.addUser(subAccountId, this.wallet.publicKey);
714
827
  const remainingAccounts = this.getRemainingAccounts({
715
828
  userAccounts: [this.getUserAccount(subAccountId)],
716
829
  });
@@ -782,9 +895,9 @@ export class DriftClient {
782
895
  },
783
896
  ]);
784
897
 
785
- return programAccounts.map(
786
- (programAccount) => programAccount.account as UserAccount
787
- );
898
+ return programAccounts
899
+ .map((programAccount) => programAccount.account as UserAccount)
900
+ .sort((a, b) => a.subAccountId - b.subAccountId);
788
901
  }
789
902
 
790
903
  public async getUserAccountsAndAddressesForAuthority(
@@ -818,9 +931,9 @@ export class DriftClient {
818
931
  },
819
932
  ]);
820
933
 
821
- return programAccounts.map(
822
- (programAccount) => programAccount.account as UserAccount
823
- );
934
+ return programAccounts
935
+ .map((programAccount) => programAccount.account as UserAccount)
936
+ .sort((a, b) => a.subAccountId - b.subAccountId);
824
937
  }
825
938
 
826
939
  public async getReferredUserStatsAccountsByReferrer(
@@ -884,22 +997,33 @@ export class DriftClient {
884
997
  this.opts
885
998
  );
886
999
 
887
- await this.users.get(subAccountId)?.unsubscribe();
888
- this.users.delete(subAccountId);
1000
+ const userMapKey = this.getUserMapKey(subAccountId, this.wallet.publicKey);
1001
+ await this.users.get(userMapKey)?.unsubscribe();
1002
+ this.users.delete(userMapKey);
889
1003
 
890
1004
  return txSig;
891
1005
  }
892
1006
 
893
- public getUser(subAccountId?: number): User {
1007
+ public getUser(subAccountId?: number, authority?: PublicKey): User {
894
1008
  subAccountId = subAccountId ?? this.activeSubAccountId;
895
- if (!this.users.has(subAccountId)) {
1009
+ authority = authority ?? this.activeAuthority;
1010
+ const userMapKey = this.getUserMapKey(subAccountId, authority);
1011
+
1012
+ if (!this.users.has(userMapKey)) {
896
1013
  throw new Error(`Clearing House has no user for user id ${subAccountId}`);
897
1014
  }
898
- return this.users.get(subAccountId);
1015
+ return this.users.get(userMapKey);
899
1016
  }
900
1017
 
901
1018
  public getUsers(): User[] {
902
- return [...this.users.values()];
1019
+ // delegate users get added to the end
1020
+ return [...this.users.values()]
1021
+ .filter((acct) => acct.getUserAccount().authority.equals(this.authority))
1022
+ .concat(
1023
+ [...this.users.values()].filter(
1024
+ (acct) => !acct.getUserAccount().authority.equals(this.authority)
1025
+ )
1026
+ );
903
1027
  }
904
1028
 
905
1029
  public getUserStats(): UserStats {
@@ -927,17 +1051,23 @@ export class DriftClient {
927
1051
 
928
1052
  this.userStatsAccountPublicKey = getUserStatsAccountPublicKey(
929
1053
  this.program.programId,
930
- this.authority
1054
+ this.activeAuthority
931
1055
  );
932
1056
  return this.userStatsAccountPublicKey;
933
1057
  }
934
1058
 
935
- public async getUserAccountPublicKey(): Promise<PublicKey> {
936
- return this.getUser().userAccountPublicKey;
1059
+ public async getUserAccountPublicKey(
1060
+ subAccountId?: number,
1061
+ authority?: PublicKey
1062
+ ): Promise<PublicKey> {
1063
+ return this.getUser(subAccountId, authority).userAccountPublicKey;
937
1064
  }
938
1065
 
939
- public getUserAccount(subAccountId?: number): UserAccount | undefined {
940
- return this.getUser(subAccountId).getUserAccount();
1066
+ public getUserAccount(
1067
+ subAccountId?: number,
1068
+ authority?: PublicKey
1069
+ ): UserAccount | undefined {
1070
+ return this.getUser(subAccountId, authority).getUserAccount();
941
1071
  }
942
1072
 
943
1073
  /**
@@ -1798,9 +1928,14 @@ export class DriftClient {
1798
1928
  );
1799
1929
 
1800
1930
  let remainingAccounts;
1801
- if (this.users.has(fromSubAccountId)) {
1931
+
1932
+ const userMapKey = this.getUserMapKey(
1933
+ fromSubAccountId,
1934
+ this.wallet.publicKey
1935
+ );
1936
+ if (this.users.has(userMapKey)) {
1802
1937
  remainingAccounts = this.getRemainingAccounts({
1803
- userAccounts: [this.users.get(fromSubAccountId).getUserAccount()],
1938
+ userAccounts: [this.users.get(userMapKey).getUserAccount()],
1804
1939
  useMarketLastSlotCache: true,
1805
1940
  writableSpotMarketIndexes: [marketIndex],
1806
1941
  });
@@ -3039,7 +3174,7 @@ export class DriftClient {
3039
3174
  user: UserAccount,
3040
3175
  txParams?: TxParams
3041
3176
  ): Promise<TransactionSignature> {
3042
- const { txSig } = await this.txSender.send(
3177
+ const { txSig } = await this.sendTransaction(
3043
3178
  wrapInTx(
3044
3179
  await this.getForceCancelOrdersIx(userAccountPublicKey, user),
3045
3180
  txParams?.computeUnits,
@@ -3078,7 +3213,7 @@ export class DriftClient {
3078
3213
  user: UserAccount,
3079
3214
  txParams?: TxParams
3080
3215
  ): Promise<TransactionSignature> {
3081
- const { txSig } = await this.txSender.send(
3216
+ const { txSig } = await this.sendTransaction(
3082
3217
  wrapInTx(
3083
3218
  await this.getUpdateUserIdleIx(userAccountPublicKey, user),
3084
3219
  txParams?.computeUnits,
@@ -4738,6 +4873,36 @@ export class DriftClient {
4738
4873
  return extendedInfo;
4739
4874
  }
4740
4875
 
4876
+ /**
4877
+ * Returns the market index and type for a given market name
4878
+ * E.g. "SOL-PERP" -> { marketIndex: 0, marketType: MarketType.PERP }
4879
+ *
4880
+ * @param name
4881
+ */
4882
+ getMarketIndexAndType(
4883
+ name: string
4884
+ ): { marketIndex: number; marketType: MarketType } | undefined {
4885
+ for (const perpMarketAccount of this.getPerpMarketAccounts()) {
4886
+ if (decodeName(perpMarketAccount.name) === name) {
4887
+ return {
4888
+ marketIndex: perpMarketAccount.marketIndex,
4889
+ marketType: MarketType.PERP,
4890
+ };
4891
+ }
4892
+ }
4893
+
4894
+ for (const spotMarketAccount of this.getSpotMarketAccounts()) {
4895
+ if (decodeName(spotMarketAccount.name) === name) {
4896
+ return {
4897
+ marketIndex: spotMarketAccount.marketIndex,
4898
+ marketType: MarketType.SPOT,
4899
+ };
4900
+ }
4901
+ }
4902
+
4903
+ return undefined;
4904
+ }
4905
+
4741
4906
  sendTransaction(
4742
4907
  tx: Transaction,
4743
4908
  additionalSigners?: Array<Signer>,
@@ -20,6 +20,9 @@ export type DriftClientConfig = {
20
20
  env?: DriftEnv;
21
21
  userStats?: boolean;
22
22
  authority?: PublicKey; // explicitly pass an authority if signer is delegate
23
+ includeDelegates?: boolean; // flag for whether to load delegate accounts as well
24
+ authoritySubaccountMap?: Map<string, number[]>; // if passed this will override subAccountIds and includeDelegates
25
+ skipLoadUsers?: boolean; // if passed to constructor, no user accounts will be loaded. they will load if updateWallet is called afterwards.
23
26
  };
24
27
 
25
28
  export type DriftClientSubscriptionConfig =
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.26.0-beta.1",
2
+ "version": "2.26.0-beta.3",
3
3
  "name": "drift",
4
4
  "instructions": [
5
5
  {
package/src/index.ts CHANGED
@@ -70,6 +70,7 @@ export * from './dlob/DLOBOrders';
70
70
  export * from './dlob/NodeList';
71
71
  export * from './dlob/DLOBSubscriber';
72
72
  export * from './dlob/types';
73
+ export * from './dlob/orderBookLevels';
73
74
  export * from './userMap/userMap';
74
75
  export * from './userMap/userStatsMap';
75
76
  export * from './math/bankruptcy';
@@ -4,8 +4,9 @@ import { Market, Orderbook } from '@project-serum/serum';
4
4
  import { SerumMarketSubscriberConfig } from './types';
5
5
  import { BN } from '@coral-xyz/anchor';
6
6
  import { PRICE_PRECISION } from '../constants/numericConstants';
7
+ import { L2Level, L2OrderBookGenerator } from '../dlob/orderBookLevels';
7
8
 
8
- export class SerumSubscriber {
9
+ export class SerumSubscriber implements L2OrderBookGenerator {
9
10
  connection: Connection;
10
11
  programId: PublicKey;
11
12
  marketAddress: PublicKey;
@@ -112,6 +113,33 @@ export class SerumSubscriber {
112
113
  return new BN(bestAsk[0] * PRICE_PRECISION.toNumber());
113
114
  }
114
115
 
116
+ public getL2Bids(): Generator<L2Level> {
117
+ return this.getL2Levels('bids');
118
+ }
119
+
120
+ public getL2Asks(): Generator<L2Level> {
121
+ return this.getL2Levels('asks');
122
+ }
123
+
124
+ *getL2Levels(side: 'bids' | 'asks'): Generator<L2Level> {
125
+ // @ts-ignore
126
+ const basePrecision = Math.pow(10, this.market._baseSplTokenDecimals);
127
+ const pricePrecision = PRICE_PRECISION.toNumber();
128
+ for (const { price: priceNum, size: sizeNum } of this[side].items(
129
+ side === 'bids'
130
+ )) {
131
+ const price = new BN(priceNum * pricePrecision);
132
+ const size = new BN(sizeNum * basePrecision);
133
+ yield {
134
+ price,
135
+ size,
136
+ sources: {
137
+ serum: size,
138
+ },
139
+ };
140
+ }
141
+ }
142
+
115
143
  public async unsubscribe(): Promise<void> {
116
144
  if (!this.subscribed) {
117
145
  return;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseTokenAccount = void 0;
4
+ const spl_token_1 = require("@solana/spl-token");
5
+ const web3_js_1 = require("@solana/web3.js");
6
+ function parseTokenAccount(data) {
7
+ const accountInfo = spl_token_1.AccountLayout.decode(data);
8
+ accountInfo.mint = new web3_js_1.PublicKey(accountInfo.mint);
9
+ accountInfo.owner = new web3_js_1.PublicKey(accountInfo.owner);
10
+ accountInfo.amount = spl_token_1.u64.fromBuffer(accountInfo.amount);
11
+ if (accountInfo.delegateOption === 0) {
12
+ accountInfo.delegate = null;
13
+ // eslint-disable-next-line new-cap
14
+ accountInfo.delegatedAmount = new spl_token_1.u64(0);
15
+ }
16
+ else {
17
+ accountInfo.delegate = new web3_js_1.PublicKey(accountInfo.delegate);
18
+ accountInfo.delegatedAmount = spl_token_1.u64.fromBuffer(accountInfo.delegatedAmount);
19
+ }
20
+ accountInfo.isInitialized = accountInfo.state !== 0;
21
+ accountInfo.isFrozen = accountInfo.state === 2;
22
+ if (accountInfo.isNativeOption === 1) {
23
+ accountInfo.rentExemptReserve = spl_token_1.u64.fromBuffer(accountInfo.isNative);
24
+ accountInfo.isNative = true;
25
+ }
26
+ else {
27
+ accountInfo.rentExemptReserve = null;
28
+ accountInfo.isNative = false;
29
+ }
30
+ if (accountInfo.closeAuthorityOption === 0) {
31
+ accountInfo.closeAuthority = null;
32
+ }
33
+ else {
34
+ accountInfo.closeAuthority = new web3_js_1.PublicKey(accountInfo.closeAuthority);
35
+ }
36
+ return accountInfo;
37
+ }
38
+ exports.parseTokenAccount = parseTokenAccount;
package/src/types.ts CHANGED
@@ -585,6 +585,7 @@ export type HistoricalIndexData = {
585
585
  export type SpotMarketAccount = {
586
586
  status: MarketStatus;
587
587
  assetTier: AssetTier;
588
+ name: number[];
588
589
 
589
590
  marketIndex: number;
590
591
  pubkey: PublicKey;
@@ -0,0 +1,27 @@
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.findComputeUnitConsumption = void 0;
13
+ function findComputeUnitConsumption(programId, connection, txSignature, commitment = 'confirmed') {
14
+ return __awaiter(this, void 0, void 0, function* () {
15
+ const tx = yield connection.getTransaction(txSignature, { commitment });
16
+ const computeUnits = [];
17
+ const regex = new RegExp(`Program ${programId.toString()} consumed ([0-9]{0,6}) of ([0-9]{0,7}) compute units`);
18
+ tx.meta.logMessages.forEach((logMessage) => {
19
+ const match = logMessage.match(regex);
20
+ if (match && match[1]) {
21
+ computeUnits.push(match[1]);
22
+ }
23
+ });
24
+ return computeUnits;
25
+ });
26
+ }
27
+ exports.findComputeUnitConsumption = findComputeUnitConsumption;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getTokenAddress = void 0;
4
+ const spl_token_1 = require("@solana/spl-token");
5
+ const web3_js_1 = require("@solana/web3.js");
6
+ const getTokenAddress = (mintAddress, userPubKey) => {
7
+ return spl_token_1.Token.getAssociatedTokenAddress(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, new web3_js_1.PublicKey(mintAddress), new web3_js_1.PublicKey(userPubKey));
8
+ };
9
+ exports.getTokenAddress = getTokenAddress;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.promiseTimeout = void 0;
4
+ function promiseTimeout(promise, timeoutMs) {
5
+ let timeoutId;
6
+ const timeoutPromise = new Promise((resolve) => {
7
+ timeoutId = setTimeout(() => resolve(null), timeoutMs);
8
+ });
9
+ return Promise.race([promise, timeoutPromise]).then((result) => {
10
+ clearTimeout(timeoutId);
11
+ return result;
12
+ });
13
+ }
14
+ exports.promiseTimeout = promiseTimeout;
@@ -0,0 +1,27 @@
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.estimateTps = void 0;
13
+ function estimateTps(programId, connection, failed) {
14
+ return __awaiter(this, void 0, void 0, function* () {
15
+ let signatures = yield connection.getSignaturesForAddress(programId, undefined, 'finalized');
16
+ if (failed) {
17
+ signatures = signatures.filter((signature) => signature.err);
18
+ }
19
+ const numberOfSignatures = signatures.length;
20
+ if (numberOfSignatures === 0) {
21
+ return 0;
22
+ }
23
+ return (numberOfSignatures /
24
+ (signatures[0].blockTime - signatures[numberOfSignatures - 1].blockTime));
25
+ });
26
+ }
27
+ exports.estimateTps = estimateTps;