@drift-labs/sdk 2.38.1-beta.9 → 2.39.1-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.38.1-beta.9
1
+ 2.39.1-beta.1
@@ -13,7 +13,7 @@ import { DriftClientConfig } from './driftClientConfig';
13
13
  import { User } from './user';
14
14
  import { UserSubscriptionConfig } from './userConfig';
15
15
  import { UserStats } from './userStats';
16
- import { JupiterClient, Route, SwapMode } from './jupiter/jupiterClient';
16
+ import { JupiterClient, QuoteResponse, Route, SwapMode } from './jupiter/jupiterClient';
17
17
  import { UserStatsSubscriptionConfig } from './userStatsConfig';
18
18
  type RemainingAccountParams = {
19
19
  userAccounts: UserAccount[];
@@ -319,7 +319,7 @@ export declare class DriftClient {
319
319
  * @param reduceOnly specify if In or Out token on the drift account must reduceOnly, checked at end of swap
320
320
  * @param txParams
321
321
  */
322
- swap({ jupiterClient, outMarketIndex, inMarketIndex, outAssociatedTokenAccount, inAssociatedTokenAccount, amount, slippageBps, swapMode, route, reduceOnly, txParams, }: {
322
+ swap({ jupiterClient, outMarketIndex, inMarketIndex, outAssociatedTokenAccount, inAssociatedTokenAccount, amount, slippageBps, swapMode, route, reduceOnly, txParams, v6, }: {
323
323
  jupiterClient: JupiterClient;
324
324
  outMarketIndex: number;
325
325
  inMarketIndex: number;
@@ -331,6 +331,9 @@ export declare class DriftClient {
331
331
  route?: Route;
332
332
  reduceOnly?: SwapReduceOnly;
333
333
  txParams?: TxParams;
334
+ v6?: {
335
+ quote?: QuoteResponse;
336
+ };
334
337
  }): Promise<TransactionSignature>;
335
338
  getJupiterSwapIx({ jupiterClient, outMarketIndex, inMarketIndex, outAssociatedTokenAccount, inAssociatedTokenAccount, amount, slippageBps, swapMode, onlyDirectRoutes, route, reduceOnly, userAccountPublicKey, }: {
336
339
  jupiterClient: JupiterClient;
@@ -349,6 +352,23 @@ export declare class DriftClient {
349
352
  ixs: TransactionInstruction[];
350
353
  lookupTables: AddressLookupTableAccount[];
351
354
  }>;
355
+ getJupiterSwapIxV6({ jupiterClient, outMarketIndex, inMarketIndex, outAssociatedTokenAccount, inAssociatedTokenAccount, amount, slippageBps, swapMode, onlyDirectRoutes, quote, reduceOnly, userAccountPublicKey, }: {
356
+ jupiterClient: JupiterClient;
357
+ outMarketIndex: number;
358
+ inMarketIndex: number;
359
+ outAssociatedTokenAccount?: PublicKey;
360
+ inAssociatedTokenAccount?: PublicKey;
361
+ amount: BN;
362
+ slippageBps?: number;
363
+ swapMode?: SwapMode;
364
+ onlyDirectRoutes?: boolean;
365
+ quote?: QuoteResponse;
366
+ reduceOnly?: SwapReduceOnly;
367
+ userAccountPublicKey?: PublicKey;
368
+ }): Promise<{
369
+ ixs: TransactionInstruction[];
370
+ lookupTables: AddressLookupTableAccount[];
371
+ }>;
352
372
  /**
353
373
  * Get the drift begin_swap and end_swap instructions
354
374
  *
@@ -1975,19 +1975,41 @@ class DriftClient {
1975
1975
  * @param reduceOnly specify if In or Out token on the drift account must reduceOnly, checked at end of swap
1976
1976
  * @param txParams
1977
1977
  */
1978
- async swap({ jupiterClient, outMarketIndex, inMarketIndex, outAssociatedTokenAccount, inAssociatedTokenAccount, amount, slippageBps, swapMode, route, reduceOnly, txParams, }) {
1979
- const { ixs, lookupTables } = await this.getJupiterSwapIx({
1980
- jupiterClient,
1981
- outMarketIndex,
1982
- inMarketIndex,
1983
- outAssociatedTokenAccount,
1984
- inAssociatedTokenAccount,
1985
- amount,
1986
- slippageBps,
1987
- swapMode,
1988
- route,
1989
- reduceOnly,
1990
- });
1978
+ async swap({ jupiterClient, outMarketIndex, inMarketIndex, outAssociatedTokenAccount, inAssociatedTokenAccount, amount, slippageBps, swapMode, route, reduceOnly, txParams, v6, }) {
1979
+ let ixs;
1980
+ let lookupTables;
1981
+ if (v6) {
1982
+ const res = await this.getJupiterSwapIxV6({
1983
+ jupiterClient,
1984
+ outMarketIndex,
1985
+ inMarketIndex,
1986
+ outAssociatedTokenAccount,
1987
+ inAssociatedTokenAccount,
1988
+ amount,
1989
+ slippageBps,
1990
+ swapMode,
1991
+ quote: v6.quote,
1992
+ reduceOnly,
1993
+ });
1994
+ ixs = res.ixs;
1995
+ lookupTables = res.lookupTables;
1996
+ }
1997
+ else {
1998
+ const res = await this.getJupiterSwapIx({
1999
+ jupiterClient,
2000
+ outMarketIndex,
2001
+ inMarketIndex,
2002
+ outAssociatedTokenAccount,
2003
+ inAssociatedTokenAccount,
2004
+ amount,
2005
+ slippageBps,
2006
+ swapMode,
2007
+ route,
2008
+ reduceOnly,
2009
+ });
2010
+ ixs = res.ixs;
2011
+ lookupTables = res.lookupTables;
2012
+ }
1991
2013
  const tx = (await this.buildTransaction(ixs, txParams, 0, lookupTables));
1992
2014
  const { txSig, slot } = await this.sendTransaction(tx);
1993
2015
  this.spotMarketLastSlotCache.set(outMarketIndex, slot);
@@ -2056,6 +2078,65 @@ class DriftClient {
2056
2078
  ];
2057
2079
  return { ixs, lookupTables };
2058
2080
  }
2081
+ async getJupiterSwapIxV6({ jupiterClient, outMarketIndex, inMarketIndex, outAssociatedTokenAccount, inAssociatedTokenAccount, amount, slippageBps, swapMode, onlyDirectRoutes, quote, reduceOnly, userAccountPublicKey, }) {
2082
+ const outMarket = this.getSpotMarketAccount(outMarketIndex);
2083
+ const inMarket = this.getSpotMarketAccount(inMarketIndex);
2084
+ if (!quote) {
2085
+ const fetchedQuote = await jupiterClient.getQuote({
2086
+ inputMint: inMarket.mint,
2087
+ outputMint: outMarket.mint,
2088
+ amount,
2089
+ slippageBps,
2090
+ swapMode,
2091
+ onlyDirectRoutes,
2092
+ });
2093
+ quote = fetchedQuote;
2094
+ }
2095
+ const transaction = await jupiterClient.getSwap({
2096
+ quote,
2097
+ userPublicKey: this.provider.wallet.publicKey,
2098
+ slippageBps,
2099
+ });
2100
+ const { transactionMessage, lookupTables } = await jupiterClient.getTransactionMessageAndLookupTables({
2101
+ transaction,
2102
+ });
2103
+ const jupiterInstructions = jupiterClient.getJupiterInstructions({
2104
+ transactionMessage,
2105
+ inputMint: inMarket.mint,
2106
+ outputMint: outMarket.mint,
2107
+ });
2108
+ const preInstructions = [];
2109
+ if (!outAssociatedTokenAccount) {
2110
+ outAssociatedTokenAccount = await this.getAssociatedTokenAccount(outMarket.marketIndex, false);
2111
+ const accountInfo = await this.connection.getAccountInfo(outAssociatedTokenAccount);
2112
+ if (!accountInfo) {
2113
+ preInstructions.push(this.createAssociatedTokenAccountIdempotentInstruction(outAssociatedTokenAccount, this.provider.wallet.publicKey, this.provider.wallet.publicKey, outMarket.mint));
2114
+ }
2115
+ }
2116
+ if (!inAssociatedTokenAccount) {
2117
+ inAssociatedTokenAccount = await this.getAssociatedTokenAccount(inMarket.marketIndex, false);
2118
+ const accountInfo = await this.connection.getAccountInfo(inAssociatedTokenAccount);
2119
+ if (!accountInfo) {
2120
+ preInstructions.push(this.createAssociatedTokenAccountIdempotentInstruction(inAssociatedTokenAccount, this.provider.wallet.publicKey, this.provider.wallet.publicKey, inMarket.mint));
2121
+ }
2122
+ }
2123
+ const { beginSwapIx, endSwapIx } = await this.getSwapIx({
2124
+ outMarketIndex,
2125
+ inMarketIndex,
2126
+ amountIn: amount,
2127
+ inTokenAccount: inAssociatedTokenAccount,
2128
+ outTokenAccount: outAssociatedTokenAccount,
2129
+ reduceOnly,
2130
+ userAccountPublicKey,
2131
+ });
2132
+ const ixs = [
2133
+ ...preInstructions,
2134
+ beginSwapIx,
2135
+ ...jupiterInstructions,
2136
+ endSwapIx,
2137
+ ];
2138
+ return { ixs, lookupTables };
2139
+ }
2059
2140
  /**
2060
2141
  * Get the drift begin_swap and end_swap instructions
2061
2142
  *
@@ -2077,6 +2158,7 @@ class DriftClient {
2077
2158
  const remainingAccounts = this.getRemainingAccounts({
2078
2159
  userAccounts,
2079
2160
  writableSpotMarketIndexes: [outMarketIndex, inMarketIndex],
2161
+ readableSpotMarketIndexes: [numericConstants_1.QUOTE_SPOT_MARKET_INDEX],
2080
2162
  });
2081
2163
  const outSpotMarket = this.getSpotMarketAccount(outMarketIndex);
2082
2164
  const inSpotMarket = this.getSpotMarketAccount(inMarketIndex);
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.38.0",
2
+ "version": "2.39.0",
3
3
  "name": "drift",
4
4
  "instructions": [
5
5
  {
package/lib/index.d.ts CHANGED
@@ -65,6 +65,7 @@ export * from './priorityFee/priorityFeeSubscriber';
65
65
  export * from './phoenix/phoenixFulfillmentConfigMap';
66
66
  export * from './tx/fastSingleTxSender';
67
67
  export * from './tx/retryTxSender';
68
+ export * from './tx/priorityFeeCalculator';
68
69
  export * from './tx/types';
69
70
  export * from './util/computeUnits';
70
71
  export * from './util/tps';
package/lib/index.js CHANGED
@@ -88,6 +88,7 @@ __exportStar(require("./priorityFee/priorityFeeSubscriber"), exports);
88
88
  __exportStar(require("./phoenix/phoenixFulfillmentConfigMap"), exports);
89
89
  __exportStar(require("./tx/fastSingleTxSender"), exports);
90
90
  __exportStar(require("./tx/retryTxSender"), exports);
91
+ __exportStar(require("./tx/priorityFeeCalculator"), exports);
91
92
  __exportStar(require("./tx/types"), exports);
92
93
  __exportStar(require("./util/computeUnits"), exports);
93
94
  __exportStar(require("./util/tps"), exports);
@@ -167,7 +167,7 @@ function calculateLiabilityWeight(size, spotMarket, marginCategory) {
167
167
  liabilityWeight = (0, margin_1.calculateSizePremiumLiabilityWeight)(sizeInAmmReservePrecision, new anchor_1.BN(spotMarket.imfFactor), new anchor_1.BN(spotMarket.maintenanceLiabilityWeight), numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION);
168
168
  break;
169
169
  default:
170
- liabilityWeight = spotMarket.initialLiabilityWeight;
170
+ liabilityWeight = new anchor_1.BN(spotMarket.initialLiabilityWeight);
171
171
  break;
172
172
  }
173
173
  return liabilityWeight;
@@ -0,0 +1,44 @@
1
+ import { TransactionInstruction } from '@solana/web3.js';
2
+ /**
3
+ * This class determines whether a priority fee needs to be included in a transaction based on
4
+ * a recent history of timed out transactions.
5
+ */
6
+ export declare class PriorityFeeCalculator {
7
+ lastTxTimeoutCount: number;
8
+ priorityFeeTriggered: boolean;
9
+ lastTxTimeoutCountTriggered: number;
10
+ priorityFeeLatchDurationMs: number;
11
+ /**
12
+ * Constructor for the PriorityFeeCalculator class.
13
+ * @param currentTimeMs - The current time in milliseconds.
14
+ * @param priorityFeeLatchDurationMs - The duration for how long to stay in triggered state before resetting. Default value is 10 seconds.
15
+ */
16
+ constructor(currentTimeMs: number, priorityFeeLatchDurationMs?: number);
17
+ /**
18
+ * Update the priority fee state based on the current time and the current timeout count.
19
+ * @param currentTimeMs current time in milliseconds
20
+ * @returns true if priority fee should be included in the next transaction
21
+ */
22
+ updatePriorityFee(currentTimeMs: number, txTimeoutCount: number): boolean;
23
+ /**
24
+ * This method returns a transaction instruction list that sets the compute limit on the ComputeBudget program.
25
+ * @param computeUnitLimit - The maximum number of compute units that can be used by the transaction.
26
+ * @returns An array of transaction instructions.
27
+ */
28
+ generateComputeBudgetIxs(computeUnitLimit: number): Array<TransactionInstruction>;
29
+ /**
30
+ * Calculates the compute unit price to use based on the desired additional fee to pay and the compute unit limit.
31
+ * @param computeUnitLimit desired CU to use
32
+ * @param additionalFeeMicroLamports desired additional fee to pay, in micro lamports
33
+ * @returns the compute unit price to use, in micro lamports
34
+ */
35
+ calculateComputeUnitPrice(computeUnitLimit: number, additionalFeeMicroLamports: number): number;
36
+ /**
37
+ * This method generates a list of transaction instructions for the ComputeBudget program, and includes a priority fee if it's required
38
+ * @param computeUnitLimit - The maximum number of compute units that can be used by the transaction.
39
+ * @param usePriorityFee - A boolean indicating whether to include a priority fee in the transaction, this should be from `this.updatePriorityFee()` or `this.priorityFeeTriggered()`.
40
+ * @param additionalFeeMicroLamports - The additional fee to be paid, in micro lamports, the actual price will be calculated.
41
+ * @returns An array of transaction instructions.
42
+ */
43
+ generateComputeBudgetWithPriorityFeeIx(computeUnitLimit: number, usePriorityFee: boolean, additionalFeeMicroLamports: number): Array<TransactionInstruction>;
44
+ }
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PriorityFeeCalculator = void 0;
4
+ const web3_js_1 = require("@solana/web3.js");
5
+ /**
6
+ * This class determines whether a priority fee needs to be included in a transaction based on
7
+ * a recent history of timed out transactions.
8
+ */
9
+ class PriorityFeeCalculator {
10
+ /**
11
+ * Constructor for the PriorityFeeCalculator class.
12
+ * @param currentTimeMs - The current time in milliseconds.
13
+ * @param priorityFeeLatchDurationMs - The duration for how long to stay in triggered state before resetting. Default value is 10 seconds.
14
+ */
15
+ constructor(currentTimeMs, priorityFeeLatchDurationMs = 10 * 1000) {
16
+ this.lastTxTimeoutCount = 0;
17
+ this.priorityFeeTriggered = false;
18
+ this.lastTxTimeoutCountTriggered = currentTimeMs;
19
+ this.priorityFeeLatchDurationMs = priorityFeeLatchDurationMs;
20
+ }
21
+ /**
22
+ * Update the priority fee state based on the current time and the current timeout count.
23
+ * @param currentTimeMs current time in milliseconds
24
+ * @returns true if priority fee should be included in the next transaction
25
+ */
26
+ updatePriorityFee(currentTimeMs, txTimeoutCount) {
27
+ let triggerPriorityFee = false;
28
+ if (txTimeoutCount > this.lastTxTimeoutCount) {
29
+ this.lastTxTimeoutCount = txTimeoutCount;
30
+ this.lastTxTimeoutCountTriggered = currentTimeMs;
31
+ triggerPriorityFee = true;
32
+ }
33
+ else {
34
+ if (!this.priorityFeeTriggered) {
35
+ triggerPriorityFee = false;
36
+ }
37
+ else if (currentTimeMs - this.lastTxTimeoutCountTriggered <
38
+ this.priorityFeeLatchDurationMs) {
39
+ triggerPriorityFee = true;
40
+ }
41
+ }
42
+ this.priorityFeeTriggered = triggerPriorityFee;
43
+ return triggerPriorityFee;
44
+ }
45
+ /**
46
+ * This method returns a transaction instruction list that sets the compute limit on the ComputeBudget program.
47
+ * @param computeUnitLimit - The maximum number of compute units that can be used by the transaction.
48
+ * @returns An array of transaction instructions.
49
+ */
50
+ generateComputeBudgetIxs(computeUnitLimit) {
51
+ const ixs = [
52
+ web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({
53
+ units: computeUnitLimit,
54
+ }),
55
+ ];
56
+ return ixs;
57
+ }
58
+ /**
59
+ * Calculates the compute unit price to use based on the desired additional fee to pay and the compute unit limit.
60
+ * @param computeUnitLimit desired CU to use
61
+ * @param additionalFeeMicroLamports desired additional fee to pay, in micro lamports
62
+ * @returns the compute unit price to use, in micro lamports
63
+ */
64
+ calculateComputeUnitPrice(computeUnitLimit, additionalFeeMicroLamports) {
65
+ return additionalFeeMicroLamports / computeUnitLimit;
66
+ }
67
+ /**
68
+ * This method generates a list of transaction instructions for the ComputeBudget program, and includes a priority fee if it's required
69
+ * @param computeUnitLimit - The maximum number of compute units that can be used by the transaction.
70
+ * @param usePriorityFee - A boolean indicating whether to include a priority fee in the transaction, this should be from `this.updatePriorityFee()` or `this.priorityFeeTriggered()`.
71
+ * @param additionalFeeMicroLamports - The additional fee to be paid, in micro lamports, the actual price will be calculated.
72
+ * @returns An array of transaction instructions.
73
+ */
74
+ generateComputeBudgetWithPriorityFeeIx(computeUnitLimit, usePriorityFee, additionalFeeMicroLamports) {
75
+ const ixs = this.generateComputeBudgetIxs(computeUnitLimit);
76
+ if (usePriorityFee) {
77
+ const computeUnitPrice = this.calculateComputeUnitPrice(computeUnitLimit, additionalFeeMicroLamports);
78
+ ixs.push(web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({
79
+ microLamports: computeUnitPrice,
80
+ }));
81
+ }
82
+ return ixs;
83
+ }
84
+ }
85
+ exports.PriorityFeeCalculator = PriorityFeeCalculator;
package/lib/user.js CHANGED
@@ -577,7 +577,7 @@ class User {
577
577
  continue;
578
578
  }
579
579
  }
580
- const { tokenAmount: worstCaseTokenAmount, ordersValue: worstCaseQuoteTokenAmount, } = (0, spotPosition_1.getWorstCaseTokenAmounts)(spotPosition, spotMarketAccount, strictOraclePrice, marginCategory);
580
+ const { tokenAmount: worstCaseTokenAmount, ordersValue: worstCaseQuoteTokenAmount, } = (0, spotPosition_1.getWorstCaseTokenAmounts)(spotPosition, spotMarketAccount, strictOraclePrice, marginCategory !== null && marginCategory !== void 0 ? marginCategory : 'Initial');
581
581
  if (worstCaseTokenAmount.gt(numericConstants_1.ZERO) && countForBase) {
582
582
  const baseAssetValue = this.getSpotAssetValue(worstCaseTokenAmount, strictOraclePrice, spotMarketAccount, marginCategory);
583
583
  totalAssetValue = totalAssetValue.add(baseAssetValue);
@@ -1834,7 +1834,7 @@ class User {
1834
1834
  const spotMarketAccount = this.driftClient.getQuoteSpotMarketAccount();
1835
1835
  const oraclePriceData = this.getOracleDataForSpotMarket(numericConstants_1.QUOTE_SPOT_MARKET_INDEX);
1836
1836
  const baseAssetValue = (0, _1.getTokenValue)(netQuoteValue, spotMarketAccount.decimals, oraclePriceData);
1837
- const { weight, weightedTokenValue } = (0, spotPosition_1.calculateWeightedTokenValue)(netQuoteValue, baseAssetValue, oraclePriceData, spotMarketAccount, marginCategory);
1837
+ const { weight, weightedTokenValue } = (0, spotPosition_1.calculateWeightedTokenValue)(netQuoteValue, baseAssetValue, oraclePriceData.price, spotMarketAccount, marginCategory);
1838
1838
  if (netQuoteValue.lt(numericConstants_1.ZERO)) {
1839
1839
  healthComponents.borrows.push({
1840
1840
  marketIndex: spotMarketAccount.marketIndex,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.38.1-beta.9",
3
+ "version": "2.39.1-beta.1",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -113,7 +113,12 @@ import { isSpotPositionAvailable } from './math/spotPosition';
113
113
  import { calculateMarketMaxAvailableInsurance } from './math/market';
114
114
  import { fetchUserStatsAccount } from './accounts/fetch';
115
115
  import { castNumberToSpotPrecision } from './math/spotMarket';
116
- import { JupiterClient, Route, SwapMode } from './jupiter/jupiterClient';
116
+ import {
117
+ JupiterClient,
118
+ QuoteResponse,
119
+ Route,
120
+ SwapMode,
121
+ } from './jupiter/jupiterClient';
117
122
  import { getNonIdleUserFilter } from './memcmp';
118
123
  import { UserStatsSubscriptionConfig } from './userStatsConfig';
119
124
  import { getMarinadeDepositIx, getMarinadeFinanceProgram } from './marinade';
@@ -3418,6 +3423,7 @@ export class DriftClient {
3418
3423
  route,
3419
3424
  reduceOnly,
3420
3425
  txParams,
3426
+ v6,
3421
3427
  }: {
3422
3428
  jupiterClient: JupiterClient;
3423
3429
  outMarketIndex: number;
@@ -3430,19 +3436,44 @@ export class DriftClient {
3430
3436
  route?: Route;
3431
3437
  reduceOnly?: SwapReduceOnly;
3432
3438
  txParams?: TxParams;
3439
+ v6?: {
3440
+ quote?: QuoteResponse;
3441
+ };
3433
3442
  }): Promise<TransactionSignature> {
3434
- const { ixs, lookupTables } = await this.getJupiterSwapIx({
3435
- jupiterClient,
3436
- outMarketIndex,
3437
- inMarketIndex,
3438
- outAssociatedTokenAccount,
3439
- inAssociatedTokenAccount,
3440
- amount,
3441
- slippageBps,
3442
- swapMode,
3443
- route,
3444
- reduceOnly,
3445
- });
3443
+ let ixs: anchor.web3.TransactionInstruction[];
3444
+ let lookupTables: anchor.web3.AddressLookupTableAccount[];
3445
+
3446
+ if (v6) {
3447
+ const res = await this.getJupiterSwapIxV6({
3448
+ jupiterClient,
3449
+ outMarketIndex,
3450
+ inMarketIndex,
3451
+ outAssociatedTokenAccount,
3452
+ inAssociatedTokenAccount,
3453
+ amount,
3454
+ slippageBps,
3455
+ swapMode,
3456
+ quote: v6.quote,
3457
+ reduceOnly,
3458
+ });
3459
+ ixs = res.ixs;
3460
+ lookupTables = res.lookupTables;
3461
+ } else {
3462
+ const res = await this.getJupiterSwapIx({
3463
+ jupiterClient,
3464
+ outMarketIndex,
3465
+ inMarketIndex,
3466
+ outAssociatedTokenAccount,
3467
+ inAssociatedTokenAccount,
3468
+ amount,
3469
+ slippageBps,
3470
+ swapMode,
3471
+ route,
3472
+ reduceOnly,
3473
+ });
3474
+ ixs = res.ixs;
3475
+ lookupTables = res.lookupTables;
3476
+ }
3446
3477
 
3447
3478
  const tx = (await this.buildTransaction(
3448
3479
  ixs,
@@ -3588,6 +3619,132 @@ export class DriftClient {
3588
3619
  return { ixs, lookupTables };
3589
3620
  }
3590
3621
 
3622
+ public async getJupiterSwapIxV6({
3623
+ jupiterClient,
3624
+ outMarketIndex,
3625
+ inMarketIndex,
3626
+ outAssociatedTokenAccount,
3627
+ inAssociatedTokenAccount,
3628
+ amount,
3629
+ slippageBps,
3630
+ swapMode,
3631
+ onlyDirectRoutes,
3632
+ quote,
3633
+ reduceOnly,
3634
+ userAccountPublicKey,
3635
+ }: {
3636
+ jupiterClient: JupiterClient;
3637
+ outMarketIndex: number;
3638
+ inMarketIndex: number;
3639
+ outAssociatedTokenAccount?: PublicKey;
3640
+ inAssociatedTokenAccount?: PublicKey;
3641
+ amount: BN;
3642
+ slippageBps?: number;
3643
+ swapMode?: SwapMode;
3644
+ onlyDirectRoutes?: boolean;
3645
+ quote?: QuoteResponse;
3646
+ reduceOnly?: SwapReduceOnly;
3647
+ userAccountPublicKey?: PublicKey;
3648
+ }): Promise<{
3649
+ ixs: TransactionInstruction[];
3650
+ lookupTables: AddressLookupTableAccount[];
3651
+ }> {
3652
+ const outMarket = this.getSpotMarketAccount(outMarketIndex);
3653
+ const inMarket = this.getSpotMarketAccount(inMarketIndex);
3654
+
3655
+ if (!quote) {
3656
+ const fetchedQuote = await jupiterClient.getQuote({
3657
+ inputMint: inMarket.mint,
3658
+ outputMint: outMarket.mint,
3659
+ amount,
3660
+ slippageBps,
3661
+ swapMode,
3662
+ onlyDirectRoutes,
3663
+ });
3664
+
3665
+ quote = fetchedQuote;
3666
+ }
3667
+
3668
+ const transaction = await jupiterClient.getSwap({
3669
+ quote,
3670
+ userPublicKey: this.provider.wallet.publicKey,
3671
+ slippageBps,
3672
+ });
3673
+
3674
+ const { transactionMessage, lookupTables } =
3675
+ await jupiterClient.getTransactionMessageAndLookupTables({
3676
+ transaction,
3677
+ });
3678
+
3679
+ const jupiterInstructions = jupiterClient.getJupiterInstructions({
3680
+ transactionMessage,
3681
+ inputMint: inMarket.mint,
3682
+ outputMint: outMarket.mint,
3683
+ });
3684
+
3685
+ const preInstructions = [];
3686
+ if (!outAssociatedTokenAccount) {
3687
+ outAssociatedTokenAccount = await this.getAssociatedTokenAccount(
3688
+ outMarket.marketIndex,
3689
+ false
3690
+ );
3691
+
3692
+ const accountInfo = await this.connection.getAccountInfo(
3693
+ outAssociatedTokenAccount
3694
+ );
3695
+ if (!accountInfo) {
3696
+ preInstructions.push(
3697
+ this.createAssociatedTokenAccountIdempotentInstruction(
3698
+ outAssociatedTokenAccount,
3699
+ this.provider.wallet.publicKey,
3700
+ this.provider.wallet.publicKey,
3701
+ outMarket.mint
3702
+ )
3703
+ );
3704
+ }
3705
+ }
3706
+
3707
+ if (!inAssociatedTokenAccount) {
3708
+ inAssociatedTokenAccount = await this.getAssociatedTokenAccount(
3709
+ inMarket.marketIndex,
3710
+ false
3711
+ );
3712
+
3713
+ const accountInfo = await this.connection.getAccountInfo(
3714
+ inAssociatedTokenAccount
3715
+ );
3716
+ if (!accountInfo) {
3717
+ preInstructions.push(
3718
+ this.createAssociatedTokenAccountIdempotentInstruction(
3719
+ inAssociatedTokenAccount,
3720
+ this.provider.wallet.publicKey,
3721
+ this.provider.wallet.publicKey,
3722
+ inMarket.mint
3723
+ )
3724
+ );
3725
+ }
3726
+ }
3727
+
3728
+ const { beginSwapIx, endSwapIx } = await this.getSwapIx({
3729
+ outMarketIndex,
3730
+ inMarketIndex,
3731
+ amountIn: amount,
3732
+ inTokenAccount: inAssociatedTokenAccount,
3733
+ outTokenAccount: outAssociatedTokenAccount,
3734
+ reduceOnly,
3735
+ userAccountPublicKey,
3736
+ });
3737
+
3738
+ const ixs = [
3739
+ ...preInstructions,
3740
+ beginSwapIx,
3741
+ ...jupiterInstructions,
3742
+ endSwapIx,
3743
+ ];
3744
+
3745
+ return { ixs, lookupTables };
3746
+ }
3747
+
3591
3748
  /**
3592
3749
  * Get the drift begin_swap and end_swap instructions
3593
3750
  *
@@ -3632,6 +3789,7 @@ export class DriftClient {
3632
3789
  const remainingAccounts = this.getRemainingAccounts({
3633
3790
  userAccounts,
3634
3791
  writableSpotMarketIndexes: [outMarketIndex, inMarketIndex],
3792
+ readableSpotMarketIndexes: [QUOTE_SPOT_MARKET_INDEX],
3635
3793
  });
3636
3794
 
3637
3795
  const outSpotMarket = this.getSpotMarketAccount(outMarketIndex);
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.38.0",
2
+ "version": "2.39.0",
3
3
  "name": "drift",
4
4
  "instructions": [
5
5
  {
package/src/index.ts CHANGED
@@ -66,6 +66,7 @@ export * from './priorityFee/priorityFeeSubscriber';
66
66
  export * from './phoenix/phoenixFulfillmentConfigMap';
67
67
  export * from './tx/fastSingleTxSender';
68
68
  export * from './tx/retryTxSender';
69
+ export * from './tx/priorityFeeCalculator';
69
70
  export * from './tx/types';
70
71
  export * from './util/computeUnits';
71
72
  export * from './util/tps';
@@ -255,7 +255,7 @@ export function calculateLiabilityWeight(
255
255
  );
256
256
  break;
257
257
  default:
258
- liabilityWeight = spotMarket.initialLiabilityWeight;
258
+ liabilityWeight = new BN(spotMarket.initialLiabilityWeight);
259
259
  break;
260
260
  }
261
261
 
@@ -0,0 +1,117 @@
1
+ import { ComputeBudgetProgram, TransactionInstruction } from '@solana/web3.js';
2
+
3
+ /**
4
+ * This class determines whether a priority fee needs to be included in a transaction based on
5
+ * a recent history of timed out transactions.
6
+ */
7
+ export class PriorityFeeCalculator {
8
+ lastTxTimeoutCount: number;
9
+ priorityFeeTriggered: boolean;
10
+ lastTxTimeoutCountTriggered: number;
11
+ priorityFeeLatchDurationMs: number; // how long to stay in triggered state before resetting
12
+
13
+ /**
14
+ * Constructor for the PriorityFeeCalculator class.
15
+ * @param currentTimeMs - The current time in milliseconds.
16
+ * @param priorityFeeLatchDurationMs - The duration for how long to stay in triggered state before resetting. Default value is 10 seconds.
17
+ */
18
+ constructor(
19
+ currentTimeMs: number,
20
+ priorityFeeLatchDurationMs: number = 10 * 1000
21
+ ) {
22
+ this.lastTxTimeoutCount = 0;
23
+ this.priorityFeeTriggered = false;
24
+ this.lastTxTimeoutCountTriggered = currentTimeMs;
25
+ this.priorityFeeLatchDurationMs = priorityFeeLatchDurationMs;
26
+ }
27
+
28
+ /**
29
+ * Update the priority fee state based on the current time and the current timeout count.
30
+ * @param currentTimeMs current time in milliseconds
31
+ * @returns true if priority fee should be included in the next transaction
32
+ */
33
+ public updatePriorityFee(
34
+ currentTimeMs: number,
35
+ txTimeoutCount: number
36
+ ): boolean {
37
+ let triggerPriorityFee = false;
38
+
39
+ if (txTimeoutCount > this.lastTxTimeoutCount) {
40
+ this.lastTxTimeoutCount = txTimeoutCount;
41
+ this.lastTxTimeoutCountTriggered = currentTimeMs;
42
+ triggerPriorityFee = true;
43
+ } else {
44
+ if (!this.priorityFeeTriggered) {
45
+ triggerPriorityFee = false;
46
+ } else if (
47
+ currentTimeMs - this.lastTxTimeoutCountTriggered <
48
+ this.priorityFeeLatchDurationMs
49
+ ) {
50
+ triggerPriorityFee = true;
51
+ }
52
+ }
53
+
54
+ this.priorityFeeTriggered = triggerPriorityFee;
55
+
56
+ return triggerPriorityFee;
57
+ }
58
+
59
+ /**
60
+ * This method returns a transaction instruction list that sets the compute limit on the ComputeBudget program.
61
+ * @param computeUnitLimit - The maximum number of compute units that can be used by the transaction.
62
+ * @returns An array of transaction instructions.
63
+ */
64
+ public generateComputeBudgetIxs(
65
+ computeUnitLimit: number
66
+ ): Array<TransactionInstruction> {
67
+ const ixs = [
68
+ ComputeBudgetProgram.setComputeUnitLimit({
69
+ units: computeUnitLimit,
70
+ }),
71
+ ];
72
+
73
+ return ixs;
74
+ }
75
+
76
+ /**
77
+ * Calculates the compute unit price to use based on the desired additional fee to pay and the compute unit limit.
78
+ * @param computeUnitLimit desired CU to use
79
+ * @param additionalFeeMicroLamports desired additional fee to pay, in micro lamports
80
+ * @returns the compute unit price to use, in micro lamports
81
+ */
82
+ public calculateComputeUnitPrice(
83
+ computeUnitLimit: number,
84
+ additionalFeeMicroLamports: number
85
+ ): number {
86
+ return additionalFeeMicroLamports / computeUnitLimit;
87
+ }
88
+
89
+ /**
90
+ * This method generates a list of transaction instructions for the ComputeBudget program, and includes a priority fee if it's required
91
+ * @param computeUnitLimit - The maximum number of compute units that can be used by the transaction.
92
+ * @param usePriorityFee - A boolean indicating whether to include a priority fee in the transaction, this should be from `this.updatePriorityFee()` or `this.priorityFeeTriggered()`.
93
+ * @param additionalFeeMicroLamports - The additional fee to be paid, in micro lamports, the actual price will be calculated.
94
+ * @returns An array of transaction instructions.
95
+ */
96
+ public generateComputeBudgetWithPriorityFeeIx(
97
+ computeUnitLimit: number,
98
+ usePriorityFee: boolean,
99
+ additionalFeeMicroLamports: number
100
+ ): Array<TransactionInstruction> {
101
+ const ixs = this.generateComputeBudgetIxs(computeUnitLimit);
102
+
103
+ if (usePriorityFee) {
104
+ const computeUnitPrice = this.calculateComputeUnitPrice(
105
+ computeUnitLimit,
106
+ additionalFeeMicroLamports
107
+ );
108
+ ixs.push(
109
+ ComputeBudgetProgram.setComputeUnitPrice({
110
+ microLamports: computeUnitPrice,
111
+ })
112
+ );
113
+ }
114
+
115
+ return ixs;
116
+ }
117
+ }
package/src/user.ts CHANGED
@@ -967,7 +967,7 @@ export class User {
967
967
  spotPosition,
968
968
  spotMarketAccount,
969
969
  strictOraclePrice,
970
- marginCategory
970
+ marginCategory ?? 'Initial'
971
971
  );
972
972
 
973
973
  if (worstCaseTokenAmount.gt(ZERO) && countForBase) {
@@ -3320,7 +3320,7 @@ export class User {
3320
3320
  const { weight, weightedTokenValue } = calculateWeightedTokenValue(
3321
3321
  netQuoteValue,
3322
3322
  baseAssetValue,
3323
- oraclePriceData,
3323
+ oraclePriceData.price,
3324
3324
  spotMarketAccount,
3325
3325
  marginCategory
3326
3326
  );
@@ -0,0 +1,77 @@
1
+ import { expect } from 'chai';
2
+ import { PriorityFeeCalculator } from '../../src/tx/priorityFeeCalculator';
3
+
4
+ describe('PriorityFeeCalculator', () => {
5
+ let priorityFeeCalculator: PriorityFeeCalculator;
6
+
7
+ const startTime = 1000000;
8
+ const latch_duration = 10_000;
9
+
10
+ beforeEach(() => {
11
+ priorityFeeCalculator = new PriorityFeeCalculator(
12
+ startTime,
13
+ latch_duration
14
+ );
15
+ });
16
+
17
+ it('should trigger priority fee when timeout count increases', () => {
18
+ const timeoutCount = 1;
19
+ expect(priorityFeeCalculator.updatePriorityFee(startTime, timeoutCount)).to
20
+ .be.true;
21
+ expect(
22
+ priorityFeeCalculator.updatePriorityFee(
23
+ startTime + latch_duration,
24
+ timeoutCount + 1
25
+ )
26
+ ).to.be.true;
27
+ expect(
28
+ priorityFeeCalculator.updatePriorityFee(
29
+ startTime + latch_duration,
30
+ timeoutCount + 2
31
+ )
32
+ ).to.be.true;
33
+ });
34
+
35
+ it('should trigger priority fee when timeout count increases, and stay latched until latch duration', () => {
36
+ const timeoutCount = 1;
37
+ expect(priorityFeeCalculator.updatePriorityFee(startTime, timeoutCount)).to
38
+ .be.true;
39
+ expect(
40
+ priorityFeeCalculator.updatePriorityFee(
41
+ startTime + latch_duration / 2,
42
+ timeoutCount
43
+ )
44
+ ).to.be.true;
45
+ expect(
46
+ priorityFeeCalculator.updatePriorityFee(
47
+ startTime + latch_duration - 1,
48
+ timeoutCount
49
+ )
50
+ ).to.be.true;
51
+ expect(
52
+ priorityFeeCalculator.updatePriorityFee(
53
+ startTime + latch_duration * 2,
54
+ timeoutCount
55
+ )
56
+ ).to.be.false;
57
+ });
58
+
59
+ it('should not trigger priority fee when timeout count does not increase', () => {
60
+ const timeoutCount = 0;
61
+ expect(priorityFeeCalculator.updatePriorityFee(startTime, timeoutCount)).to
62
+ .be.false;
63
+ });
64
+
65
+ it('should correctly calculate compute unit price', () => {
66
+ const computeUnitLimit = 1_000_000;
67
+ const additionalFeeMicroLamports = 1_000_000_000; // 1000 lamports
68
+ const actualComputeUnitPrice =
69
+ priorityFeeCalculator.calculateComputeUnitPrice(
70
+ computeUnitLimit,
71
+ additionalFeeMicroLamports
72
+ );
73
+ expect(actualComputeUnitPrice * computeUnitLimit).to.equal(
74
+ additionalFeeMicroLamports
75
+ );
76
+ });
77
+ });