@drift-labs/sdk 2.41.0-beta.0 → 2.41.0-beta.2

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 (81) hide show
  1. package/README.md +0 -1
  2. package/VERSION +1 -1
  3. package/bun.lockb +0 -0
  4. package/lib/accounts/types.d.ts +5 -1
  5. package/lib/accounts/webSocketAccountSubscriber.d.ts +6 -1
  6. package/lib/accounts/webSocketAccountSubscriber.js +28 -2
  7. package/lib/accounts/webSocketDriftClientAccountSubscriber.d.ts +2 -1
  8. package/lib/accounts/webSocketDriftClientAccountSubscriber.js +6 -5
  9. package/lib/accounts/webSocketProgramAccountSubscriber.d.ts +32 -0
  10. package/lib/accounts/webSocketProgramAccountSubscriber.js +99 -0
  11. package/lib/accounts/webSocketUserAccountSubscriber.d.ts +2 -1
  12. package/lib/accounts/webSocketUserAccountSubscriber.js +3 -2
  13. package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +2 -1
  14. package/lib/accounts/webSocketUserStatsAccountSubsriber.js +3 -2
  15. package/lib/addresses/pda.d.ts +1 -0
  16. package/lib/addresses/pda.js +5 -1
  17. package/lib/adminClient.d.ts +2 -0
  18. package/lib/adminClient.js +20 -0
  19. package/lib/auctionSubscriber/auctionSubscriber.d.ts +3 -2
  20. package/lib/auctionSubscriber/auctionSubscriber.js +15 -7
  21. package/lib/auctionSubscriber/types.d.ts +1 -0
  22. package/lib/dlob/DLOB.d.ts +2 -6
  23. package/lib/dlob/DLOB.js +9 -11
  24. package/lib/dlob/DLOBSubscriber.js +4 -7
  25. package/lib/dlob/orderBookLevels.d.ts +4 -2
  26. package/lib/dlob/orderBookLevels.js +79 -16
  27. package/lib/driftClient.d.ts +2 -1
  28. package/lib/driftClient.js +13 -14
  29. package/lib/driftClientConfig.d.ts +1 -0
  30. package/lib/factory/bigNum.js +4 -2
  31. package/lib/idl/drift.json +222 -2
  32. package/lib/jupiter/jupiterClient.d.ts +4 -1
  33. package/lib/jupiter/jupiterClient.js +4 -1
  34. package/lib/math/amm.js +7 -2
  35. package/lib/math/auction.d.ts +12 -1
  36. package/lib/math/auction.js +22 -1
  37. package/lib/math/market.js +2 -4
  38. package/lib/math/superStake.d.ts +51 -4
  39. package/lib/math/superStake.js +173 -21
  40. package/lib/math/trade.js +2 -4
  41. package/lib/math/utils.d.ts +1 -0
  42. package/lib/math/utils.js +10 -1
  43. package/lib/orderSubscriber/OrderSubscriber.d.ts +1 -3
  44. package/lib/orderSubscriber/OrderSubscriber.js +4 -3
  45. package/lib/orderSubscriber/WebsocketSubscription.d.ts +4 -2
  46. package/lib/orderSubscriber/WebsocketSubscription.js +15 -12
  47. package/lib/orderSubscriber/types.d.ts +1 -0
  48. package/lib/user.d.ts +2 -2
  49. package/lib/user.js +5 -5
  50. package/package.json +2 -1
  51. package/src/accounts/types.ts +8 -1
  52. package/src/accounts/webSocketAccountSubscriber.ts +36 -2
  53. package/src/accounts/webSocketDriftClientAccountSubscriber.ts +15 -5
  54. package/src/accounts/webSocketProgramAccountSubscriber.ts +152 -0
  55. package/src/accounts/webSocketUserAccountSubscriber.ts +10 -2
  56. package/src/accounts/webSocketUserStatsAccountSubsriber.ts +10 -2
  57. package/src/addresses/pda.ts +9 -0
  58. package/src/adminClient.ts +32 -0
  59. package/src/auctionSubscriber/auctionSubscriber.ts +30 -21
  60. package/src/auctionSubscriber/types.ts +1 -0
  61. package/src/dlob/DLOB.ts +9 -32
  62. package/src/dlob/DLOBSubscriber.ts +8 -7
  63. package/src/dlob/orderBookLevels.ts +133 -32
  64. package/src/driftClient.ts +14 -16
  65. package/src/driftClientConfig.ts +1 -0
  66. package/src/factory/bigNum.ts +2 -0
  67. package/src/idl/drift.json +222 -2
  68. package/src/jupiter/jupiterClient.ts +6 -0
  69. package/src/math/amm.ts +9 -2
  70. package/src/math/auction.ts +36 -2
  71. package/src/math/market.ts +4 -9
  72. package/src/math/superStake.ts +247 -23
  73. package/src/math/trade.ts +3 -11
  74. package/src/math/utils.ts +12 -0
  75. package/src/orderSubscriber/OrderSubscriber.ts +12 -7
  76. package/src/orderSubscriber/WebsocketSubscription.ts +34 -23
  77. package/src/orderSubscriber/types.ts +1 -0
  78. package/src/user.ts +7 -5
  79. package/tests/amm/test.ts +402 -0
  80. package/tests/auctions/test.ts +66 -0
  81. package/tests/dlob/test.ts +1 -73
@@ -275,16 +275,20 @@ export class JupiterClient {
275
275
  inputMint,
276
276
  outputMint,
277
277
  amount,
278
+ maxAccounts = 50, // 50 is an estimated amount with buffer
278
279
  slippageBps = 50,
279
280
  swapMode = 'ExactIn',
280
281
  onlyDirectRoutes = false,
282
+ excludeDexes = [],
281
283
  }: {
282
284
  inputMint: PublicKey;
283
285
  outputMint: PublicKey;
284
286
  amount: BN;
287
+ maxAccounts?: number;
285
288
  slippageBps?: number;
286
289
  swapMode?: SwapMode;
287
290
  onlyDirectRoutes?: boolean;
291
+ excludeDexes?: string[];
288
292
  }): Promise<QuoteResponse> {
289
293
  const params = new URLSearchParams({
290
294
  inputMint: inputMint.toString(),
@@ -293,6 +297,8 @@ export class JupiterClient {
293
297
  slippageBps: slippageBps.toString(),
294
298
  swapMode,
295
299
  onlyDirectRoutes: onlyDirectRoutes.toString(),
300
+ maxAccounts: maxAccounts.toString(),
301
+ excludeDexes: excludeDexes.join(','),
296
302
  }).toString();
297
303
  const quote = await (await fetch(`${this.url}/v6/quote?${params}`)).json();
298
304
  return quote;
package/src/math/amm.ts CHANGED
@@ -471,12 +471,19 @@ export function calculateVolSpreadBN(
471
471
  clampMax
472
472
  );
473
473
 
474
+ // only consider confidence interval at full value when above 25 bps
475
+ let confComponent = lastOracleConfPct;
476
+
477
+ if (lastOracleConfPct.lte(PRICE_PRECISION.div(new BN(400)))) {
478
+ confComponent = lastOracleConfPct.div(new BN(10));
479
+ }
480
+
474
481
  const longVolSpread = BN.max(
475
- lastOracleConfPct,
482
+ confComponent,
476
483
  volSpread.mul(longVolSpreadFactor).div(PERCENTAGE_PRECISION)
477
484
  );
478
485
  const shortVolSpread = BN.max(
479
- lastOracleConfPct,
486
+ confComponent,
480
487
  volSpread.mul(shortVolSpreadFactor).div(PERCENTAGE_PRECISION)
481
488
  );
482
489
 
@@ -1,5 +1,5 @@
1
- import { isOneOfVariant, isVariant, Order } from '../types';
2
- import { BN, ZERO } from '../.';
1
+ import { isOneOfVariant, isVariant, Order, PositionDirection } from '../types';
2
+ import { BN, ONE, ZERO } from '../.';
3
3
 
4
4
  export function isAuctionComplete(order: Order, slot: number): boolean {
5
5
  if (order.auctionDuration === 0) {
@@ -104,3 +104,37 @@ export function getAuctionPriceForOracleOffsetAuction(
104
104
 
105
105
  return oraclePrice.add(priceOffset);
106
106
  }
107
+
108
+ export function deriveOracleAuctionParams({
109
+ direction,
110
+ oraclePrice,
111
+ auctionStartPrice,
112
+ auctionEndPrice,
113
+ limitPrice,
114
+ }: {
115
+ direction: PositionDirection;
116
+ oraclePrice: BN;
117
+ auctionStartPrice: BN;
118
+ auctionEndPrice: BN;
119
+ limitPrice: BN;
120
+ }): { auctionStartPrice: BN; auctionEndPrice: BN; oraclePriceOffset: number } {
121
+ let oraclePriceOffset = limitPrice.sub(oraclePrice);
122
+ if (oraclePriceOffset.eq(ZERO)) {
123
+ oraclePriceOffset = isVariant(direction, 'long')
124
+ ? auctionEndPrice.sub(oraclePrice).add(ONE)
125
+ : auctionEndPrice.sub(oraclePrice).sub(ONE);
126
+ }
127
+
128
+ let oraclePriceOffsetNum;
129
+ try {
130
+ oraclePriceOffsetNum = oraclePriceOffset.toNumber();
131
+ } catch (e) {
132
+ oraclePriceOffsetNum = 0;
133
+ }
134
+
135
+ return {
136
+ auctionStartPrice: auctionStartPrice.sub(oraclePrice),
137
+ auctionEndPrice: auctionEndPrice.sub(oraclePrice),
138
+ oraclePriceOffset: oraclePriceOffsetNum,
139
+ };
140
+ }
@@ -279,27 +279,22 @@ export function calculateAvailablePerpLiquidity(
279
279
 
280
280
  asks = asks.abs();
281
281
 
282
- const bidPrice = calculateBidPrice(market, oraclePriceData);
283
- const askPrice = calculateAskPrice(market, oraclePriceData);
284
-
285
- for (const bid of dlob.getMakerLimitBids(
282
+ for (const bid of dlob.getRestingLimitBids(
286
283
  market.marketIndex,
287
284
  slot,
288
285
  MarketType.PERP,
289
- oraclePriceData,
290
- askPrice
286
+ oraclePriceData
291
287
  )) {
292
288
  bids = bids.add(
293
289
  bid.order.baseAssetAmount.sub(bid.order.baseAssetAmountFilled)
294
290
  );
295
291
  }
296
292
 
297
- for (const ask of dlob.getMakerLimitAsks(
293
+ for (const ask of dlob.getRestingLimitAsks(
298
294
  market.marketIndex,
299
295
  slot,
300
296
  MarketType.PERP,
301
- oraclePriceData,
302
- bidPrice
297
+ oraclePriceData
303
298
  )) {
304
299
  asks = asks.add(
305
300
  ask.order.baseAssetAmount.sub(ask.order.baseAssetAmountFilled)
@@ -12,20 +12,23 @@ import { User } from '../user';
12
12
  import { DepositRecord, isVariant } from '../types';
13
13
  import { LAMPORTS_PRECISION, ZERO } from '../constants/numericConstants';
14
14
  import fetch from 'node-fetch';
15
+ import { checkSameDate } from './utils';
15
16
 
16
17
  export async function findBestSuperStakeIxs({
18
+ marketIndex,
17
19
  amount,
18
20
  jupiterClient,
19
21
  driftClient,
20
22
  userAccountPublicKey,
21
- marinadePrice,
23
+ price,
22
24
  forceMarinade,
23
25
  onlyDirectRoutes,
24
26
  }: {
27
+ marketIndex: number;
25
28
  amount: BN;
26
29
  jupiterClient: JupiterClient;
27
30
  driftClient: DriftClient;
28
- marinadePrice?: number;
31
+ price?: number;
29
32
  userAccountPublicKey?: PublicKey;
30
33
  forceMarinade?: boolean;
31
34
  onlyDirectRoutes?: boolean;
@@ -35,9 +38,54 @@ export async function findBestSuperStakeIxs({
35
38
  method: 'jupiter' | 'marinade';
36
39
  price: number;
37
40
  }> {
38
- if (!marinadePrice) {
41
+ if (marketIndex === 2) {
42
+ return findBestMSolSuperStakeIxs({
43
+ amount,
44
+ jupiterClient,
45
+ driftClient,
46
+ userAccountPublicKey,
47
+ price,
48
+ forceMarinade,
49
+ onlyDirectRoutes,
50
+ });
51
+ } else if (marketIndex === 6) {
52
+ return findBestJitoSolSuperStakeIxs({
53
+ amount,
54
+ jupiterClient,
55
+ driftClient,
56
+ userAccountPublicKey,
57
+ onlyDirectRoutes,
58
+ });
59
+ } else {
60
+ throw new Error(`Unsupported superstake market index: ${marketIndex}`);
61
+ }
62
+ }
63
+
64
+ export async function findBestMSolSuperStakeIxs({
65
+ amount,
66
+ jupiterClient,
67
+ driftClient,
68
+ userAccountPublicKey,
69
+ price,
70
+ forceMarinade,
71
+ onlyDirectRoutes,
72
+ }: {
73
+ amount: BN;
74
+ jupiterClient: JupiterClient;
75
+ driftClient: DriftClient;
76
+ price?: number;
77
+ userAccountPublicKey?: PublicKey;
78
+ forceMarinade?: boolean;
79
+ onlyDirectRoutes?: boolean;
80
+ }): Promise<{
81
+ ixs: TransactionInstruction[];
82
+ lookupTables: AddressLookupTableAccount[];
83
+ method: 'jupiter' | 'marinade';
84
+ price: number;
85
+ }> {
86
+ if (!price) {
39
87
  const marinadeProgram = getMarinadeFinanceProgram(driftClient.provider);
40
- marinadePrice = await getMarinadeMSolPrice(marinadeProgram);
88
+ price = await getMarinadeMSolPrice(marinadeProgram);
41
89
  }
42
90
 
43
91
  const solMint = driftClient.getSpotMarketAccount(1).mint;
@@ -59,7 +107,7 @@ export async function findBestSuperStakeIxs({
59
107
  console.error('Error getting jupiter price', e);
60
108
  }
61
109
 
62
- if (!jupiterPrice || marinadePrice <= jupiterPrice || forceMarinade) {
110
+ if (!jupiterPrice || price <= jupiterPrice || forceMarinade) {
63
111
  const ixs = await driftClient.getStakeForMSOLIx({
64
112
  amount,
65
113
  userAccountPublicKey,
@@ -68,7 +116,7 @@ export async function findBestSuperStakeIxs({
68
116
  method: 'marinade',
69
117
  ixs,
70
118
  lookupTables: [],
71
- price: marinadePrice,
119
+ price: price,
72
120
  };
73
121
  } else {
74
122
  const { ixs, lookupTables } = await driftClient.getJupiterSwapIx({
@@ -88,10 +136,170 @@ export async function findBestSuperStakeIxs({
88
136
  }
89
137
  }
90
138
 
139
+ export async function findBestJitoSolSuperStakeIxs({
140
+ amount,
141
+ jupiterClient,
142
+ driftClient,
143
+ userAccountPublicKey,
144
+ onlyDirectRoutes,
145
+ }: {
146
+ amount: BN;
147
+ jupiterClient: JupiterClient;
148
+ driftClient: DriftClient;
149
+ userAccountPublicKey?: PublicKey;
150
+ onlyDirectRoutes?: boolean;
151
+ }): Promise<{
152
+ ixs: TransactionInstruction[];
153
+ lookupTables: AddressLookupTableAccount[];
154
+ method: 'jupiter' | 'marinade';
155
+ price: number;
156
+ }> {
157
+ const solMint = driftClient.getSpotMarketAccount(1).mint;
158
+ const JitoSolMint = driftClient.getSpotMarketAccount(6).mint;
159
+
160
+ let jupiterPrice;
161
+ let bestRoute;
162
+ try {
163
+ const jupiterRoutes = await jupiterClient.getRoutes({
164
+ inputMint: solMint,
165
+ outputMint: JitoSolMint,
166
+ amount,
167
+ onlyDirectRoutes,
168
+ });
169
+
170
+ bestRoute = jupiterRoutes[0];
171
+ jupiterPrice = bestRoute.inAmount / bestRoute.outAmount;
172
+ } catch (e) {
173
+ console.error('Error getting jupiter price', e);
174
+ throw e;
175
+ }
176
+
177
+ const { ixs, lookupTables } = await driftClient.getJupiterSwapIx({
178
+ inMarketIndex: 1,
179
+ outMarketIndex: 6,
180
+ route: bestRoute,
181
+ jupiterClient,
182
+ amount,
183
+ userAccountPublicKey,
184
+ });
185
+ return {
186
+ method: 'jupiter',
187
+ ixs,
188
+ lookupTables,
189
+ price: jupiterPrice,
190
+ };
191
+ }
192
+
193
+ export type JITO_SOL_METRICS_ENDPOINT_RESPONSE = {
194
+ data: {
195
+ getStakePoolStats: {
196
+ tvl: {
197
+ // TVL in SOL, BN
198
+ data: number;
199
+ date: string;
200
+ }[];
201
+ supply: {
202
+ // jitoSOL supply
203
+ data: number;
204
+ date: string;
205
+ }[];
206
+ apy: {
207
+ data: number;
208
+ date: string;
209
+ }[];
210
+ };
211
+ };
212
+ };
213
+
214
+ const JITO_SOL_START_DATE = '2022-10-31T00:00:00Z';
215
+
216
+ export async function fetchJitoSolMetrics() {
217
+ const res = await fetch('https://kobe.mainnet.jito.network/', {
218
+ body: JSON.stringify({
219
+ operationName: 'QueryRoot',
220
+ variables: {
221
+ request: {
222
+ bucketType: 'DAILY',
223
+ rangeFilter: {
224
+ start: JITO_SOL_START_DATE,
225
+ end: new Date().toISOString(),
226
+ },
227
+ sortBy: {
228
+ order: 'ASC',
229
+ field: 'BLOCK_TIME',
230
+ },
231
+ },
232
+ },
233
+ query: `
234
+ query QueryRoot($request: GetStakePoolStatsRequest!) {
235
+ getStakePoolStats(req: $request) {
236
+ tvl {
237
+ data
238
+ date
239
+ }
240
+ apy {
241
+ data
242
+ date
243
+ }
244
+ supply {
245
+ data
246
+ date
247
+ }
248
+ }
249
+ }
250
+ `,
251
+ }),
252
+ method: 'POST',
253
+ });
254
+
255
+ const data: JITO_SOL_METRICS_ENDPOINT_RESPONSE = await res.json();
256
+
257
+ return data;
258
+ }
259
+
260
+ const getJitoSolHistoricalPriceMap = async (timestamps: number[]) => {
261
+ try {
262
+ const data = await fetchJitoSolMetrics();
263
+ const jitoSolHistoricalPriceMap = new Map<number, number>();
264
+ const jitoSolHistoricalPriceInSol = [];
265
+
266
+ for (let i = 0; i < data.data.getStakePoolStats.supply.length; i++) {
267
+ const priceInSol =
268
+ data.data.getStakePoolStats.tvl[i].data /
269
+ 10 ** 9 /
270
+ data.data.getStakePoolStats.supply[i].data;
271
+ jitoSolHistoricalPriceInSol.push({
272
+ price: priceInSol,
273
+ ts: data.data.getStakePoolStats.tvl[i].date,
274
+ });
275
+ }
276
+
277
+ for (const timestamp of timestamps) {
278
+ const date = new Date(timestamp * 1000);
279
+ const dateString = date.toISOString();
280
+
281
+ const price = jitoSolHistoricalPriceInSol.find((p) =>
282
+ checkSameDate(p.ts, dateString)
283
+ );
284
+
285
+ if (price) {
286
+ jitoSolHistoricalPriceMap.set(timestamp, price.price);
287
+ }
288
+ }
289
+
290
+ return jitoSolHistoricalPriceMap;
291
+ } catch (err) {
292
+ console.error(err);
293
+ return undefined;
294
+ }
295
+ };
296
+
91
297
  export async function calculateSolEarned({
298
+ marketIndex,
92
299
  user,
93
300
  depositRecords,
94
301
  }: {
302
+ marketIndex: number;
95
303
  user: User;
96
304
  depositRecords: DepositRecord[];
97
305
  }): Promise<BN> {
@@ -101,20 +309,24 @@ export async function calculateSolEarned({
101
309
  ...depositRecords.map((r) => r.ts.toNumber()),
102
310
  ];
103
311
 
104
- const msolRatios = new Map<number, number>();
312
+ let lstRatios = new Map<number, number>();
105
313
 
106
- const getPrice = async (timestamp) => {
314
+ const getMsolPrice = async (timestamp) => {
107
315
  const date = new Date(timestamp * 1000); // Convert Unix timestamp to milliseconds
108
316
  const swaggerApiDateTime = date.toISOString(); // Format date as swagger API date-time
109
317
  const url = `https://api.marinade.finance/msol/price_sol?time=${swaggerApiDateTime}`;
110
318
  const response = await fetch(url);
111
319
  if (response.status === 200) {
112
320
  const data = await response.json();
113
- msolRatios.set(timestamp, data);
321
+ lstRatios.set(timestamp, data);
114
322
  }
115
323
  };
116
324
 
117
- await Promise.all(timestamps.map(getPrice));
325
+ if (marketIndex === 2) {
326
+ await Promise.all(timestamps.map(getMsolPrice));
327
+ } else if (marketIndex === 6) {
328
+ lstRatios = await getJitoSolHistoricalPriceMap(timestamps);
329
+ }
118
330
 
119
331
  let solEarned = ZERO;
120
332
  for (const record of depositRecords) {
@@ -125,7 +337,7 @@ export async function calculateSolEarned({
125
337
  solEarned = solEarned.add(record.amount);
126
338
  }
127
339
  } else if (record.marketIndex === 2) {
128
- const msolRatio = msolRatios.get(record.ts.toNumber());
340
+ const msolRatio = lstRatios.get(record.ts.toNumber());
129
341
  const msolRatioBN = new BN(msolRatio * LAMPORTS_PER_SOL);
130
342
 
131
343
  const solAmount = record.amount.mul(msolRatioBN).div(LAMPORTS_PRECISION);
@@ -134,34 +346,46 @@ export async function calculateSolEarned({
134
346
  } else {
135
347
  solEarned = solEarned.add(solAmount);
136
348
  }
349
+ } else if (record.marketIndex === 6) {
350
+ const jitoSolRatio = lstRatios.get(record.ts.toNumber());
351
+ const jitoSolRatioBN = new BN(jitoSolRatio * LAMPORTS_PER_SOL);
352
+
353
+ const solAmount = record.amount
354
+ .mul(jitoSolRatioBN)
355
+ .div(LAMPORTS_PRECISION);
356
+ if (isVariant(record.direction, 'deposit')) {
357
+ solEarned = solEarned.sub(solAmount);
358
+ } else {
359
+ solEarned = solEarned.add(solAmount);
360
+ }
137
361
  }
138
362
  }
139
363
 
140
- const currentMSOLTokenAmount = await user.getTokenAmount(2);
141
- const currentSOLTokenAmount = await user.getTokenAmount(1);
142
-
143
- const currentMSOLRatio = msolRatios.get(now);
144
- const currentMSOLRatioBN = new BN(currentMSOLRatio * LAMPORTS_PER_SOL);
364
+ const currentLstTokenAmount = await user.getTokenAmount(marketIndex);
365
+ const currentLstRatio = lstRatios.get(now);
366
+ const currentLstRatioBN = new BN(currentLstRatio * LAMPORTS_PER_SOL);
145
367
 
146
368
  solEarned = solEarned.add(
147
- currentMSOLTokenAmount.mul(currentMSOLRatioBN).div(LAMPORTS_PRECISION)
369
+ currentLstTokenAmount.mul(currentLstRatioBN).div(LAMPORTS_PRECISION)
148
370
  );
371
+
372
+ const currentSOLTokenAmount = await user.getTokenAmount(1);
149
373
  solEarned = solEarned.add(currentSOLTokenAmount);
150
374
 
151
375
  return solEarned;
152
376
  }
153
377
 
154
- // calculate estimated liquidation price (in mSOL/SOL) based on target amounts
378
+ // calculate estimated liquidation price (in LST/SOL) based on target amounts
155
379
  export function calculateEstimatedSuperStakeLiquidationPrice(
156
- msolDepositAmount: number,
157
- msolMaintenanceAssetWeight: number,
380
+ lstDepositAmount: number,
381
+ lstMaintenanceAssetWeight: number,
158
382
  solBorrowAmount: number,
159
383
  solMaintenanceLiabilityWeight: number,
160
- msolPriceRatio: number
384
+ lstPriceRatio: number
161
385
  ): number {
162
386
  const liquidationDivergence =
163
387
  (solMaintenanceLiabilityWeight * solBorrowAmount) /
164
- (msolMaintenanceAssetWeight * msolDepositAmount * msolPriceRatio);
165
- const liquidationPrice = msolPriceRatio * liquidationDivergence;
388
+ (lstMaintenanceAssetWeight * lstDepositAmount * lstPriceRatio);
389
+ const liquidationPrice = lstPriceRatio * liquidationDivergence;
166
390
  return liquidationPrice;
167
391
  }
package/src/math/trade.ts CHANGED
@@ -411,16 +411,8 @@ export function calculateEstimatedPerpEntryPrice(
411
411
 
412
412
  const takerIsLong = isVariant(direction, 'long');
413
413
  const limitOrders = dlob[
414
- takerIsLong ? 'getMakerLimitAsks' : 'getMakerLimitBids'
415
- ](
416
- market.marketIndex,
417
- slot,
418
- MarketType.PERP,
419
- oraclePriceData,
420
- takerIsLong
421
- ? calculateBidPrice(market, oraclePriceData)
422
- : calculateAskPrice(market, oraclePriceData)
423
- );
414
+ takerIsLong ? 'getRestingLimitAsks' : 'getRestingLimitBids'
415
+ ](market.marketIndex, slot, MarketType.PERP, oraclePriceData);
424
416
 
425
417
  const swapDirection = getSwapDirection(assetType, direction);
426
418
 
@@ -726,7 +718,7 @@ export function calculateEstimatedSpotEntryPrice(
726
718
 
727
719
  const takerIsLong = isVariant(direction, 'long');
728
720
  const dlobLimitOrders = dlob[
729
- takerIsLong ? 'getMakerLimitAsks' : 'getMakerLimitBids'
721
+ takerIsLong ? 'getRestingLimitAsks' : 'getRestingLimitBids'
730
722
  ](market.marketIndex, slot, MarketType.SPOT, oraclePriceData);
731
723
  const serumLimitOrders = takerIsLong
732
724
  ? serumAsks.getL2(100)
package/src/math/utils.ts CHANGED
@@ -83,3 +83,15 @@ export function timeRemainingUntilUpdate(
83
83
 
84
84
  return timeRemainingUntilUpdate;
85
85
  }
86
+
87
+ export const checkSameDate = (dateString1: string, dateString2: string) => {
88
+ const date1 = new Date(dateString1);
89
+ const date2 = new Date(dateString2);
90
+
91
+ const isSameDate =
92
+ date1.getDate() === date2.getDate() &&
93
+ date1.getMonth() === date2.getMonth() &&
94
+ date1.getFullYear() === date2.getFullYear();
95
+
96
+ return isSameDate;
97
+ };
@@ -30,6 +30,7 @@ export class OrderSubscriber {
30
30
  this.subscription = new WebsocketSubscription({
31
31
  orderSubscriber: this,
32
32
  skipInitialLoad: config.subscriptionConfig.skipInitialLoad,
33
+ resubTimeoutMs: config.subscriptionConfig.resubTimeoutMs,
33
34
  });
34
35
  }
35
36
  this.eventEmitter = new EventEmitter();
@@ -86,7 +87,12 @@ export class OrderSubscriber {
86
87
  programAccount.account.data[1]
87
88
  );
88
89
  programAccountSet.add(key);
89
- this.tryUpdateUserAccount(key, buffer, slot);
90
+ const userAccount =
91
+ this.driftClient.program.account.user.coder.accounts.decode(
92
+ 'User',
93
+ buffer
94
+ ) as UserAccount;
95
+ this.tryUpdateUserAccount(key, userAccount, slot);
90
96
  }
91
97
 
92
98
  for (const key of this.usersAccounts.keys()) {
@@ -102,14 +108,13 @@ export class OrderSubscriber {
102
108
  }
103
109
  }
104
110
 
105
- tryUpdateUserAccount(key: string, buffer: Buffer, slot: number): void {
111
+ tryUpdateUserAccount(
112
+ key: string,
113
+ userAccount: UserAccount,
114
+ slot: number
115
+ ): void {
106
116
  const slotAndUserAccount = this.usersAccounts.get(key);
107
117
  if (!slotAndUserAccount || slotAndUserAccount.slot < slot) {
108
- const userAccount =
109
- this.driftClient.program.account.user.coder.accounts.decode(
110
- 'User',
111
- buffer
112
- ) as UserAccount;
113
118
  const newOrders = userAccount.orders.filter(
114
119
  (order) =>
115
120
  order.slot.toNumber() > (slotAndUserAccount?.slot ?? 0) &&
@@ -1,42 +1,57 @@
1
1
  import { OrderSubscriber } from './OrderSubscriber';
2
2
  import { getNonIdleUserFilter, getUserFilter } from '../memcmp';
3
+ import { WebSocketProgramAccountSubscriber } from '../accounts/webSocketProgramAccountSubscriber';
4
+ import { UserAccount } from '../types';
5
+ import { Context, PublicKey } from '@solana/web3.js';
3
6
 
4
7
  export class WebsocketSubscription {
5
8
  private orderSubscriber: OrderSubscriber;
6
9
  private skipInitialLoad: boolean;
10
+ private resubTimeoutMs?: number;
7
11
 
8
- private websocketId: number;
12
+ private subscriber: WebSocketProgramAccountSubscriber<UserAccount>;
9
13
 
10
14
  constructor({
11
15
  orderSubscriber,
12
16
  skipInitialLoad = false,
17
+ resubTimeoutMs,
13
18
  }: {
14
19
  orderSubscriber: OrderSubscriber;
15
20
  skipInitialLoad?: boolean;
21
+ resubTimeoutMs?: number;
16
22
  }) {
17
23
  this.orderSubscriber = orderSubscriber;
18
24
  this.skipInitialLoad = skipInitialLoad;
25
+ this.resubTimeoutMs = resubTimeoutMs;
19
26
  }
20
27
 
21
28
  public async subscribe(): Promise<void> {
22
- if (this.websocketId) {
23
- return;
24
- }
25
-
26
- this.websocketId =
27
- this.orderSubscriber.driftClient.connection.onProgramAccountChange(
28
- this.orderSubscriber.driftClient.program.programId,
29
- (keyAccountInfo, context) => {
30
- const userKey = keyAccountInfo.accountId.toBase58();
31
- this.orderSubscriber.tryUpdateUserAccount(
32
- userKey,
33
- keyAccountInfo.accountInfo.data,
34
- context.slot
35
- );
29
+ if (!this.subscriber) {
30
+ this.subscriber = new WebSocketProgramAccountSubscriber<UserAccount>(
31
+ 'OrderSubscriber',
32
+ 'User',
33
+ this.orderSubscriber.driftClient.program,
34
+ this.orderSubscriber.driftClient.program.account.user.coder.accounts.decode.bind(
35
+ this.orderSubscriber.driftClient.program.account.user.coder.accounts
36
+ ),
37
+ {
38
+ filters: [getUserFilter(), getNonIdleUserFilter()],
39
+ commitment: this.orderSubscriber.driftClient.opts.commitment,
36
40
  },
37
- this.orderSubscriber.driftClient.opts.commitment,
38
- [getUserFilter(), getNonIdleUserFilter()]
41
+ this.resubTimeoutMs
39
42
  );
43
+ }
44
+
45
+ await this.subscriber.subscribe(
46
+ (accountId: PublicKey, account: UserAccount, context: Context) => {
47
+ const userKey = accountId.toBase58();
48
+ this.orderSubscriber.tryUpdateUserAccount(
49
+ userKey,
50
+ account,
51
+ context.slot
52
+ );
53
+ }
54
+ );
40
55
 
41
56
  if (!this.skipInitialLoad) {
42
57
  await this.orderSubscriber.fetch();
@@ -44,11 +59,7 @@ export class WebsocketSubscription {
44
59
  }
45
60
 
46
61
  public async unsubscribe(): Promise<void> {
47
- if (this.websocketId) {
48
- await this.orderSubscriber.driftClient.connection.removeProgramAccountChangeListener(
49
- this.websocketId
50
- );
51
- this.websocketId = undefined;
52
- }
62
+ if (!this.subscriber) return;
63
+ this.subscriber.unsubscribe();
53
64
  }
54
65
  }
@@ -12,6 +12,7 @@ export type OrderSubscriberConfig = {
12
12
  | {
13
13
  type: 'websocket';
14
14
  skipInitialLoad?: boolean;
15
+ resubTimeoutMs?: number;
15
16
  };
16
17
  };
17
18