@drift-labs/sdk 2.31.1-beta.1 → 2.31.1-beta.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 (42) hide show
  1. package/VERSION +1 -1
  2. package/lib/accounts/mockUserAccountSubscriber.d.ts +23 -0
  3. package/lib/accounts/mockUserAccountSubscriber.js +31 -0
  4. package/lib/constants/perpMarkets.js +20 -0
  5. package/lib/driftClient.d.ts +12 -1
  6. package/lib/driftClient.js +92 -21
  7. package/lib/driftClientConfig.d.ts +4 -9
  8. package/lib/idl/drift.json +1 -1
  9. package/lib/index.d.ts +1 -0
  10. package/lib/index.js +1 -0
  11. package/lib/marinade/index.d.ts +11 -0
  12. package/lib/marinade/index.js +36 -0
  13. package/lib/marinade/types.d.ts +1963 -0
  14. package/lib/marinade/types.js +1965 -0
  15. package/lib/math/tiers.d.ts +4 -0
  16. package/lib/math/tiers.js +52 -0
  17. package/lib/tx/retryTxSender.d.ts +14 -3
  18. package/lib/tx/retryTxSender.js +27 -22
  19. package/lib/tx/types.d.ts +3 -2
  20. package/lib/user.d.ts +10 -1
  21. package/lib/user.js +39 -8
  22. package/lib/userConfig.d.ts +4 -0
  23. package/lib/userStats.js +4 -1
  24. package/lib/userStatsConfig.d.ts +2 -0
  25. package/package.json +1 -1
  26. package/src/accounts/mockUserAccountSubscriber.ts +53 -0
  27. package/src/config.ts +2 -2
  28. package/src/constants/perpMarkets.ts +20 -0
  29. package/src/driftClient.ts +134 -21
  30. package/src/driftClientConfig.ts +4 -9
  31. package/src/idl/drift.json +1 -1
  32. package/src/index.ts +1 -0
  33. package/src/marinade/idl/idl.json +1962 -0
  34. package/src/marinade/index.ts +64 -0
  35. package/src/marinade/types.ts +3925 -0
  36. package/src/math/tiers.ts +44 -0
  37. package/src/tx/retryTxSender.ts +46 -36
  38. package/src/tx/types.ts +4 -2
  39. package/src/user.ts +63 -12
  40. package/src/userConfig.ts +5 -0
  41. package/src/userStats.ts +4 -0
  42. package/src/userStatsConfig.ts +3 -0
@@ -0,0 +1,4 @@
1
+ import { PerpMarketAccount, SpotMarketAccount } from '../types';
2
+ export declare function getPerpMarketTierNumber(perpMarket: PerpMarketAccount): number;
3
+ export declare function getSpotMarketTierNumber(spotMarket: SpotMarketAccount): number;
4
+ export declare function perpTierIsAsSafeAs(perpTier: number, otherPerpTier: number, otherSpotTier: number): boolean;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.perpTierIsAsSafeAs = exports.getSpotMarketTierNumber = exports.getPerpMarketTierNumber = void 0;
4
+ const types_1 = require("../types");
5
+ function getPerpMarketTierNumber(perpMarket) {
6
+ if ((0, types_1.isVariant)(perpMarket.contractTier, 'a')) {
7
+ return 0;
8
+ }
9
+ else if ((0, types_1.isVariant)(perpMarket.contractTier, 'b')) {
10
+ return 1;
11
+ }
12
+ else if ((0, types_1.isVariant)(perpMarket.contractTier, 'c')) {
13
+ return 2;
14
+ }
15
+ else if ((0, types_1.isVariant)(perpMarket.contractTier, 'speculative')) {
16
+ return 3;
17
+ }
18
+ else if ((0, types_1.isVariant)(perpMarket.contractTier, 'isolated')) {
19
+ return 4;
20
+ }
21
+ else {
22
+ return 5;
23
+ }
24
+ }
25
+ exports.getPerpMarketTierNumber = getPerpMarketTierNumber;
26
+ function getSpotMarketTierNumber(spotMarket) {
27
+ if ((0, types_1.isVariant)(spotMarket.assetTier, 'collateral')) {
28
+ return 0;
29
+ }
30
+ else if ((0, types_1.isVariant)(spotMarket.assetTier, 'protected')) {
31
+ return 1;
32
+ }
33
+ else if ((0, types_1.isVariant)(spotMarket.assetTier, 'cross')) {
34
+ return 2;
35
+ }
36
+ else if ((0, types_1.isVariant)(spotMarket.assetTier, 'isolated')) {
37
+ return 3;
38
+ }
39
+ else if ((0, types_1.isVariant)(spotMarket.assetTier, 'unlisted')) {
40
+ return 4;
41
+ }
42
+ else {
43
+ return 5;
44
+ }
45
+ }
46
+ exports.getSpotMarketTierNumber = getSpotMarketTierNumber;
47
+ function perpTierIsAsSafeAs(perpTier, otherPerpTier, otherSpotTier) {
48
+ const asSafeAsPerp = perpTier <= otherPerpTier;
49
+ const asSafeAsSpot = otherSpotTier === 4 || (otherSpotTier >= 2 && perpTier <= 2);
50
+ return asSafeAsSpot && asSafeAsPerp;
51
+ }
52
+ exports.perpTierIsAsSafeAs = perpTierIsAsSafeAs;
@@ -1,16 +1,26 @@
1
1
  /// <reference types="node" />
2
2
  import { TxSender, TxSigAndSlot } from './types';
3
3
  import { Commitment, ConfirmOptions, RpcResponseAndContext, Signer, SignatureResult, Transaction, TransactionSignature, Connection, VersionedTransaction, TransactionInstruction, AddressLookupTableAccount } from '@solana/web3.js';
4
- import { AnchorProvider } from '@coral-xyz/anchor';
4
+ import { IWallet } from '../types';
5
5
  type ResolveReference = {
6
6
  resolve?: () => void;
7
7
  };
8
8
  export declare class RetryTxSender implements TxSender {
9
- provider: AnchorProvider;
9
+ connection: Connection;
10
+ wallet: IWallet;
11
+ opts: ConfirmOptions;
10
12
  timeout: number;
11
13
  retrySleep: number;
12
14
  additionalConnections: Connection[];
13
- constructor(provider: AnchorProvider, timeout?: number, retrySleep?: number, additionalConnections?: Connection[]);
15
+ timoutCount: number;
16
+ constructor({ connection, wallet, opts, timeout, retrySleep, additionalConnections, }: {
17
+ connection: Connection;
18
+ wallet: IWallet;
19
+ opts?: ConfirmOptions;
20
+ timeout?: number;
21
+ retrySleep?: number;
22
+ additionalConnections?: any;
23
+ });
14
24
  send(tx: Transaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean): Promise<TxSigAndSlot>;
15
25
  prepareTx(tx: Transaction, additionalSigners: Array<Signer>, opts: ConfirmOptions): Promise<Transaction>;
16
26
  getVersionedTransaction(ixs: TransactionInstruction[], lookupTableAccounts: AddressLookupTableAccount[], additionalSigners?: Array<Signer>, opts?: ConfirmOptions): Promise<VersionedTransaction>;
@@ -22,5 +32,6 @@ export declare class RetryTxSender implements TxSender {
22
32
  promiseTimeout<T>(promises: Promise<T>[], timeoutMs: number): Promise<T | null>;
23
33
  sendToAdditionalConnections(rawTx: Buffer | Uint8Array, opts: ConfirmOptions): void;
24
34
  addAdditionalConnection(newConnection: Connection): void;
35
+ getTimeoutCount(): number;
25
36
  }
26
37
  export {};
@@ -5,15 +5,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.RetryTxSender = void 0;
7
7
  const web3_js_1 = require("@solana/web3.js");
8
+ const anchor_1 = require("@coral-xyz/anchor");
8
9
  const assert_1 = __importDefault(require("assert"));
9
10
  const bs58_1 = __importDefault(require("bs58"));
10
11
  const DEFAULT_TIMEOUT = 35000;
11
12
  const DEFAULT_RETRY = 8000;
12
13
  class RetryTxSender {
13
- constructor(provider, timeout, retrySleep, additionalConnections = new Array()) {
14
- this.provider = provider;
15
- this.timeout = timeout !== null && timeout !== void 0 ? timeout : DEFAULT_TIMEOUT;
16
- this.retrySleep = retrySleep !== null && retrySleep !== void 0 ? retrySleep : DEFAULT_RETRY;
14
+ constructor({ connection, wallet, opts = anchor_1.AnchorProvider.defaultOptions(), timeout = DEFAULT_TIMEOUT, retrySleep = DEFAULT_RETRY, additionalConnections = new Array(), }) {
15
+ this.timoutCount = 0;
16
+ this.connection = connection;
17
+ this.wallet = wallet;
18
+ this.opts = opts;
19
+ this.timeout = timeout;
20
+ this.retrySleep = retrySleep;
17
21
  this.additionalConnections = additionalConnections;
18
22
  }
19
23
  async send(tx, additionalSigners, opts, preSigned) {
@@ -21,7 +25,7 @@ class RetryTxSender {
21
25
  additionalSigners = [];
22
26
  }
23
27
  if (opts === undefined) {
24
- opts = this.provider.opts;
28
+ opts = this.opts;
25
29
  }
26
30
  const signedTx = preSigned
27
31
  ? tx
@@ -29,14 +33,14 @@ class RetryTxSender {
29
33
  return this.sendRawTransaction(signedTx.serialize(), opts);
30
34
  }
31
35
  async prepareTx(tx, additionalSigners, opts) {
32
- tx.feePayer = this.provider.wallet.publicKey;
33
- tx.recentBlockhash = (await this.provider.connection.getRecentBlockhash(opts.preflightCommitment)).blockhash;
36
+ tx.feePayer = this.wallet.publicKey;
37
+ tx.recentBlockhash = (await this.connection.getRecentBlockhash(opts.preflightCommitment)).blockhash;
34
38
  additionalSigners
35
39
  .filter((s) => s !== undefined)
36
40
  .forEach((kp) => {
37
41
  tx.partialSign(kp);
38
42
  });
39
- const signedTx = await this.provider.wallet.signTransaction(tx);
43
+ const signedTx = await this.wallet.signTransaction(tx);
40
44
  return signedTx;
41
45
  }
42
46
  async getVersionedTransaction(ixs, lookupTableAccounts, additionalSigners, opts) {
@@ -44,11 +48,11 @@ class RetryTxSender {
44
48
  additionalSigners = [];
45
49
  }
46
50
  if (opts === undefined) {
47
- opts = this.provider.opts;
51
+ opts = this.opts;
48
52
  }
49
53
  const message = new web3_js_1.TransactionMessage({
50
- payerKey: this.provider.wallet.publicKey,
51
- recentBlockhash: (await this.provider.connection.getRecentBlockhash(opts.preflightCommitment)).blockhash,
54
+ payerKey: this.wallet.publicKey,
55
+ recentBlockhash: (await this.connection.getRecentBlockhash(opts.preflightCommitment)).blockhash,
52
56
  instructions: ixs,
53
57
  }).compileToV0Message(lookupTableAccounts);
54
58
  const tx = new web3_js_1.VersionedTransaction(message);
@@ -60,9 +64,9 @@ class RetryTxSender {
60
64
  signedTx = tx;
61
65
  // @ts-ignore
62
66
  }
63
- else if (this.provider.wallet.payer) {
67
+ else if (this.wallet.payer) {
64
68
  // @ts-ignore
65
- tx.sign((additionalSigners !== null && additionalSigners !== void 0 ? additionalSigners : []).concat(this.provider.wallet.payer));
69
+ tx.sign((additionalSigners !== null && additionalSigners !== void 0 ? additionalSigners : []).concat(this.wallet.payer));
66
70
  signedTx = tx;
67
71
  }
68
72
  else {
@@ -70,10 +74,10 @@ class RetryTxSender {
70
74
  tx.sign([kp]);
71
75
  });
72
76
  // @ts-ignore
73
- signedTx = await this.provider.wallet.signTransaction(tx);
77
+ signedTx = await this.wallet.signTransaction(tx);
74
78
  }
75
79
  if (opts === undefined) {
76
- opts = this.provider.opts;
80
+ opts = this.opts;
77
81
  }
78
82
  return this.sendRawTransaction(signedTx.serialize(), opts);
79
83
  }
@@ -81,7 +85,7 @@ class RetryTxSender {
81
85
  const startTime = this.getTimestamp();
82
86
  let txid;
83
87
  try {
84
- txid = await this.provider.connection.sendRawTransaction(rawTransaction, opts);
88
+ txid = await this.connection.sendRawTransaction(rawTransaction, opts);
85
89
  this.sendToAdditionalConnections(rawTransaction, opts);
86
90
  }
87
91
  catch (e) {
@@ -102,7 +106,7 @@ class RetryTxSender {
102
106
  while (!done && this.getTimestamp() - startTime < this.timeout) {
103
107
  await this.sleep(resolveReference);
104
108
  if (!done) {
105
- this.provider.connection
109
+ this.connection
106
110
  .sendRawTransaction(rawTransaction, opts)
107
111
  .catch((e) => {
108
112
  console.error(e);
@@ -136,12 +140,9 @@ class RetryTxSender {
136
140
  }
137
141
  (0, assert_1.default)(decodedSignature.length === 64, 'signature has invalid length');
138
142
  const start = Date.now();
139
- const subscriptionCommitment = commitment || this.provider.opts.commitment;
143
+ const subscriptionCommitment = commitment || this.opts.commitment;
140
144
  const subscriptionIds = new Array();
141
- const connections = [
142
- this.provider.connection,
143
- ...this.additionalConnections,
144
- ];
145
+ const connections = [this.connection, ...this.additionalConnections];
145
146
  let response = null;
146
147
  const promises = connections.map((connection, i) => {
147
148
  let subscriptionId;
@@ -174,6 +175,7 @@ class RetryTxSender {
174
175
  }
175
176
  }
176
177
  if (response === null) {
178
+ this.timoutCount += 1;
177
179
  const duration = (Date.now() - start) / 1000;
178
180
  throw new Error(`Transaction was not confirmed in ${duration.toFixed(2)} seconds. It is unknown if it succeeded or failed. Check signature ${signature} using the Solana Explorer or CLI tools.`);
179
181
  }
@@ -217,5 +219,8 @@ class RetryTxSender {
217
219
  this.additionalConnections.push(newConnection);
218
220
  }
219
221
  }
222
+ getTimeoutCount() {
223
+ return this.timoutCount;
224
+ }
220
225
  }
221
226
  exports.RetryTxSender = RetryTxSender;
package/lib/tx/types.d.ts CHANGED
@@ -1,14 +1,15 @@
1
1
  /// <reference types="node" />
2
- import { Provider } from '@coral-xyz/anchor';
3
2
  import { AddressLookupTableAccount, ConfirmOptions, Signer, Transaction, TransactionInstruction, TransactionSignature, VersionedTransaction } from '@solana/web3.js';
3
+ import { IWallet } from '../types';
4
4
  export type TxSigAndSlot = {
5
5
  txSig: TransactionSignature;
6
6
  slot: number;
7
7
  };
8
8
  export interface TxSender {
9
- provider: Provider;
9
+ wallet: IWallet;
10
10
  send(tx: Transaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean): Promise<TxSigAndSlot>;
11
11
  sendVersionedTransaction(tx: VersionedTransaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean): Promise<TxSigAndSlot>;
12
12
  getVersionedTransaction(ixs: TransactionInstruction[], lookupTableAccounts: AddressLookupTableAccount[], additionalSigners?: Array<Signer>, opts?: ConfirmOptions): Promise<VersionedTransaction>;
13
13
  sendRawTransaction(rawTransaction: Buffer | Uint8Array, opts: ConfirmOptions): Promise<TxSigAndSlot>;
14
+ getTimeoutCount(): number;
14
15
  }
package/lib/user.d.ts CHANGED
@@ -107,6 +107,7 @@ export declare class User {
107
107
  */
108
108
  getMaintenanceMarginRequirement(liquidationBuffer?: BN): BN;
109
109
  getActivePerpPositions(): PerpPosition[];
110
+ getActiveSpotPositions(): SpotPosition[];
110
111
  /**
111
112
  * calculates unrealized position price pnl
112
113
  * @returns : Precision QUOTE_PRECISION
@@ -185,7 +186,11 @@ export declare class User {
185
186
  * @returns : Precision TEN_THOUSAND
186
187
  */
187
188
  getMarginRatio(): BN;
188
- canBeLiquidated(): boolean;
189
+ canBeLiquidated(): {
190
+ canBeLiquidated: boolean;
191
+ marginRequirement: BN;
192
+ totalCollateral: BN;
193
+ };
189
194
  isBeingLiquidated(): boolean;
190
195
  isBankrupt(): boolean;
191
196
  /**
@@ -277,6 +282,10 @@ export declare class User {
277
282
  maxDepositAmount: BN;
278
283
  };
279
284
  canMakeIdle(slot: BN, slotsBeforeIdle: BN): boolean;
285
+ getSafestTiers(): {
286
+ perpTier: number;
287
+ spotTier: number;
288
+ };
280
289
  /**
281
290
  * Get the total position value, excluding any position coming from the given target market
282
291
  * @param marketToIgnore
package/lib/user.js CHANGED
@@ -12,6 +12,7 @@ const pollingUserAccountSubscriber_1 = require("./accounts/pollingUserAccountSub
12
12
  const webSocketUserAccountSubscriber_1 = require("./accounts/webSocketUserAccountSubscriber");
13
13
  const spotPosition_1 = require("./math/spotPosition");
14
14
  const oracles_1 = require("./math/oracles");
15
+ const tiers_1 = require("./math/tiers");
15
16
  class User {
16
17
  get isSubscribed() {
17
18
  return this._isSubscribed && this.accountSubscriber.isSubscribed;
@@ -20,13 +21,16 @@ class User {
20
21
  this._isSubscribed = val;
21
22
  }
22
23
  constructor(config) {
23
- var _a;
24
+ var _a, _b;
24
25
  this._isSubscribed = false;
25
26
  this.driftClient = config.driftClient;
26
27
  this.userAccountPublicKey = config.userAccountPublicKey;
27
28
  if (((_a = config.accountSubscription) === null || _a === void 0 ? void 0 : _a.type) === 'polling') {
28
29
  this.accountSubscriber = new pollingUserAccountSubscriber_1.PollingUserAccountSubscriber(config.driftClient.program, config.userAccountPublicKey, config.accountSubscription.accountLoader);
29
30
  }
31
+ else if (((_b = config.accountSubscription) === null || _b === void 0 ? void 0 : _b.type) === 'custom') {
32
+ this.accountSubscriber = config.accountSubscription.userAccountSubscriber;
33
+ }
30
34
  else {
31
35
  this.accountSubscriber = new webSocketUserAccountSubscriber_1.WebSocketUserAccountSubscriber(config.driftClient.program, config.userAccountPublicKey);
32
36
  }
@@ -176,7 +180,9 @@ class User {
176
180
  * @returns : pnl from settle
177
181
  */
178
182
  getPerpPositionWithLPSettle(marketIndex, originalPosition) {
179
- originalPosition = originalPosition !== null && originalPosition !== void 0 ? originalPosition : this.getPerpPosition(marketIndex);
183
+ var _a;
184
+ originalPosition =
185
+ (_a = originalPosition !== null && originalPosition !== void 0 ? originalPosition : this.getPerpPosition(marketIndex)) !== null && _a !== void 0 ? _a : this.getEmptyPosition(marketIndex);
180
186
  if (originalPosition.lpShares.eq(numericConstants_1.ZERO)) {
181
187
  return [originalPosition, numericConstants_1.ZERO, numericConstants_1.ZERO];
182
188
  }
@@ -228,7 +234,7 @@ class User {
228
234
  let pnl;
229
235
  if (updateType == 'open' || updateType == 'increase') {
230
236
  newQuoteEntry = position.quoteEntryAmount.add(deltaQaa);
231
- pnl = 0;
237
+ pnl = numericConstants_1.ZERO;
232
238
  }
233
239
  else if (updateType == 'reduce' || updateType == 'close') {
234
240
  newQuoteEntry = position.quoteEntryAmount.sub(position.quoteEntryAmount
@@ -305,6 +311,9 @@ class User {
305
311
  !(pos.openOrders == 0) ||
306
312
  !pos.lpShares.eq(numericConstants_1.ZERO));
307
313
  }
314
+ getActiveSpotPositions() {
315
+ return this.getUserAccount().spotPositions.filter((pos) => !(0, spotPosition_1.isSpotPositionAvailable)(pos));
316
+ }
308
317
  /**
309
318
  * calculates unrealized position price pnl
310
319
  * @returns : Precision QUOTE_PRECISION
@@ -601,7 +610,8 @@ class User {
601
610
  * @returns : Precision QUOTE_PRECISION
602
611
  */
603
612
  getPerpPositionValue(marketIndex, oraclePriceData, includeOpenOrders = false) {
604
- const userPosition = this.getPerpPosition(marketIndex) || this.getEmptyPosition(marketIndex);
613
+ const userPosition = this.getPerpPositionWithLPSettle(marketIndex)[0] ||
614
+ this.getEmptyPosition(marketIndex);
605
615
  const market = this.driftClient.getPerpMarketAccount(userPosition.marketIndex);
606
616
  return (0, margin_1.calculateBaseAssetValueWithOracle)(market, userPosition, oraclePriceData, includeOpenOrders);
607
617
  }
@@ -775,12 +785,16 @@ class User {
775
785
  const totalCollateral = this.getTotalCollateral('Maintenance');
776
786
  // if user being liq'd, can continue to be liq'd until total collateral above the margin requirement plus buffer
777
787
  let liquidationBuffer = undefined;
778
- const isBeingLiquidated = (0, types_1.isVariant)(this.getUserAccount().status, 'beingLiquidated');
779
- if (isBeingLiquidated) {
788
+ if (this.isBeingLiquidated()) {
780
789
  liquidationBuffer = new _1.BN(this.driftClient.getStateAccount().liquidationMarginBufferRatio);
781
790
  }
782
- const maintenanceRequirement = this.getMaintenanceMarginRequirement(liquidationBuffer);
783
- return totalCollateral.lt(maintenanceRequirement);
791
+ const marginRequirement = this.getMaintenanceMarginRequirement(liquidationBuffer);
792
+ const canBeLiquidated = totalCollateral.lt(marginRequirement);
793
+ return {
794
+ canBeLiquidated,
795
+ marginRequirement,
796
+ totalCollateral,
797
+ };
784
798
  }
785
799
  isBeingLiquidated() {
786
800
  return (0, types_1.isOneOfVariant)(this.getUserAccount().status, [
@@ -1281,6 +1295,23 @@ class User {
1281
1295
  }
1282
1296
  return true;
1283
1297
  }
1298
+ getSafestTiers() {
1299
+ let safestPerpTier = 4;
1300
+ let safestSpotTier = 4;
1301
+ for (const perpPosition of this.getActivePerpPositions()) {
1302
+ safestPerpTier = Math.min(safestPerpTier, (0, tiers_1.getPerpMarketTierNumber)(this.driftClient.getPerpMarketAccount(perpPosition.marketIndex)));
1303
+ }
1304
+ for (const spotPosition of this.getActiveSpotPositions()) {
1305
+ if ((0, types_1.isVariant)(spotPosition.balanceType, 'deposit')) {
1306
+ continue;
1307
+ }
1308
+ safestSpotTier = Math.min(safestSpotTier, (0, tiers_1.getSpotMarketTierNumber)(this.driftClient.getSpotMarketAccount(spotPosition.marketIndex)));
1309
+ }
1310
+ return {
1311
+ perpTier: safestPerpTier,
1312
+ spotTier: safestSpotTier,
1313
+ };
1314
+ }
1284
1315
  /**
1285
1316
  * Get the total position value, excluding any position coming from the given target market
1286
1317
  * @param marketToIgnore
@@ -1,6 +1,7 @@
1
1
  import { DriftClient } from './driftClient';
2
2
  import { PublicKey } from '@solana/web3.js';
3
3
  import { BulkAccountLoader } from './accounts/bulkAccountLoader';
4
+ import { UserAccountSubscriber } from './accounts/types';
4
5
  export type UserConfig = {
5
6
  accountSubscription?: UserSubscriptionConfig;
6
7
  driftClient: DriftClient;
@@ -11,4 +12,7 @@ export type UserSubscriptionConfig = {
11
12
  } | {
12
13
  type: 'polling';
13
14
  accountLoader: BulkAccountLoader;
15
+ } | {
16
+ type: 'custom';
17
+ userAccountSubscriber: UserAccountSubscriber;
14
18
  };
package/lib/userStats.js CHANGED
@@ -7,12 +7,15 @@ const webSocketUserStatsAccountSubsriber_1 = require("./accounts/webSocketUserSt
7
7
  const pda_1 = require("./addresses/pda");
8
8
  class UserStats {
9
9
  constructor(config) {
10
- var _a;
10
+ var _a, _b;
11
11
  this.driftClient = config.driftClient;
12
12
  this.userStatsAccountPublicKey = config.userStatsAccountPublicKey;
13
13
  if (((_a = config.accountSubscription) === null || _a === void 0 ? void 0 : _a.type) === 'polling') {
14
14
  this.accountSubscriber = new pollingUserStatsAccountSubscriber_1.PollingUserStatsAccountSubscriber(config.driftClient.program, config.userStatsAccountPublicKey, config.accountSubscription.accountLoader);
15
15
  }
16
+ else if (((_b = config.accountSubscription) === null || _b === void 0 ? void 0 : _b.type) === 'custom') {
17
+ throw new Error('Custom account subscription not yet implemented for user stats');
18
+ }
16
19
  else {
17
20
  this.accountSubscriber = new webSocketUserStatsAccountSubsriber_1.WebSocketUserStatsAccountSubscriber(config.driftClient.program, config.userStatsAccountPublicKey);
18
21
  }
@@ -11,4 +11,6 @@ export type UserStatsSubscriptionConfig = {
11
11
  } | {
12
12
  type: 'polling';
13
13
  accountLoader: BulkAccountLoader;
14
+ } | {
15
+ type: 'custom';
14
16
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.31.1-beta.1",
3
+ "version": "2.31.1-beta.11",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -0,0 +1,53 @@
1
+ import { DataAndSlot, UserAccountEvents, UserAccountSubscriber } from './types';
2
+ import { PublicKey } from '@solana/web3.js';
3
+ import StrictEventEmitter from 'strict-event-emitter-types';
4
+ import { EventEmitter } from 'events';
5
+ import { UserAccount } from '../types';
6
+
7
+ export class MockUserAccountSubscriber implements UserAccountSubscriber {
8
+ isSubscribed: boolean;
9
+ eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
10
+ userAccountPublicKey: PublicKey;
11
+
12
+ callbackId?: string;
13
+ errorCallbackId?: string;
14
+
15
+ user: DataAndSlot<UserAccount>;
16
+
17
+ public constructor(
18
+ userAccountPublicKey: PublicKey,
19
+ data: UserAccount,
20
+ slot: number
21
+ ) {
22
+ this.isSubscribed = true;
23
+ this.eventEmitter = new EventEmitter();
24
+ this.userAccountPublicKey = userAccountPublicKey;
25
+ this.user = { data, slot };
26
+ }
27
+
28
+ async subscribe(_userAccount?: UserAccount): Promise<boolean> {
29
+ return true;
30
+ }
31
+
32
+ async addToAccountLoader(): Promise<void> {}
33
+
34
+ async fetch(): Promise<void> {}
35
+
36
+ doesAccountExist(): boolean {
37
+ return this.user !== undefined;
38
+ }
39
+
40
+ async unsubscribe(): Promise<void> {}
41
+
42
+ assertIsSubscribed(): void {}
43
+
44
+ public getUserAccountAndSlot(): DataAndSlot<UserAccount> {
45
+ return this.user;
46
+ }
47
+
48
+ public updateData(userAccount: UserAccount, slot: number): void {
49
+ this.user = { data: userAccount, slot };
50
+ this.eventEmitter.emit('userAccountUpdate', userAccount);
51
+ this.eventEmitter.emit('update');
52
+ }
53
+ }
package/src/config.ts CHANGED
@@ -131,7 +131,7 @@ export async function findAllMarketAndOracles(program: Program): Promise<{
131
131
  (await program.account.spotMarket.all()) as ProgramAccount<SpotMarketAccount>[];
132
132
 
133
133
  for (const perpMarketProgramAccount of perpMarketProgramAccounts) {
134
- const perpMarket = perpMarketProgramAccount.account;
134
+ const perpMarket = perpMarketProgramAccount.account as PerpMarketAccount;
135
135
  perpMarketIndexes.push(perpMarket.marketIndex);
136
136
  oracleInfos.set(perpMarket.amm.oracle.toString(), {
137
137
  publicKey: perpMarket.amm.oracle,
@@ -140,7 +140,7 @@ export async function findAllMarketAndOracles(program: Program): Promise<{
140
140
  }
141
141
 
142
142
  for (const spotMarketProgramAccount of spotMarketProgramAccounts) {
143
- const spotMarket = spotMarketProgramAccount.account;
143
+ const spotMarket = spotMarketProgramAccount.account as SpotMarketAccount;
144
144
  spotMarketIndexes.push(spotMarket.marketIndex);
145
145
  oracleInfos.set(spotMarket.oracle.toString(), {
146
146
  publicKey: spotMarket.oracle,
@@ -134,6 +134,16 @@ export const DevnetPerpMarkets: PerpMarketConfig[] = [
134
134
  launchTs: 1683125906000,
135
135
  oracleSource: OracleSource.PYTH,
136
136
  },
137
+ {
138
+ fullName: 'RNDR',
139
+ category: ['Infra'],
140
+ symbol: 'RNDR-PERP',
141
+ baseAssetSymbol: 'RNDR',
142
+ marketIndex: 12,
143
+ oracle: new PublicKey('C2QvUPBiU3fViSyqA4nZgGyYqLgYf9PRpd8B8oLoo48w'),
144
+ launchTs: 1683125906000,
145
+ oracleSource: OracleSource.PYTH,
146
+ },
137
147
  ];
138
148
 
139
149
  export const MainnetPerpMarkets: PerpMarketConfig[] = [
@@ -257,6 +267,16 @@ export const MainnetPerpMarkets: PerpMarketConfig[] = [
257
267
  launchTs: 1683125906000,
258
268
  oracleSource: OracleSource.PYTH,
259
269
  },
270
+ {
271
+ fullName: 'RNDR',
272
+ category: ['Infra'],
273
+ symbol: 'RNDR-PERP',
274
+ baseAssetSymbol: 'RNDR',
275
+ marketIndex: 12,
276
+ oracle: new PublicKey('CYGfrBJB9HgLf9iZyN4aH5HvUAi2htQ4MjPxeXMf4Egn'),
277
+ launchTs: 1683125906000,
278
+ oracleSource: OracleSource.PYTH,
279
+ },
260
280
  ];
261
281
 
262
282
  export const PerpMarkets: { [key in DriftEnv]: PerpMarketConfig[] } = {