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

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 (100) hide show
  1. package/VERSION +1 -1
  2. package/examples/phoenix.ts +11 -4
  3. package/lib/accounts/basicUserAccountSubscriber.d.ts +4 -0
  4. package/lib/accounts/basicUserAccountSubscriber.js +4 -0
  5. package/lib/accounts/bulkAccountLoader.js +7 -1
  6. package/lib/accounts/oneShotUserAccountSubscriber.d.ts +17 -0
  7. package/lib/accounts/oneShotUserAccountSubscriber.js +48 -0
  8. package/lib/accounts/pollingInsuranceFundStakeAccountSubscriber.js +1 -0
  9. package/lib/accounts/webSocketAccountSubscriber.d.ts +1 -1
  10. package/lib/accounts/webSocketAccountSubscriber.js +7 -4
  11. package/lib/accounts/webSocketProgramAccountSubscriber.d.ts +1 -1
  12. package/lib/accounts/webSocketProgramAccountSubscriber.js +7 -4
  13. package/lib/adminClient.d.ts +1 -0
  14. package/lib/adminClient.js +9 -0
  15. package/lib/constants/numericConstants.d.ts +3 -0
  16. package/lib/constants/numericConstants.js +4 -1
  17. package/lib/dlob/orderBookLevels.d.ts +22 -0
  18. package/lib/dlob/orderBookLevels.js +115 -1
  19. package/lib/driftClient.d.ts +3 -0
  20. package/lib/driftClient.js +31 -5
  21. package/lib/events/webSocketLogProvider.js +3 -3
  22. package/lib/factory/bigNum.d.ts +1 -1
  23. package/lib/factory/bigNum.js +5 -2
  24. package/lib/idl/drift.json +52 -1
  25. package/lib/index.d.ts +2 -1
  26. package/lib/index.js +2 -1
  27. package/lib/math/amm.d.ts +5 -1
  28. package/lib/math/amm.js +62 -13
  29. package/lib/math/state.js +3 -0
  30. package/lib/orderSubscriber/OrderSubscriber.js +1 -0
  31. package/lib/orderSubscriber/WebsocketSubscription.d.ts +4 -1
  32. package/lib/orderSubscriber/WebsocketSubscription.js +25 -1
  33. package/lib/orderSubscriber/types.d.ts +1 -0
  34. package/lib/phoenix/phoenixSubscriber.js +10 -6
  35. package/lib/priorityFee/averageOverSlotsStrategy.d.ts +12 -0
  36. package/lib/priorityFee/averageOverSlotsStrategy.js +28 -0
  37. package/lib/priorityFee/averageStrategy.d.ts +7 -0
  38. package/lib/priorityFee/averageStrategy.js +11 -0
  39. package/lib/priorityFee/ewmaStrategy.d.ts +13 -0
  40. package/lib/priorityFee/ewmaStrategy.js +33 -0
  41. package/lib/priorityFee/index.d.ts +7 -0
  42. package/lib/priorityFee/index.js +23 -0
  43. package/lib/priorityFee/maxOverSlotsStrategy.d.ts +12 -0
  44. package/lib/priorityFee/maxOverSlotsStrategy.js +29 -0
  45. package/lib/priorityFee/maxStrategy.d.ts +7 -0
  46. package/lib/priorityFee/maxStrategy.js +9 -0
  47. package/lib/priorityFee/priorityFeeSubscriber.d.ts +15 -4
  48. package/lib/priorityFee/priorityFeeSubscriber.js +38 -14
  49. package/lib/priorityFee/types.d.ts +6 -0
  50. package/lib/priorityFee/types.js +2 -0
  51. package/lib/slot/SlotSubscriber.d.ts +11 -3
  52. package/lib/slot/SlotSubscriber.js +40 -4
  53. package/lib/types.d.ts +4 -1
  54. package/lib/types.js +1 -0
  55. package/lib/user.d.ts +1 -1
  56. package/lib/user.js +15 -8
  57. package/lib/userMap/userMap.d.ts +3 -0
  58. package/lib/userMap/userMap.js +10 -1
  59. package/lib/userStats.d.ts +1 -0
  60. package/lib/userStats.js +3 -0
  61. package/package.json +1 -1
  62. package/src/accounts/basicUserAccountSubscriber.ts +4 -0
  63. package/src/accounts/bulkAccountLoader.ts +10 -3
  64. package/src/accounts/oneShotUserAccountSubscriber.ts +64 -0
  65. package/src/accounts/pollingInsuranceFundStakeAccountSubscriber.ts +1 -0
  66. package/src/accounts/webSocketAccountSubscriber.ts +7 -4
  67. package/src/accounts/webSocketProgramAccountSubscriber.ts +7 -4
  68. package/src/adminClient.ts +13 -0
  69. package/src/constants/numericConstants.ts +4 -0
  70. package/src/dlob/orderBookLevels.ts +136 -0
  71. package/src/driftClient.ts +50 -6
  72. package/src/events/webSocketLogProvider.ts +3 -3
  73. package/src/factory/bigNum.ts +11 -2
  74. package/src/idl/drift.json +52 -1
  75. package/src/index.ts +2 -1
  76. package/src/math/amm.ts +159 -25
  77. package/src/math/state.ts +3 -0
  78. package/src/orderSubscriber/OrderSubscriber.ts +1 -0
  79. package/src/orderSubscriber/WebsocketSubscription.ts +28 -0
  80. package/src/orderSubscriber/types.ts +1 -0
  81. package/src/phoenix/phoenixSubscriber.ts +14 -8
  82. package/src/priorityFee/averageOverSlotsStrategy.ts +30 -0
  83. package/src/priorityFee/averageStrategy.ts +11 -0
  84. package/src/priorityFee/ewmaStrategy.ts +40 -0
  85. package/src/priorityFee/index.ts +7 -0
  86. package/src/priorityFee/maxOverSlotsStrategy.ts +31 -0
  87. package/src/priorityFee/maxStrategy.ts +7 -0
  88. package/src/priorityFee/priorityFeeSubscriber.ts +46 -19
  89. package/src/priorityFee/types.ts +5 -0
  90. package/src/slot/SlotSubscriber.ts +52 -5
  91. package/src/types.ts +2 -1
  92. package/src/user.ts +25 -8
  93. package/src/userMap/userMap.ts +17 -3
  94. package/src/userStats.ts +8 -0
  95. package/tests/amm/test.ts +219 -11
  96. package/tests/bn/test.ts +27 -0
  97. package/tests/dlob/helpers.ts +1 -1
  98. package/tests/dlob/test.ts +372 -2
  99. package/tests/tx/priorityFeeStrategy.ts +97 -0
  100. package/tests/user/helpers.ts +1 -0
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.52.0-beta.0
1
+ 2.52.0-beta.10
@@ -1,5 +1,5 @@
1
1
  import { Connection, PublicKey } from '@solana/web3.js';
2
- import { PRICE_PRECISION, PhoenixSubscriber } from '../src';
2
+ import { BASE_PRECISION, PRICE_PRECISION, PhoenixSubscriber } from '../src';
3
3
  import { PROGRAM_ID } from '@ellipsis-labs/phoenix-sdk';
4
4
 
5
5
  export async function listenToBook(): Promise<void> {
@@ -19,9 +19,16 @@ export async function listenToBook(): Promise<void> {
19
19
  await phoenixSubscriber.subscribe();
20
20
 
21
21
  for (let i = 0; i < 10; i++) {
22
- const bid = phoenixSubscriber.getBestBid().toNumber() / PRICE_PRECISION;
23
- const ask = phoenixSubscriber.getBestAsk().toNumber() / PRICE_PRECISION;
24
- console.log(`iter ${i}:`, bid.toFixed(3), '@', ask.toFixed(3));
22
+ const bids = phoenixSubscriber.getL2Levels("bids");
23
+ const asks = phoenixSubscriber.getL2Levels("asks");
24
+ console.log("bids");
25
+ for (const bid of bids) {
26
+ console.log(bid.price.toNumber() / PRICE_PRECISION.toNumber(), bid.size.toNumber() / BASE_PRECISION.toNumber());
27
+ }
28
+ console.log("asks");
29
+ for (const ask of asks) {
30
+ console.log(ask.price.toNumber() / PRICE_PRECISION.toNumber(), ask.size.toNumber() / BASE_PRECISION.toNumber());
31
+ }
25
32
  await new Promise((r) => setTimeout(r, 2000));
26
33
  }
27
34
 
@@ -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
  }
@@ -24,5 +24,5 @@ export declare class WebSocketAccountSubscriber<T> implements AccountSubscriber<
24
24
  fetch(): Promise<void>;
25
25
  handleRpcResponse(context: Context, accountInfo?: AccountInfo<Buffer>): void;
26
26
  decodeBuffer(buffer: Buffer): T;
27
- unsubscribe(): Promise<void>;
27
+ unsubscribe(onResub?: boolean): Promise<void>;
28
28
  }
@@ -15,7 +15,7 @@ class WebSocketAccountSubscriber {
15
15
  commitment !== null && commitment !== void 0 ? commitment : this.program.provider.opts.commitment;
16
16
  }
17
17
  async subscribe(onChange) {
18
- if (this.listenerId || this.isUnsubscribing) {
18
+ if (this.listenerId != null || this.isUnsubscribing) {
19
19
  return;
20
20
  }
21
21
  this.onChange = onChange;
@@ -58,7 +58,7 @@ class WebSocketAccountSubscriber {
58
58
  }
59
59
  if (this.receivingData) {
60
60
  console.log(`No ws data from ${this.accountName} in ${this.resubTimeoutMs}ms, resubscribing`);
61
- await this.unsubscribe();
61
+ await this.unsubscribe(true);
62
62
  this.receivingData = false;
63
63
  await this.subscribe(this.onChange);
64
64
  }
@@ -114,11 +114,14 @@ class WebSocketAccountSubscriber {
114
114
  return this.program.account[this.accountName].coder.accounts.decode((0, utils_1.capitalize)(this.accountName), buffer);
115
115
  }
116
116
  }
117
- unsubscribe() {
117
+ unsubscribe(onResub = false) {
118
+ if (!onResub) {
119
+ this.resubTimeoutMs = undefined;
120
+ }
118
121
  this.isUnsubscribing = true;
119
122
  clearTimeout(this.timeoutId);
120
123
  this.timeoutId = undefined;
121
- if (this.listenerId) {
124
+ if (this.listenerId != null) {
122
125
  const promise = this.program.provider.connection
123
126
  .removeAccountChangeListener(this.listenerId)
124
127
  .then(() => {
@@ -29,5 +29,5 @@ export declare class WebSocketProgramAccountSubscriber<T> implements ProgramAcco
29
29
  subscribe(onChange: (accountId: PublicKey, data: T, context: Context) => void): Promise<void>;
30
30
  private setTimeout;
31
31
  handleRpcResponse(context: Context, keyedAccountInfo: KeyedAccountInfo): void;
32
- unsubscribe(): Promise<void>;
32
+ unsubscribe(onResub?: boolean): Promise<void>;
33
33
  }
@@ -17,7 +17,7 @@ class WebSocketProgramAccountSubscriber {
17
17
  }
18
18
  async subscribe(onChange) {
19
19
  var _a;
20
- if (this.listenerId || this.isUnsubscribing) {
20
+ if (this.listenerId != null || this.isUnsubscribing) {
21
21
  return;
22
22
  }
23
23
  this.onChange = onChange;
@@ -47,7 +47,7 @@ class WebSocketProgramAccountSubscriber {
47
47
  }
48
48
  if (this.receivingData) {
49
49
  console.log(`No ws data from ${this.subscriptionName} in ${this.resubTimeoutMs}ms, resubscribing`);
50
- await this.unsubscribe();
50
+ await this.unsubscribe(true);
51
51
  this.receivingData = false;
52
52
  await this.subscribe(this.onChange);
53
53
  }
@@ -93,11 +93,14 @@ class WebSocketProgramAccountSubscriber {
93
93
  this.onChange(keyedAccountInfo.accountId, account, context);
94
94
  }
95
95
  }
96
- unsubscribe() {
96
+ unsubscribe(onResub = false) {
97
+ if (!onResub) {
98
+ this.resubTimeoutMs = undefined;
99
+ }
97
100
  this.isUnsubscribing = true;
98
101
  clearTimeout(this.timeoutId);
99
102
  this.timeoutId = undefined;
100
- if (this.listenerId) {
103
+ if (this.listenerId != null) {
101
104
  const promise = this.program.provider.connection
102
105
  .removeAccountChangeListener(this.listenerId)
103
106
  .then(() => {
@@ -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;
@@ -47,4 +47,26 @@ export declare function getVammL2Generator({ marketAccount, oraclePriceData, num
47
47
  topOfBookQuoteAmounts?: BN[];
48
48
  }): L2OrderBookGenerator;
49
49
  export declare function groupL2(l2: L2OrderBook, grouping: BN, depth: number): L2OrderBook;
50
+ /**
51
+ * The purpose of this function is uncross the L2 orderbook by modifying the bid/ask price at the top of the book
52
+ * This will make the liquidity look worse but more intuitive (users familiar with clob get confused w temporarily
53
+ * crossing book)
54
+ *
55
+ * Things to note about how it works:
56
+ * - it will not uncross the user's liquidity
57
+ * - it does the uncrossing by "shifting" the crossing liquidity to the nearest uncrossed levels. Thus the output liquidity maintains the same total size.
58
+ *
59
+ * @param bids
60
+ * @param asks
61
+ * @param oraclePrice
62
+ * @param oracleTwap5Min
63
+ * @param markTwap5Min
64
+ * @param grouping
65
+ * @param userBids
66
+ * @param userAsks
67
+ */
68
+ export declare function uncrossL2(bids: L2Level[], asks: L2Level[], oraclePrice: BN, oracleTwap5Min: BN, markTwap5Min: BN, grouping: BN, userBids: Set<string>, userAsks: Set<string>): {
69
+ bids: L2Level[];
70
+ asks: L2Level[];
71
+ };
50
72
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.groupL2 = exports.getVammL2Generator = exports.createL2Levels = exports.mergeL2LevelGenerators = exports.getL2GeneratorFromDLOBNodes = exports.DEFAULT_TOP_OF_BOOK_QUOTE_AMOUNTS = void 0;
3
+ exports.uncrossL2 = exports.groupL2 = exports.getVammL2Generator = exports.createL2Levels = exports.mergeL2LevelGenerators = exports.getL2GeneratorFromDLOBNodes = exports.DEFAULT_TOP_OF_BOOK_QUOTE_AMOUNTS = void 0;
4
4
  const __1 = require("..");
5
5
  const assert_1 = require("../assert/assert");
6
6
  exports.DEFAULT_TOP_OF_BOOK_QUOTE_AMOUNTS = [
@@ -245,3 +245,117 @@ function groupL2Levels(levels, grouping, direction, depth) {
245
245
  }
246
246
  return groupedLevels;
247
247
  }
248
+ /**
249
+ * The purpose of this function is uncross the L2 orderbook by modifying the bid/ask price at the top of the book
250
+ * This will make the liquidity look worse but more intuitive (users familiar with clob get confused w temporarily
251
+ * crossing book)
252
+ *
253
+ * Things to note about how it works:
254
+ * - it will not uncross the user's liquidity
255
+ * - it does the uncrossing by "shifting" the crossing liquidity to the nearest uncrossed levels. Thus the output liquidity maintains the same total size.
256
+ *
257
+ * @param bids
258
+ * @param asks
259
+ * @param oraclePrice
260
+ * @param oracleTwap5Min
261
+ * @param markTwap5Min
262
+ * @param grouping
263
+ * @param userBids
264
+ * @param userAsks
265
+ */
266
+ function uncrossL2(bids, asks, oraclePrice, oracleTwap5Min, markTwap5Min, grouping, userBids, userAsks) {
267
+ // If there are no bids or asks, there is nothing to center
268
+ if (bids.length === 0 || asks.length === 0) {
269
+ return { bids, asks };
270
+ }
271
+ // If the top of the book is already centered, there is nothing to do
272
+ if (bids[0].price.lt(asks[0].price)) {
273
+ return { bids, asks };
274
+ }
275
+ const newBids = [];
276
+ const newAsks = [];
277
+ const updateLevels = (newPrice, oldLevel, levels) => {
278
+ if (levels.length > 0 && levels[levels.length - 1].price.eq(newPrice)) {
279
+ levels[levels.length - 1].size = levels[levels.length - 1].size.add(oldLevel.size);
280
+ for (const [source, size] of Object.entries(oldLevel.sources)) {
281
+ if (levels[levels.length - 1].sources[source]) {
282
+ levels[levels.length - 1].sources = {
283
+ ...levels[levels.length - 1].sources,
284
+ [source]: levels[levels.length - 1].sources[source].add(size),
285
+ };
286
+ }
287
+ else {
288
+ levels[levels.length - 1].sources[source] = size;
289
+ }
290
+ }
291
+ }
292
+ else {
293
+ levels.push({
294
+ price: newPrice,
295
+ size: oldLevel.size,
296
+ sources: oldLevel.sources,
297
+ });
298
+ }
299
+ };
300
+ // This is the best estimate of the premium in the market vs oracle to filter crossing around
301
+ const referencePrice = oraclePrice.add(markTwap5Min.sub(oracleTwap5Min));
302
+ let bidIndex = 0;
303
+ let askIndex = 0;
304
+ while (bidIndex < bids.length || askIndex < asks.length) {
305
+ const nextBid = bids[bidIndex];
306
+ const nextAsk = asks[askIndex];
307
+ if (!nextBid) {
308
+ newAsks.push(nextAsk);
309
+ askIndex++;
310
+ continue;
311
+ }
312
+ if (!nextAsk) {
313
+ newBids.push(nextBid);
314
+ bidIndex++;
315
+ continue;
316
+ }
317
+ if (nextBid.price.gt(nextAsk.price)) {
318
+ if (userBids.has(nextBid.price.toString())) {
319
+ newBids.push(nextBid);
320
+ bidIndex++;
321
+ continue;
322
+ }
323
+ if (userAsks.has(nextAsk.price.toString())) {
324
+ newAsks.push(nextAsk);
325
+ askIndex++;
326
+ continue;
327
+ }
328
+ if (nextBid.price.gt(referencePrice) &&
329
+ nextAsk.price.gt(referencePrice)) {
330
+ const newBidPrice = nextAsk.price.sub(grouping);
331
+ updateLevels(newBidPrice, nextBid, newBids);
332
+ bidIndex++;
333
+ }
334
+ else if (nextAsk.price.lt(referencePrice) &&
335
+ nextBid.price.lt(referencePrice)) {
336
+ const newAskPrice = nextBid.price.add(grouping);
337
+ updateLevels(newAskPrice, nextAsk, newAsks);
338
+ askIndex++;
339
+ }
340
+ else {
341
+ const newBidPrice = referencePrice.sub(grouping);
342
+ const newAskPrice = referencePrice.add(grouping);
343
+ updateLevels(newBidPrice, nextBid, newBids);
344
+ updateLevels(newAskPrice, nextAsk, newAsks);
345
+ bidIndex++;
346
+ askIndex++;
347
+ }
348
+ }
349
+ else {
350
+ newAsks.push(nextAsk);
351
+ askIndex++;
352
+ newBids.push(nextBid);
353
+ bidIndex++;
354
+ }
355
+ }
356
+ return {
357
+ bids: newBids,
358
+ asks: newAsks,
359
+ };
360
+ }
361
+ exports.uncrossL2 = uncrossL2;
@@ -134,6 +134,9 @@ export declare class DriftClient {
134
134
  getReferredUserStatsAccountsByReferrer(referrer: PublicKey): Promise<UserStatsAccount[]>;
135
135
  getReferrerNameAccountsForAuthority(authority: PublicKey): Promise<ReferrerNameAccount[]>;
136
136
  deleteUser(subAccountId?: number, txParams?: TxParams): Promise<TransactionSignature>;
137
+ getUserDeletionIx(userAccountPublicKey: PublicKey): Promise<anchor.web3.TransactionInstruction>;
138
+ reclaimRent(subAccountId?: number, txParams?: TxParams): Promise<TransactionSignature>;
139
+ getReclaimRentIx(userAccountPublicKey: PublicKey): Promise<anchor.web3.TransactionInstruction>;
137
140
  getUser(subAccountId?: number, authority?: PublicKey): User;
138
141
  hasUser(subAccountId?: number, authority?: PublicKey): boolean;
139
142
  getUsers(): User[];
@@ -668,6 +668,14 @@ class DriftClient {
668
668
  async deleteUser(subAccountId = 0, txParams) {
669
669
  var _a;
670
670
  const userAccountPublicKey = (0, pda_1.getUserAccountPublicKeySync)(this.program.programId, this.wallet.publicKey, subAccountId);
671
+ const ix = await this.getUserDeletionIx(userAccountPublicKey);
672
+ const { txSig } = await this.sendTransaction(await this.buildTransaction(ix, txParams), [], this.opts);
673
+ const userMapKey = this.getUserMapKey(subAccountId, this.wallet.publicKey);
674
+ await ((_a = this.users.get(userMapKey)) === null || _a === void 0 ? void 0 : _a.unsubscribe());
675
+ this.users.delete(userMapKey);
676
+ return txSig;
677
+ }
678
+ async getUserDeletionIx(userAccountPublicKey) {
671
679
  const ix = await this.program.instruction.deleteUser({
672
680
  accounts: {
673
681
  user: userAccountPublicKey,
@@ -676,12 +684,25 @@ class DriftClient {
676
684
  state: await this.getStatePublicKey(),
677
685
  },
678
686
  });
687
+ return ix;
688
+ }
689
+ async reclaimRent(subAccountId = 0, txParams) {
690
+ const userAccountPublicKey = (0, pda_1.getUserAccountPublicKeySync)(this.program.programId, this.wallet.publicKey, subAccountId);
691
+ const ix = await this.getReclaimRentIx(userAccountPublicKey);
679
692
  const { txSig } = await this.sendTransaction(await this.buildTransaction(ix, txParams), [], this.opts);
680
- const userMapKey = this.getUserMapKey(subAccountId, this.wallet.publicKey);
681
- await ((_a = this.users.get(userMapKey)) === null || _a === void 0 ? void 0 : _a.unsubscribe());
682
- this.users.delete(userMapKey);
683
693
  return txSig;
684
694
  }
695
+ async getReclaimRentIx(userAccountPublicKey) {
696
+ return await this.program.instruction.reclaimRent({
697
+ accounts: {
698
+ user: userAccountPublicKey,
699
+ userStats: this.getUserStatsAccountPublicKey(),
700
+ authority: this.wallet.publicKey,
701
+ state: await this.getStatePublicKey(),
702
+ rent: anchor.web3.SYSVAR_RENT_PUBKEY,
703
+ },
704
+ });
705
+ }
685
706
  getUser(subAccountId, authority) {
686
707
  subAccountId = subAccountId !== null && subAccountId !== void 0 ? subAccountId : this.activeSubAccountId;
687
708
  authority = authority !== null && authority !== void 0 ? authority : this.authority;
@@ -2212,8 +2233,13 @@ class DriftClient {
2212
2233
  async getSwapIx({ outMarketIndex, inMarketIndex, amountIn, inTokenAccount, outTokenAccount, limitPrice, reduceOnly, userAccountPublicKey, }) {
2213
2234
  const userAccountPublicKeyToUse = userAccountPublicKey || (await this.getUserAccountPublicKey());
2214
2235
  const userAccounts = [];
2215
- if (this.hasUser() && this.getUser().getUserAccountAndSlot()) {
2216
- userAccounts.push(this.getUser().getUserAccountAndSlot().data);
2236
+ try {
2237
+ if (this.hasUser() && this.getUser().getUserAccountAndSlot()) {
2238
+ userAccounts.push(this.getUser().getUserAccountAndSlot().data);
2239
+ }
2240
+ }
2241
+ catch (err) {
2242
+ // ignore
2217
2243
  }
2218
2244
  const remainingAccounts = this.getRemainingAccounts({
2219
2245
  userAccounts,
@@ -17,7 +17,7 @@ class WebSocketLogProvider {
17
17
  }
18
18
  }
19
19
  async subscribe(callback) {
20
- if (this.subscriptionId) {
20
+ if (this.subscriptionId != null) {
21
21
  return true;
22
22
  }
23
23
  this.callback = callback;
@@ -48,14 +48,14 @@ class WebSocketLogProvider {
48
48
  }, this.commitment);
49
49
  }
50
50
  isSubscribed() {
51
- return this.subscriptionId !== undefined;
51
+ return this.subscriptionId != null;
52
52
  }
53
53
  async unsubscribe(external = false) {
54
54
  this.isUnsubscribing = true;
55
55
  this.externalUnsubscribe = external;
56
56
  clearTimeout(this.timeoutId);
57
57
  this.timeoutId = undefined;
58
- if (this.subscriptionId !== undefined) {
58
+ if (this.subscriptionId != null) {
59
59
  try {
60
60
  await this.connection.removeOnLogsListener(this.subscriptionId);
61
61
  this.subscriptionId = undefined;
@@ -86,7 +86,7 @@ export declare class BigNum {
86
86
  * @returns
87
87
  */
88
88
  toNotional(useTradePrecision?: boolean, precisionOverride?: number): string;
89
- toMillified(precision?: number, rounded?: boolean): string;
89
+ toMillified(precision?: number, rounded?: boolean, type?: 'financial' | 'scientific'): string;
90
90
  toJSON(): {
91
91
  val: string;
92
92
  precision: string;
@@ -330,7 +330,7 @@ class BigNum {
330
330
  }
331
331
  return `${prefix}${val.replace('-', '')}`;
332
332
  }
333
- toMillified(precision = 3, rounded = false) {
333
+ toMillified(precision = 3, rounded = false, type = 'financial') {
334
334
  if (rounded) {
335
335
  return this.toRounded(precision).toMillified(precision);
336
336
  }
@@ -346,7 +346,10 @@ class BigNum {
346
346
  if (leftSide.length <= 3) {
347
347
  return this.shift(new anchor_1.BN(precision)).toPrecision(precision, true);
348
348
  }
349
- const unitTicks = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'];
349
+ const unitTicks = type === 'financial'
350
+ ? ['', 'K', 'M', 'B', 'T', 'Q']
351
+ : ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'];
352
+ // TODO -- handle nubers which are larger than the max unit tick
350
353
  const unitNumber = Math.floor((leftSide.length - 1) / 3);
351
354
  const unit = unitTicks[unitNumber];
352
355
  let leadDigits = leftSide.slice(0, precision);