@drift-labs/sdk 2.52.0-beta.0 → 2.52.0-beta.1

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.
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.52.0-beta.0
1
+ 2.52.0-beta.1
@@ -4,6 +4,10 @@ import { PublicKey } from '@solana/web3.js';
4
4
  import StrictEventEmitter from 'strict-event-emitter-types';
5
5
  import { EventEmitter } from 'events';
6
6
  import { UserAccount } from '../types';
7
+ /**
8
+ * Basic implementation of UserAccountSubscriber. It will only take in UserAccount
9
+ * data during initialization and will not fetch or subscribe to updates.
10
+ */
7
11
  export declare class BasicUserAccountSubscriber implements UserAccountSubscriber {
8
12
  isSubscribed: boolean;
9
13
  eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
@@ -2,6 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BasicUserAccountSubscriber = void 0;
4
4
  const events_1 = require("events");
5
+ /**
6
+ * Basic implementation of UserAccountSubscriber. It will only take in UserAccount
7
+ * data during initialization and will not fetch or subscribe to updates.
8
+ */
5
9
  class BasicUserAccountSubscriber {
6
10
  constructor(userAccountPublicKey, data, slot) {
7
11
  this.isSubscribed = true;
@@ -47,6 +47,7 @@ class BulkAccountLoader {
47
47
  if (existingAccountToLoad) {
48
48
  existingAccountToLoad.callbacks.delete(callbackId);
49
49
  if (existingAccountToLoad.callbacks.size === 0) {
50
+ this.bufferAndSlotMap.delete(publicKey.toString());
50
51
  this.accountsToLoad.delete(existingAccountToLoad.publicKey.toString());
51
52
  }
52
53
  }
@@ -107,7 +108,9 @@ class BulkAccountLoader {
107
108
  const requests = new Array();
108
109
  for (const accountsToLoadChunk of accountsToLoadChunks) {
109
110
  const args = [
110
- accountsToLoadChunk.map((accountToLoad) => {
111
+ accountsToLoadChunk
112
+ .filter((accountToLoad) => accountToLoad.callbacks.size > 0)
113
+ .map((accountToLoad) => {
111
114
  return accountToLoad.publicKey.toBase58();
112
115
  }),
113
116
  { commitment: this.commitment },
@@ -137,6 +140,9 @@ class BulkAccountLoader {
137
140
  }
138
141
  const accountsToLoad = accountsToLoadChunks[i];
139
142
  accountsToLoad.forEach((accountToLoad, j) => {
143
+ if (accountToLoad.callbacks.size === 0) {
144
+ return;
145
+ }
140
146
  const key = accountToLoad.publicKey.toBase58();
141
147
  const oldRPCResponse = this.bufferAndSlotMap.get(key);
142
148
  if (oldRPCResponse && newSlot < oldRPCResponse.slot) {
@@ -0,0 +1,17 @@
1
+ import { Commitment, PublicKey } from '@solana/web3.js';
2
+ import { UserAccount } from '../types';
3
+ import { BasicUserAccountSubscriber } from './basicUserAccountSubscriber';
4
+ import { Program } from '@coral-xyz/anchor';
5
+ /**
6
+ * Simple implementation of UserAccountSubscriber. It will fetch the UserAccount
7
+ * date on subscribe (or call to fetch) if no account data is provided on init.
8
+ * Expect to use only 1 RPC call unless you call fetch repeatedly.
9
+ */
10
+ export declare class OneShotUserAccountSubscriber extends BasicUserAccountSubscriber {
11
+ program: Program;
12
+ commitment: Commitment;
13
+ constructor(program: Program, userAccountPublicKey: PublicKey, data?: UserAccount, slot?: number, commitment?: Commitment);
14
+ subscribe(userAccount?: UserAccount): Promise<boolean>;
15
+ fetchIfUnloaded(): Promise<void>;
16
+ fetch(): Promise<void>;
17
+ }
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OneShotUserAccountSubscriber = void 0;
4
+ const basicUserAccountSubscriber_1 = require("./basicUserAccountSubscriber");
5
+ /**
6
+ * Simple implementation of UserAccountSubscriber. It will fetch the UserAccount
7
+ * date on subscribe (or call to fetch) if no account data is provided on init.
8
+ * Expect to use only 1 RPC call unless you call fetch repeatedly.
9
+ */
10
+ class OneShotUserAccountSubscriber extends basicUserAccountSubscriber_1.BasicUserAccountSubscriber {
11
+ constructor(program, userAccountPublicKey, data, slot, commitment) {
12
+ super(userAccountPublicKey, data, slot);
13
+ this.program = program;
14
+ this.commitment = commitment !== null && commitment !== void 0 ? commitment : 'confirmed';
15
+ }
16
+ async subscribe(userAccount) {
17
+ if (userAccount) {
18
+ this.user = { data: userAccount, slot: this.user.slot };
19
+ return true;
20
+ }
21
+ await this.fetchIfUnloaded();
22
+ if (this.doesAccountExist()) {
23
+ this.eventEmitter.emit('update');
24
+ }
25
+ return true;
26
+ }
27
+ async fetchIfUnloaded() {
28
+ if (this.user.data === undefined) {
29
+ await this.fetch();
30
+ }
31
+ }
32
+ async fetch() {
33
+ var _a, _b;
34
+ try {
35
+ const dataAndContext = await this.program.account.user.fetchAndContext(this.userAccountPublicKey, this.commitment);
36
+ if (dataAndContext.context.slot > ((_b = (_a = this.user) === null || _a === void 0 ? void 0 : _a.slot) !== null && _b !== void 0 ? _b : 0)) {
37
+ this.user = {
38
+ data: dataAndContext.data,
39
+ slot: dataAndContext.context.slot,
40
+ };
41
+ }
42
+ }
43
+ catch (e) {
44
+ console.error(`OneShotUserAccountSubscriber.fetch() UserAccount does not exist: ${e.message}`);
45
+ }
46
+ }
47
+ }
48
+ exports.OneShotUserAccountSubscriber = OneShotUserAccountSubscriber;
@@ -22,6 +22,7 @@ class PollingInsuranceFundStakeAccountSubscriber {
22
22
  };
23
23
  }
24
24
  await this.addToAccountLoader();
25
+ await this.fetchIfUnloaded();
25
26
  if (this.doesAccountExist()) {
26
27
  this.eventEmitter.emit('update');
27
28
  }
@@ -54,6 +54,7 @@ export declare class AdminClient extends DriftClient {
54
54
  updateSpotMarketOracle(spotMarketIndex: number, oracle: PublicKey, oracleSource: OracleSource): Promise<TransactionSignature>;
55
55
  updateSpotMarketOrdersEnabled(spotMarketIndex: number, ordersEnabled: boolean): Promise<TransactionSignature>;
56
56
  updateSerumFulfillmentConfigStatus(serumFulfillmentConfig: PublicKey, status: SpotFulfillmentConfigStatus): Promise<TransactionSignature>;
57
+ updatePhoenixFulfillmentConfigStatus(phoenixFulfillmentConfig: PublicKey, status: SpotFulfillmentConfigStatus): Promise<TransactionSignature>;
57
58
  updateSpotMarketExpiry(spotMarketIndex: number, expiryTs: BN): Promise<TransactionSignature>;
58
59
  updateWhitelistMint(whitelistMint?: PublicKey): Promise<TransactionSignature>;
59
60
  updateDiscountMint(discountMint: PublicKey): Promise<TransactionSignature>;
@@ -626,6 +626,15 @@ class AdminClient extends driftClient_1.DriftClient {
626
626
  },
627
627
  });
628
628
  }
629
+ async updatePhoenixFulfillmentConfigStatus(phoenixFulfillmentConfig, status) {
630
+ return await this.program.rpc.phoenixFulfillmentConfigStatus(status, {
631
+ accounts: {
632
+ admin: this.wallet.publicKey,
633
+ state: await this.getStatePublicKey(),
634
+ phoenixFulfillmentConfig,
635
+ },
636
+ });
637
+ }
629
638
  async updateSpotMarketExpiry(spotMarketIndex, expiryTs) {
630
639
  return await this.program.rpc.updateSpotMarketExpiry(expiryTs, {
631
640
  accounts: {
@@ -61,3 +61,6 @@ export declare const LAMPORTS_PRECISION: BN;
61
61
  export declare const LAMPORTS_EXP: BN;
62
62
  export declare const OPEN_ORDER_MARGIN_REQUIREMENT: BN;
63
63
  export declare const DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT: BN;
64
+ export declare const ACCOUNT_AGE_DELETION_CUTOFF_SECONDS: number;
65
+ export declare const IDLE_TIME_SLOTS = 9000;
66
+ export declare const SLOT_TIME_ESTIMATE_MS = 400;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MARGIN_PRECISION = exports.AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO = exports.PRICE_TO_QUOTE_PRECISION = exports.PRICE_DIV_PEG = exports.AMM_TO_QUOTE_PRECISION_RATIO = exports.BASE_PRECISION_EXP = exports.BASE_PRECISION = exports.AMM_RESERVE_PRECISION = exports.PEG_PRECISION = exports.FUNDING_RATE_BUFFER_PRECISION = exports.FUNDING_RATE_PRECISION = exports.PRICE_PRECISION = exports.QUOTE_PRECISION = exports.LIQUIDATION_FEE_PRECISION = exports.SPOT_MARKET_IMF_PRECISION = exports.SPOT_MARKET_IMF_PRECISION_EXP = exports.SPOT_MARKET_BALANCE_PRECISION = exports.SPOT_MARKET_BALANCE_PRECISION_EXP = exports.SPOT_MARKET_WEIGHT_PRECISION = exports.SPOT_MARKET_UTILIZATION_PRECISION = exports.SPOT_MARKET_UTILIZATION_PRECISION_EXP = exports.SPOT_MARKET_CUMULATIVE_INTEREST_PRECISION = exports.SPOT_MARKET_CUMULATIVE_INTEREST_PRECISION_EXP = exports.SPOT_MARKET_RATE_PRECISION = exports.SPOT_MARKET_RATE_PRECISION_EXP = exports.AMM_RESERVE_PRECISION_EXP = exports.PEG_PRECISION_EXP = exports.FUNDING_RATE_PRECISION_EXP = exports.PRICE_PRECISION_EXP = exports.FUNDING_RATE_BUFFER_PRECISION_EXP = exports.QUOTE_PRECISION_EXP = exports.CONCENTRATION_PRECISION = exports.PERCENTAGE_PRECISION = exports.PERCENTAGE_PRECISION_EXP = exports.MAX_LEVERAGE_ORDER_SIZE = exports.MAX_LEVERAGE = exports.TEN_MILLION = exports.BN_MAX = exports.TEN_THOUSAND = exports.TEN = exports.NINE = exports.EIGHT = exports.SEVEN = exports.SIX = exports.FIVE = exports.FOUR = exports.THREE = exports.TWO = exports.ONE = exports.ZERO = void 0;
4
- exports.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT = exports.OPEN_ORDER_MARGIN_REQUIREMENT = exports.LAMPORTS_EXP = exports.LAMPORTS_PRECISION = exports.QUOTE_SPOT_MARKET_INDEX = exports.ONE_YEAR = exports.ONE_HOUR = exports.FIVE_MINUTE = exports.FUNDING_RATE_OFFSET_DENOMINATOR = exports.LIQUIDATION_PCT_PRECISION = exports.BID_ASK_SPREAD_PRECISION = void 0;
4
+ exports.SLOT_TIME_ESTIMATE_MS = exports.IDLE_TIME_SLOTS = exports.ACCOUNT_AGE_DELETION_CUTOFF_SECONDS = exports.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT = exports.OPEN_ORDER_MARGIN_REQUIREMENT = exports.LAMPORTS_EXP = exports.LAMPORTS_PRECISION = exports.QUOTE_SPOT_MARKET_INDEX = exports.ONE_YEAR = exports.ONE_HOUR = exports.FIVE_MINUTE = exports.FUNDING_RATE_OFFSET_DENOMINATOR = exports.LIQUIDATION_PCT_PRECISION = exports.BID_ASK_SPREAD_PRECISION = void 0;
5
5
  const web3_js_1 = require("@solana/web3.js");
6
6
  const __1 = require("../");
7
7
  exports.ZERO = new __1.BN(0);
@@ -65,3 +65,6 @@ exports.LAMPORTS_PRECISION = new __1.BN(web3_js_1.LAMPORTS_PER_SOL);
65
65
  exports.LAMPORTS_EXP = new __1.BN(Math.log10(web3_js_1.LAMPORTS_PER_SOL));
66
66
  exports.OPEN_ORDER_MARGIN_REQUIREMENT = exports.QUOTE_PRECISION.div(new __1.BN(100));
67
67
  exports.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT = new __1.BN(-25).mul(exports.QUOTE_PRECISION);
68
+ exports.ACCOUNT_AGE_DELETION_CUTOFF_SECONDS = 60 * 60 * 24 * 13; // 13 days
69
+ exports.IDLE_TIME_SLOTS = 9000;
70
+ exports.SLOT_TIME_ESTIMATE_MS = 400;
@@ -133,6 +133,7 @@ export declare class DriftClient {
133
133
  getUserAccountsForAuthority(authority: PublicKey): Promise<UserAccount[]>;
134
134
  getReferredUserStatsAccountsByReferrer(referrer: PublicKey): Promise<UserStatsAccount[]>;
135
135
  getReferrerNameAccountsForAuthority(authority: PublicKey): Promise<ReferrerNameAccount[]>;
136
+ getUserDeletionIx(userAccountPublicKey: PublicKey): Promise<anchor.web3.TransactionInstruction>;
136
137
  deleteUser(subAccountId?: number, txParams?: TxParams): Promise<TransactionSignature>;
137
138
  getUser(subAccountId?: number, authority?: PublicKey): User;
138
139
  hasUser(subAccountId?: number, authority?: PublicKey): boolean;
@@ -665,9 +665,7 @@ class DriftClient {
665
665
  ]);
666
666
  return programAccounts.map((programAccount) => programAccount.account);
667
667
  }
668
- async deleteUser(subAccountId = 0, txParams) {
669
- var _a;
670
- const userAccountPublicKey = (0, pda_1.getUserAccountPublicKeySync)(this.program.programId, this.wallet.publicKey, subAccountId);
668
+ async getUserDeletionIx(userAccountPublicKey) {
671
669
  const ix = await this.program.instruction.deleteUser({
672
670
  accounts: {
673
671
  user: userAccountPublicKey,
@@ -676,6 +674,12 @@ class DriftClient {
676
674
  state: await this.getStatePublicKey(),
677
675
  },
678
676
  });
677
+ return ix;
678
+ }
679
+ async deleteUser(subAccountId = 0, txParams) {
680
+ var _a;
681
+ const userAccountPublicKey = (0, pda_1.getUserAccountPublicKeySync)(this.program.programId, this.wallet.publicKey, subAccountId);
682
+ const ix = await this.getUserDeletionIx(userAccountPublicKey);
679
683
  const { txSig } = await this.sendTransaction(await this.buildTransaction(ix, txParams), [], this.opts);
680
684
  const userMapKey = this.getUserMapKey(subAccountId, this.wallet.publicKey);
681
685
  await ((_a = this.users.get(userMapKey)) === null || _a === void 0 ? void 0 : _a.unsubscribe());
package/lib/index.d.ts CHANGED
@@ -20,6 +20,7 @@ export * from './accounts/pollingUserAccountSubscriber';
20
20
  export * from './accounts/pollingUserStatsAccountSubscriber';
21
21
  export * from './accounts/pollingInsuranceFundStakeAccountSubscriber';
22
22
  export * from './accounts/basicUserAccountSubscriber';
23
+ export * from './accounts/oneShotUserAccountSubscriber';
23
24
  export * from './accounts/types';
24
25
  export * from './addresses/pda';
25
26
  export * from './adminClient';
package/lib/index.js CHANGED
@@ -43,6 +43,7 @@ __exportStar(require("./accounts/pollingUserAccountSubscriber"), exports);
43
43
  __exportStar(require("./accounts/pollingUserStatsAccountSubscriber"), exports);
44
44
  __exportStar(require("./accounts/pollingInsuranceFundStakeAccountSubscriber"), exports);
45
45
  __exportStar(require("./accounts/basicUserAccountSubscriber"), exports);
46
+ __exportStar(require("./accounts/oneShotUserAccountSubscriber"), exports);
46
47
  __exportStar(require("./accounts/types"), exports);
47
48
  __exportStar(require("./addresses/pda"), exports);
48
49
  __exportStar(require("./adminClient"), exports);
@@ -73,7 +73,7 @@ class UserMap {
73
73
  userAccountPublicKey,
74
74
  accountSubscription: {
75
75
  type: 'custom',
76
- userAccountSubscriber: new __1.BasicUserAccountSubscriber(userAccountPublicKey, userAccount, slot),
76
+ userAccountSubscriber: new __1.OneShotUserAccountSubscriber(this.driftClient.program, userAccountPublicKey, userAccount, slot, this.commitment),
77
77
  },
78
78
  });
79
79
  await user.subscribe(userAccount);
@@ -15,4 +15,5 @@ export declare class UserStats {
15
15
  getAccountAndSlot(): DataAndSlot<UserStatsAccount>;
16
16
  getAccount(): UserStatsAccount;
17
17
  getReferrerInfo(): ReferrerInfo | undefined;
18
+ static getOldestActionTs(account: UserStatsAccount): number;
18
19
  }
package/lib/userStats.js CHANGED
@@ -48,5 +48,8 @@ class UserStats {
48
48
  };
49
49
  }
50
50
  }
51
+ static getOldestActionTs(account) {
52
+ return Math.min(account.lastFillerVolume30DTs.toNumber(), account.lastMakerVolume30DTs.toNumber(), account.lastTakerVolume30DTs.toNumber());
53
+ }
51
54
  }
52
55
  exports.UserStats = UserStats;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.52.0-beta.0",
3
+ "version": "2.52.0-beta.1",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -4,6 +4,10 @@ import StrictEventEmitter from 'strict-event-emitter-types';
4
4
  import { EventEmitter } from 'events';
5
5
  import { UserAccount } from '../types';
6
6
 
7
+ /**
8
+ * Basic implementation of UserAccountSubscriber. It will only take in UserAccount
9
+ * data during initialization and will not fetch or subscribe to updates.
10
+ */
7
11
  export class BasicUserAccountSubscriber implements UserAccountSubscriber {
8
12
  isSubscribed: boolean;
9
13
  eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
@@ -78,6 +78,7 @@ export class BulkAccountLoader {
78
78
  if (existingAccountToLoad) {
79
79
  existingAccountToLoad.callbacks.delete(callbackId);
80
80
  if (existingAccountToLoad.callbacks.size === 0) {
81
+ this.bufferAndSlotMap.delete(publicKey.toString());
81
82
  this.accountsToLoad.delete(existingAccountToLoad.publicKey.toString());
82
83
  }
83
84
  }
@@ -153,9 +154,11 @@ export class BulkAccountLoader {
153
154
  const requests = new Array<{ methodName: string; args: any }>();
154
155
  for (const accountsToLoadChunk of accountsToLoadChunks) {
155
156
  const args = [
156
- accountsToLoadChunk.map((accountToLoad) => {
157
- return accountToLoad.publicKey.toBase58();
158
- }),
157
+ accountsToLoadChunk
158
+ .filter((accountToLoad) => accountToLoad.callbacks.size > 0)
159
+ .map((accountToLoad) => {
160
+ return accountToLoad.publicKey.toBase58();
161
+ }),
159
162
  { commitment: this.commitment },
160
163
  ];
161
164
 
@@ -190,6 +193,10 @@ export class BulkAccountLoader {
190
193
 
191
194
  const accountsToLoad = accountsToLoadChunks[i];
192
195
  accountsToLoad.forEach((accountToLoad, j) => {
196
+ if (accountToLoad.callbacks.size === 0) {
197
+ return;
198
+ }
199
+
193
200
  const key = accountToLoad.publicKey.toBase58();
194
201
  const oldRPCResponse = this.bufferAndSlotMap.get(key);
195
202
 
@@ -0,0 +1,64 @@
1
+ import { Commitment, PublicKey } from '@solana/web3.js';
2
+ import { UserAccount } from '../types';
3
+ import { BasicUserAccountSubscriber } from './basicUserAccountSubscriber';
4
+ import { Program } from '@coral-xyz/anchor';
5
+
6
+ /**
7
+ * Simple implementation of UserAccountSubscriber. It will fetch the UserAccount
8
+ * date on subscribe (or call to fetch) if no account data is provided on init.
9
+ * Expect to use only 1 RPC call unless you call fetch repeatedly.
10
+ */
11
+ export class OneShotUserAccountSubscriber extends BasicUserAccountSubscriber {
12
+ program: Program;
13
+ commitment: Commitment;
14
+
15
+ public constructor(
16
+ program: Program,
17
+ userAccountPublicKey: PublicKey,
18
+ data?: UserAccount,
19
+ slot?: number,
20
+ commitment?: Commitment
21
+ ) {
22
+ super(userAccountPublicKey, data, slot);
23
+ this.program = program;
24
+ this.commitment = commitment ?? 'confirmed';
25
+ }
26
+
27
+ async subscribe(userAccount?: UserAccount): Promise<boolean> {
28
+ if (userAccount) {
29
+ this.user = { data: userAccount, slot: this.user.slot };
30
+ return true;
31
+ }
32
+
33
+ await this.fetchIfUnloaded();
34
+ if (this.doesAccountExist()) {
35
+ this.eventEmitter.emit('update');
36
+ }
37
+ return true;
38
+ }
39
+
40
+ async fetchIfUnloaded(): Promise<void> {
41
+ if (this.user.data === undefined) {
42
+ await this.fetch();
43
+ }
44
+ }
45
+
46
+ async fetch(): Promise<void> {
47
+ try {
48
+ const dataAndContext = await this.program.account.user.fetchAndContext(
49
+ this.userAccountPublicKey,
50
+ this.commitment
51
+ );
52
+ if (dataAndContext.context.slot > (this.user?.slot ?? 0)) {
53
+ this.user = {
54
+ data: dataAndContext.data as UserAccount,
55
+ slot: dataAndContext.context.slot,
56
+ };
57
+ }
58
+ } catch (e) {
59
+ console.error(
60
+ `OneShotUserAccountSubscriber.fetch() UserAccount does not exist: ${e.message}`
61
+ );
62
+ }
63
+ }
64
+ }
@@ -54,6 +54,7 @@ export class PollingInsuranceFundStakeAccountSubscriber
54
54
 
55
55
  await this.addToAccountLoader();
56
56
 
57
+ await this.fetchIfUnloaded();
57
58
  if (this.doesAccountExist()) {
58
59
  this.eventEmitter.emit('update');
59
60
  }
@@ -1181,6 +1181,19 @@ export class AdminClient extends DriftClient {
1181
1181
  });
1182
1182
  }
1183
1183
 
1184
+ public async updatePhoenixFulfillmentConfigStatus(
1185
+ phoenixFulfillmentConfig: PublicKey,
1186
+ status: SpotFulfillmentConfigStatus
1187
+ ): Promise<TransactionSignature> {
1188
+ return await this.program.rpc.phoenixFulfillmentConfigStatus(status, {
1189
+ accounts: {
1190
+ admin: this.wallet.publicKey,
1191
+ state: await this.getStatePublicKey(),
1192
+ phoenixFulfillmentConfig,
1193
+ },
1194
+ });
1195
+ }
1196
+
1184
1197
  public async updateSpotMarketExpiry(
1185
1198
  spotMarketIndex: number,
1186
1199
  expiryTs: BN
@@ -99,3 +99,7 @@ export const OPEN_ORDER_MARGIN_REQUIREMENT = QUOTE_PRECISION.div(new BN(100));
99
99
  export const DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT = new BN(
100
100
  -25
101
101
  ).mul(QUOTE_PRECISION);
102
+
103
+ export const ACCOUNT_AGE_DELETION_CUTOFF_SECONDS = 60 * 60 * 24 * 13; // 13 days
104
+ export const IDLE_TIME_SLOTS = 9000;
105
+ export const SLOT_TIME_ESTIMATE_MS = 400;
@@ -1112,6 +1112,19 @@ export class DriftClient {
1112
1112
  );
1113
1113
  }
1114
1114
 
1115
+ public async getUserDeletionIx(userAccountPublicKey: PublicKey) {
1116
+ const ix = await this.program.instruction.deleteUser({
1117
+ accounts: {
1118
+ user: userAccountPublicKey,
1119
+ userStats: this.getUserStatsAccountPublicKey(),
1120
+ authority: this.wallet.publicKey,
1121
+ state: await this.getStatePublicKey(),
1122
+ },
1123
+ });
1124
+
1125
+ return ix;
1126
+ }
1127
+
1115
1128
  public async deleteUser(
1116
1129
  subAccountId = 0,
1117
1130
  txParams?: TxParams
@@ -1122,14 +1135,7 @@ export class DriftClient {
1122
1135
  subAccountId
1123
1136
  );
1124
1137
 
1125
- const ix = await this.program.instruction.deleteUser({
1126
- accounts: {
1127
- user: userAccountPublicKey,
1128
- userStats: this.getUserStatsAccountPublicKey(),
1129
- authority: this.wallet.publicKey,
1130
- state: await this.getStatePublicKey(),
1131
- },
1132
- });
1138
+ const ix = await this.getUserDeletionIx(userAccountPublicKey);
1133
1139
 
1134
1140
  const { txSig } = await this.sendTransaction(
1135
1141
  await this.buildTransaction(ix, txParams),
package/src/index.ts CHANGED
@@ -21,6 +21,7 @@ export * from './accounts/pollingUserAccountSubscriber';
21
21
  export * from './accounts/pollingUserStatsAccountSubscriber';
22
22
  export * from './accounts/pollingInsuranceFundStakeAccountSubscriber';
23
23
  export * from './accounts/basicUserAccountSubscriber';
24
+ export * from './accounts/oneShotUserAccountSubscriber';
24
25
  export * from './accounts/types';
25
26
  export * from './addresses/pda';
26
27
  export * from './adminClient';
@@ -13,7 +13,7 @@ import {
13
13
  LPRecord,
14
14
  StateAccount,
15
15
  DLOB,
16
- BasicUserAccountSubscriber,
16
+ OneShotUserAccountSubscriber,
17
17
  BN,
18
18
  } from '..';
19
19
 
@@ -132,10 +132,12 @@ export class UserMap implements UserMapInterface {
132
132
  userAccountPublicKey,
133
133
  accountSubscription: {
134
134
  type: 'custom',
135
- userAccountSubscriber: new BasicUserAccountSubscriber(
135
+ userAccountSubscriber: new OneShotUserAccountSubscriber(
136
+ this.driftClient.program,
136
137
  userAccountPublicKey,
137
138
  userAccount,
138
- slot
139
+ slot,
140
+ this.commitment
139
141
  ),
140
142
  },
141
143
  });
package/src/userStats.ts CHANGED
@@ -82,4 +82,12 @@ export class UserStats {
82
82
  };
83
83
  }
84
84
  }
85
+
86
+ public static getOldestActionTs(account: UserStatsAccount): number {
87
+ return Math.min(
88
+ account.lastFillerVolume30DTs.toNumber(),
89
+ account.lastMakerVolume30DTs.toNumber(),
90
+ account.lastTakerVolume30DTs.toNumber()
91
+ );
92
+ }
85
93
  }