@drift-labs/sdk 2.144.0-beta.1 → 2.144.0-beta.3

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.144.0-beta.1
1
+ 2.144.0-beta.3
@@ -413,18 +413,6 @@ class grpcDriftClientAccountSubscriberV2 {
413
413
  // Remove accounts in batches - perp markets
414
414
  if (perpMarketPubkeysToRemove.length > 0) {
415
415
  await this.perpMarketsSubscriber.removeAccounts(perpMarketPubkeysToRemove);
416
- // Clean up the mapping for removed perp markets
417
- for (const pubkey of perpMarketPubkeysToRemove) {
418
- const pubkeyString = pubkey.toBase58();
419
- for (const [marketIndex, accountPubkey,] of this.perpMarketIndexToAccountPubkeyMap.entries()) {
420
- if (accountPubkey === pubkeyString) {
421
- this.perpMarketIndexToAccountPubkeyMap.delete(marketIndex);
422
- this.perpOracleMap.delete(marketIndex);
423
- this.perpOracleStringMap.delete(marketIndex);
424
- break;
425
- }
426
- }
427
- }
428
416
  }
429
417
  // Remove accounts in batches - oracles
430
418
  if (oraclePubkeysToRemove.length > 0) {
@@ -26,6 +26,11 @@ import { PythSolanaReceiver } from '@pythnetwork/pyth-solana-receiver/lib/idl/py
26
26
  import { Slothash } from './slot/SlothashSubscriber';
27
27
  import { SignedMsgOrderParams } from './types';
28
28
  import { RevenueShareEscrowMap } from './userMap/revenueShareEscrowMap';
29
+ import { TitanClient } from './titan/titanClient';
30
+ /**
31
+ * Union type for swap clients (Titan and Jupiter)
32
+ */
33
+ export type SwapClient = TitanClient | JupiterClient;
29
34
  type RemainingAccountParams = {
30
35
  userAccounts: UserAccount[];
31
36
  writablePerpMarketIndexes?: number[];
@@ -531,23 +536,23 @@ export declare class DriftClient {
531
536
  addPhoenixRemainingAccounts(marketIndex: number, remainingAccounts: AccountMeta[], fulfillmentConfig: PhoenixV1FulfillmentConfigAccount): void;
532
537
  addOpenbookRemainingAccounts(marketIndex: number, remainingAccounts: AccountMeta[], fulfillmentConfig: OpenbookV2FulfillmentConfigAccount): void;
533
538
  /**
534
- * Swap tokens in drift account using jupiter
535
- * @param jupiterClient jupiter client to find routes and jupiter instructions
539
+ * Swap tokens in drift account using titan or jupiter
540
+ * @param swapClient swap client to find routes and instructions (Titan or Jupiter)
536
541
  * @param outMarketIndex the market index of the token you're buying
537
542
  * @param inMarketIndex the market index of the token you're selling
538
- * @param outAssociatedTokenAccount the token account to receive the token being sold on jupiter
543
+ * @param outAssociatedTokenAccount the token account to receive the token being sold on titan or jupiter
539
544
  * @param inAssociatedTokenAccount the token account to
540
545
  * @param amount the amount of TokenIn, regardless of swapMode
541
- * @param slippageBps the max slippage passed to jupiter api
542
- * @param swapMode jupiter swapMode (ExactIn or ExactOut), default is ExactIn
543
- * @param route the jupiter route to use for the swap
546
+ * @param slippageBps the max slippage passed to titan or jupiter api
547
+ * @param swapMode titan or jupiter swapMode (ExactIn or ExactOut), default is ExactIn
548
+ * @param route the titan or jupiter route to use for the swap
544
549
  * @param reduceOnly specify if In or Out token on the drift account must reduceOnly, checked at end of swap
545
550
  * @param v6 pass in the quote response from Jupiter quote's API (deprecated, use quote instead)
546
551
  * @param quote pass in the quote response from Jupiter quote's API
547
552
  * @param txParams
548
553
  */
549
- swap({ jupiterClient, outMarketIndex, inMarketIndex, outAssociatedTokenAccount, inAssociatedTokenAccount, amount, slippageBps, swapMode, reduceOnly, txParams, v6, quote, onlyDirectRoutes, }: {
550
- jupiterClient: JupiterClient;
554
+ swap({ swapClient, outMarketIndex, inMarketIndex, outAssociatedTokenAccount, inAssociatedTokenAccount, amount, slippageBps, swapMode, reduceOnly, txParams, v6, quote, onlyDirectRoutes, }: {
555
+ swapClient: SwapClient;
551
556
  outMarketIndex: number;
552
557
  inMarketIndex: number;
553
558
  outAssociatedTokenAccount?: PublicKey;
@@ -563,6 +568,22 @@ export declare class DriftClient {
563
568
  };
564
569
  quote?: QuoteResponse;
565
570
  }): Promise<TransactionSignature>;
571
+ getTitanSwapIx({ titanClient, outMarketIndex, inMarketIndex, outAssociatedTokenAccount, inAssociatedTokenAccount, amount, slippageBps, swapMode, onlyDirectRoutes, reduceOnly, userAccountPublicKey, }: {
572
+ titanClient: TitanClient;
573
+ outMarketIndex: number;
574
+ inMarketIndex: number;
575
+ outAssociatedTokenAccount?: PublicKey;
576
+ inAssociatedTokenAccount?: PublicKey;
577
+ amount: BN;
578
+ slippageBps?: number;
579
+ swapMode?: string;
580
+ onlyDirectRoutes?: boolean;
581
+ reduceOnly?: SwapReduceOnly;
582
+ userAccountPublicKey?: PublicKey;
583
+ }): Promise<{
584
+ ixs: TransactionInstruction[];
585
+ lookupTables: AddressLookupTableAccount[];
586
+ }>;
566
587
  getJupiterSwapIxV6({ jupiterClient, outMarketIndex, inMarketIndex, outAssociatedTokenAccount, inAssociatedTokenAccount, amount, slippageBps, swapMode, onlyDirectRoutes, quote, reduceOnly, userAccountPublicKey, }: {
567
588
  jupiterClient: JupiterClient;
568
589
  outMarketIndex: number;
@@ -51,6 +51,7 @@ const spotPosition_1 = require("./math/spotPosition");
51
51
  const market_1 = require("./math/market");
52
52
  const fetch_1 = require("./accounts/fetch");
53
53
  const spotMarket_1 = require("./math/spotMarket");
54
+ const jupiterClient_1 = require("./jupiter/jupiterClient");
54
55
  const memcmp_1 = require("./memcmp");
55
56
  const marinade_1 = require("./marinade");
56
57
  const orderParams_1 = require("./orderParams");
@@ -74,6 +75,7 @@ const utils_3 = require("./oracles/utils");
74
75
  const webSocketDriftClientAccountSubscriber_1 = require("./accounts/webSocketDriftClientAccountSubscriber");
75
76
  const orders_1 = require("./math/orders");
76
77
  const builder_1 = require("./math/builder");
78
+ const titanClient_1 = require("./titan/titanClient");
77
79
  /**
78
80
  * # DriftClient
79
81
  * This class is the main way to interact with Drift Protocol. It allows you to subscribe to the various accounts where the Market's state is stored, as well as: opening positions, liquidating, settling funding, depositing & withdrawing, and more.
@@ -3100,36 +3102,56 @@ class DriftClient {
3100
3102
  }
3101
3103
  }
3102
3104
  /**
3103
- * Swap tokens in drift account using jupiter
3104
- * @param jupiterClient jupiter client to find routes and jupiter instructions
3105
+ * Swap tokens in drift account using titan or jupiter
3106
+ * @param swapClient swap client to find routes and instructions (Titan or Jupiter)
3105
3107
  * @param outMarketIndex the market index of the token you're buying
3106
3108
  * @param inMarketIndex the market index of the token you're selling
3107
- * @param outAssociatedTokenAccount the token account to receive the token being sold on jupiter
3109
+ * @param outAssociatedTokenAccount the token account to receive the token being sold on titan or jupiter
3108
3110
  * @param inAssociatedTokenAccount the token account to
3109
3111
  * @param amount the amount of TokenIn, regardless of swapMode
3110
- * @param slippageBps the max slippage passed to jupiter api
3111
- * @param swapMode jupiter swapMode (ExactIn or ExactOut), default is ExactIn
3112
- * @param route the jupiter route to use for the swap
3112
+ * @param slippageBps the max slippage passed to titan or jupiter api
3113
+ * @param swapMode titan or jupiter swapMode (ExactIn or ExactOut), default is ExactIn
3114
+ * @param route the titan or jupiter route to use for the swap
3113
3115
  * @param reduceOnly specify if In or Out token on the drift account must reduceOnly, checked at end of swap
3114
3116
  * @param v6 pass in the quote response from Jupiter quote's API (deprecated, use quote instead)
3115
3117
  * @param quote pass in the quote response from Jupiter quote's API
3116
3118
  * @param txParams
3117
3119
  */
3118
- async swap({ jupiterClient, outMarketIndex, inMarketIndex, outAssociatedTokenAccount, inAssociatedTokenAccount, amount, slippageBps, swapMode, reduceOnly, txParams, v6, quote, onlyDirectRoutes = false, }) {
3119
- const quoteToUse = quote !== null && quote !== void 0 ? quote : v6 === null || v6 === void 0 ? void 0 : v6.quote;
3120
- const res = await this.getJupiterSwapIxV6({
3121
- jupiterClient,
3122
- outMarketIndex,
3123
- inMarketIndex,
3124
- outAssociatedTokenAccount,
3125
- inAssociatedTokenAccount,
3126
- amount,
3127
- slippageBps,
3128
- swapMode,
3129
- quote: quoteToUse,
3130
- reduceOnly,
3131
- onlyDirectRoutes,
3132
- });
3120
+ async swap({ swapClient, outMarketIndex, inMarketIndex, outAssociatedTokenAccount, inAssociatedTokenAccount, amount, slippageBps, swapMode, reduceOnly, txParams, v6, quote, onlyDirectRoutes = false, }) {
3121
+ let res;
3122
+ if (swapClient instanceof titanClient_1.TitanClient) {
3123
+ res = await this.getTitanSwapIx({
3124
+ titanClient: swapClient,
3125
+ outMarketIndex,
3126
+ inMarketIndex,
3127
+ outAssociatedTokenAccount,
3128
+ inAssociatedTokenAccount,
3129
+ amount,
3130
+ slippageBps,
3131
+ swapMode,
3132
+ onlyDirectRoutes,
3133
+ reduceOnly,
3134
+ });
3135
+ }
3136
+ else if (swapClient instanceof jupiterClient_1.JupiterClient) {
3137
+ const quoteToUse = quote !== null && quote !== void 0 ? quote : v6 === null || v6 === void 0 ? void 0 : v6.quote;
3138
+ res = await this.getJupiterSwapIxV6({
3139
+ jupiterClient: swapClient,
3140
+ outMarketIndex,
3141
+ inMarketIndex,
3142
+ outAssociatedTokenAccount,
3143
+ inAssociatedTokenAccount,
3144
+ amount,
3145
+ slippageBps,
3146
+ swapMode,
3147
+ quote: quoteToUse,
3148
+ reduceOnly,
3149
+ onlyDirectRoutes,
3150
+ });
3151
+ }
3152
+ else {
3153
+ throw new Error('Invalid swap client type. Must be TitanClient or JupiterClient.');
3154
+ }
3133
3155
  const ixs = res.ixs;
3134
3156
  const lookupTables = res.lookupTables;
3135
3157
  const tx = (await this.buildTransaction(ixs, txParams, 0, lookupTables));
@@ -3138,6 +3160,60 @@ class DriftClient {
3138
3160
  this.spotMarketLastSlotCache.set(inMarketIndex, slot);
3139
3161
  return txSig;
3140
3162
  }
3163
+ async getTitanSwapIx({ titanClient, outMarketIndex, inMarketIndex, outAssociatedTokenAccount, inAssociatedTokenAccount, amount, slippageBps, swapMode, onlyDirectRoutes, reduceOnly, userAccountPublicKey, }) {
3164
+ const outMarket = this.getSpotMarketAccount(outMarketIndex);
3165
+ const inMarket = this.getSpotMarketAccount(inMarketIndex);
3166
+ const isExactOut = swapMode === 'ExactOut';
3167
+ const exactOutBufferedAmountIn = amount.muln(1001).divn(1000); // Add 10bp buffer
3168
+ const preInstructions = [];
3169
+ if (!outAssociatedTokenAccount) {
3170
+ const tokenProgram = this.getTokenProgramForSpotMarket(outMarket);
3171
+ outAssociatedTokenAccount = await this.getAssociatedTokenAccount(outMarket.marketIndex, false, tokenProgram);
3172
+ const accountInfo = await this.connection.getAccountInfo(outAssociatedTokenAccount);
3173
+ if (!accountInfo) {
3174
+ preInstructions.push(this.createAssociatedTokenAccountIdempotentInstruction(outAssociatedTokenAccount, this.provider.wallet.publicKey, this.provider.wallet.publicKey, outMarket.mint, tokenProgram));
3175
+ }
3176
+ }
3177
+ if (!inAssociatedTokenAccount) {
3178
+ const tokenProgram = this.getTokenProgramForSpotMarket(inMarket);
3179
+ inAssociatedTokenAccount = await this.getAssociatedTokenAccount(inMarket.marketIndex, false, tokenProgram);
3180
+ const accountInfo = await this.connection.getAccountInfo(inAssociatedTokenAccount);
3181
+ if (!accountInfo) {
3182
+ preInstructions.push(this.createAssociatedTokenAccountIdempotentInstruction(inAssociatedTokenAccount, this.provider.wallet.publicKey, this.provider.wallet.publicKey, inMarket.mint, tokenProgram));
3183
+ }
3184
+ }
3185
+ const { beginSwapIx, endSwapIx } = await this.getSwapIx({
3186
+ outMarketIndex,
3187
+ inMarketIndex,
3188
+ amountIn: isExactOut ? exactOutBufferedAmountIn : amount,
3189
+ inTokenAccount: inAssociatedTokenAccount,
3190
+ outTokenAccount: outAssociatedTokenAccount,
3191
+ reduceOnly,
3192
+ userAccountPublicKey,
3193
+ });
3194
+ const { transactionMessage, lookupTables } = await titanClient.getSwap({
3195
+ inputMint: inMarket.mint,
3196
+ outputMint: outMarket.mint,
3197
+ amount,
3198
+ userPublicKey: this.provider.wallet.publicKey,
3199
+ slippageBps,
3200
+ swapMode: isExactOut ? titanClient_1.SwapMode.ExactOut : titanClient_1.SwapMode.ExactIn,
3201
+ onlyDirectRoutes,
3202
+ sizeConstraint: utils_2.MAX_TX_BYTE_SIZE - 375, // buffer for drift instructions
3203
+ });
3204
+ const titanInstructions = titanClient.getTitanInstructions({
3205
+ transactionMessage,
3206
+ inputMint: inMarket.mint,
3207
+ outputMint: outMarket.mint,
3208
+ });
3209
+ const ixs = [
3210
+ ...preInstructions,
3211
+ beginSwapIx,
3212
+ ...titanInstructions,
3213
+ endSwapIx,
3214
+ ];
3215
+ return { ixs, lookupTables };
3216
+ }
3141
3217
  async getJupiterSwapIxV6({ jupiterClient, outMarketIndex, inMarketIndex, outAssociatedTokenAccount, inAssociatedTokenAccount, amount, slippageBps, swapMode, onlyDirectRoutes, quote, reduceOnly, userAccountPublicKey, }) {
3142
3218
  const outMarket = this.getSpotMarketAccount(outMarketIndex);
3143
3219
  const inMarket = this.getSpotMarketAccount(inMarketIndex);
@@ -34,4 +34,4 @@ export declare function calculateOrderBaseAssetAmount(order: Order, existingBase
34
34
  * - BN size (>=0) if bounded
35
35
  * - null if impossible (target < liabilityWeight) OR imfFactor == 0 (unbounded)
36
36
  */
37
- export declare function maxSizeForTargetLiabilityWeightBN(target: BN, imfFactor: BN, liabilityWeight: BN): BN | null;
37
+ export declare function maxSizeForTargetLiabilityWeightBN(target: BN, imfFactor: BN, liabilityWeight: BN, market: PerpMarketAccount): BN | null;
@@ -277,7 +277,7 @@ exports.calculateOrderBaseAssetAmount = calculateOrderBaseAssetAmount;
277
277
  * - BN size (>=0) if bounded
278
278
  * - null if impossible (target < liabilityWeight) OR imfFactor == 0 (unbounded)
279
279
  */
280
- function maxSizeForTargetLiabilityWeightBN(target, imfFactor, liabilityWeight) {
280
+ function maxSizeForTargetLiabilityWeightBN(target, imfFactor, liabilityWeight, market) {
281
281
  if (target.lt(liabilityWeight))
282
282
  return null;
283
283
  if (imfFactor.isZero())
@@ -307,6 +307,11 @@ function maxSizeForTargetLiabilityWeightBN(target, imfFactor, liabilityWeight) {
307
307
  hi = mid.sub(numericConstants_1.ONE);
308
308
  }
309
309
  }
310
+ // cap at max OI
311
+ const maxOpenInterest = market.amm.maxOpenInterest;
312
+ if (lo.gt(maxOpenInterest)) {
313
+ return maxOpenInterest;
314
+ }
310
315
  return lo;
311
316
  }
312
317
  exports.maxSizeForTargetLiabilityWeightBN = maxSizeForTargetLiabilityWeightBN;
@@ -0,0 +1,86 @@
1
+ /// <reference types="bn.js" />
2
+ import { Connection, PublicKey, TransactionMessage, AddressLookupTableAccount, TransactionInstruction } from '@solana/web3.js';
3
+ import { BN } from '@coral-xyz/anchor';
4
+ export declare enum SwapMode {
5
+ ExactIn = "ExactIn",
6
+ ExactOut = "ExactOut"
7
+ }
8
+ export interface QuoteResponse {
9
+ inputMint: string;
10
+ inAmount: string;
11
+ outputMint: string;
12
+ outAmount: string;
13
+ swapMode: SwapMode;
14
+ slippageBps: number;
15
+ platformFee?: {
16
+ amount?: string;
17
+ feeBps?: number;
18
+ };
19
+ routePlan: Array<{
20
+ swapInfo: any;
21
+ percent: number;
22
+ }>;
23
+ contextSlot?: number;
24
+ timeTaken?: number;
25
+ error?: string;
26
+ errorCode?: string;
27
+ }
28
+ export declare class TitanClient {
29
+ authToken: string;
30
+ url: string;
31
+ connection: Connection;
32
+ constructor({ connection, authToken, url, }: {
33
+ connection: Connection;
34
+ authToken: string;
35
+ url?: string;
36
+ });
37
+ /**
38
+ * Get routes for a swap
39
+ */
40
+ getQuote({ inputMint, outputMint, amount, userPublicKey, maxAccounts, // 50 is an estimated amount with buffer
41
+ slippageBps, swapMode, onlyDirectRoutes, excludeDexes, sizeConstraint, accountsLimitWritable, }: {
42
+ inputMint: PublicKey;
43
+ outputMint: PublicKey;
44
+ amount: BN;
45
+ userPublicKey: PublicKey;
46
+ maxAccounts?: number;
47
+ slippageBps?: number;
48
+ swapMode?: string;
49
+ onlyDirectRoutes?: boolean;
50
+ excludeDexes?: string[];
51
+ sizeConstraint?: number;
52
+ accountsLimitWritable?: number;
53
+ }): Promise<QuoteResponse>;
54
+ /**
55
+ * Get a swap transaction for quote
56
+ */
57
+ getSwap({ inputMint, outputMint, amount, userPublicKey, maxAccounts, // 50 is an estimated amount with buffer
58
+ slippageBps, swapMode, onlyDirectRoutes, excludeDexes, sizeConstraint, accountsLimitWritable, }: {
59
+ inputMint: PublicKey;
60
+ outputMint: PublicKey;
61
+ amount: BN;
62
+ userPublicKey: PublicKey;
63
+ maxAccounts?: number;
64
+ slippageBps?: number;
65
+ swapMode?: SwapMode;
66
+ onlyDirectRoutes?: boolean;
67
+ excludeDexes?: string[];
68
+ sizeConstraint?: number;
69
+ accountsLimitWritable?: number;
70
+ }): Promise<{
71
+ transactionMessage: TransactionMessage;
72
+ lookupTables: AddressLookupTableAccount[];
73
+ }>;
74
+ /**
75
+ * Get the titan instructions from transaction by filtering out instructions to compute budget and associated token programs
76
+ * @param transactionMessage the transaction message
77
+ * @param inputMint the input mint
78
+ * @param outputMint the output mint
79
+ */
80
+ getTitanInstructions({ transactionMessage, inputMint, outputMint, }: {
81
+ transactionMessage: TransactionMessage;
82
+ inputMint: PublicKey;
83
+ outputMint: PublicKey;
84
+ }): TransactionInstruction[];
85
+ private getTransactionMessageAndLookupTables;
86
+ }
@@ -0,0 +1,214 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TitanClient = exports.SwapMode = void 0;
4
+ const web3_js_1 = require("@solana/web3.js");
5
+ const msgpack_1 = require("@msgpack/msgpack");
6
+ var SwapMode;
7
+ (function (SwapMode) {
8
+ SwapMode["ExactIn"] = "ExactIn";
9
+ SwapMode["ExactOut"] = "ExactOut";
10
+ })(SwapMode || (exports.SwapMode = SwapMode = {}));
11
+ const TITAN_API_URL = 'https://api.titan.exchange';
12
+ class TitanClient {
13
+ constructor({ connection, authToken, url, }) {
14
+ this.connection = connection;
15
+ this.authToken = authToken;
16
+ this.url = url !== null && url !== void 0 ? url : TITAN_API_URL;
17
+ }
18
+ /**
19
+ * Get routes for a swap
20
+ */
21
+ async getQuote({ inputMint, outputMint, amount, userPublicKey, maxAccounts = 50, // 50 is an estimated amount with buffer
22
+ slippageBps, swapMode, onlyDirectRoutes, excludeDexes, sizeConstraint, accountsLimitWritable, }) {
23
+ var _a;
24
+ const params = new URLSearchParams({
25
+ inputMint: inputMint.toString(),
26
+ outputMint: outputMint.toString(),
27
+ amount: amount.toString(),
28
+ userPublicKey: userPublicKey.toString(),
29
+ ...(slippageBps && { slippageBps: slippageBps.toString() }),
30
+ ...(swapMode && {
31
+ swapMode: swapMode === 'ExactOut' ? SwapMode.ExactOut : SwapMode.ExactIn,
32
+ }),
33
+ ...(onlyDirectRoutes && {
34
+ onlyDirectRoutes: onlyDirectRoutes.toString(),
35
+ }),
36
+ ...(maxAccounts && { accountsLimitTotal: maxAccounts.toString() }),
37
+ ...(excludeDexes && { excludeDexes: excludeDexes.join(',') }),
38
+ ...(sizeConstraint && { sizeConstraint: sizeConstraint.toString() }),
39
+ ...(accountsLimitWritable && {
40
+ accountsLimitWritable: accountsLimitWritable.toString(),
41
+ }),
42
+ });
43
+ const response = await fetch(`${this.url}/api/v1/quote/swap?${params.toString()}`, {
44
+ headers: {
45
+ Accept: 'application/vnd.msgpack',
46
+ 'Accept-Encoding': 'gzip, deflate, br',
47
+ Authorization: `Bearer ${this.authToken}`,
48
+ },
49
+ });
50
+ if (!response.ok) {
51
+ throw new Error(`Titan API error: ${response.status} ${response.statusText}`);
52
+ }
53
+ const buffer = await response.arrayBuffer();
54
+ const data = (0, msgpack_1.decode)(buffer);
55
+ const route = data.quotes[Object.keys(data.quotes).find((key) => key.toLowerCase() === 'titan') ||
56
+ ''];
57
+ if (!route) {
58
+ throw new Error('No routes available');
59
+ }
60
+ return {
61
+ inputMint: inputMint.toString(),
62
+ inAmount: amount.toString(),
63
+ outputMint: outputMint.toString(),
64
+ outAmount: route.outAmount.toString(),
65
+ swapMode: data.swapMode,
66
+ slippageBps: route.slippageBps,
67
+ platformFee: route.platformFee
68
+ ? {
69
+ amount: route.platformFee.amount.toString(),
70
+ feeBps: route.platformFee.fee_bps,
71
+ }
72
+ : undefined,
73
+ routePlan: ((_a = route.steps) === null || _a === void 0 ? void 0 : _a.map((step) => {
74
+ var _a;
75
+ return ({
76
+ swapInfo: {
77
+ ammKey: new web3_js_1.PublicKey(step.ammKey).toString(),
78
+ label: step.label,
79
+ inputMint: new web3_js_1.PublicKey(step.inputMint).toString(),
80
+ outputMint: new web3_js_1.PublicKey(step.outputMint).toString(),
81
+ inAmount: step.inAmount.toString(),
82
+ outAmount: step.outAmount.toString(),
83
+ feeAmount: ((_a = step.feeAmount) === null || _a === void 0 ? void 0 : _a.toString()) || '0',
84
+ feeMint: step.feeMint ? new web3_js_1.PublicKey(step.feeMint).toString() : '',
85
+ },
86
+ percent: 100,
87
+ });
88
+ })) || [],
89
+ contextSlot: route.contextSlot,
90
+ timeTaken: route.timeTaken,
91
+ };
92
+ }
93
+ /**
94
+ * Get a swap transaction for quote
95
+ */
96
+ async getSwap({ inputMint, outputMint, amount, userPublicKey, maxAccounts = 50, // 50 is an estimated amount with buffer
97
+ slippageBps, swapMode, onlyDirectRoutes, excludeDexes, sizeConstraint, accountsLimitWritable, }) {
98
+ const params = new URLSearchParams({
99
+ inputMint: inputMint.toString(),
100
+ outputMint: outputMint.toString(),
101
+ amount: amount.toString(),
102
+ userPublicKey: userPublicKey.toString(),
103
+ ...(slippageBps && { slippageBps: slippageBps.toString() }),
104
+ ...(swapMode && { swapMode: swapMode }),
105
+ ...(maxAccounts && { accountsLimitTotal: maxAccounts.toString() }),
106
+ ...(excludeDexes && { excludeDexes: excludeDexes.join(',') }),
107
+ ...(onlyDirectRoutes && {
108
+ onlyDirectRoutes: onlyDirectRoutes.toString(),
109
+ }),
110
+ ...(sizeConstraint && { sizeConstraint: sizeConstraint.toString() }),
111
+ ...(accountsLimitWritable && {
112
+ accountsLimitWritable: accountsLimitWritable.toString(),
113
+ }),
114
+ });
115
+ const response = await fetch(`${this.url}/api/v1/quote/swap?${params.toString()}`, {
116
+ headers: {
117
+ Accept: 'application/vnd.msgpack',
118
+ 'Accept-Encoding': 'gzip, deflate, br',
119
+ Authorization: `Bearer ${this.authToken}`,
120
+ },
121
+ });
122
+ if (!response.ok) {
123
+ if (response.status === 404) {
124
+ throw new Error('No routes available');
125
+ }
126
+ throw new Error(`Titan API error: ${response.status} ${response.statusText}`);
127
+ }
128
+ const buffer = await response.arrayBuffer();
129
+ const data = (0, msgpack_1.decode)(buffer);
130
+ const route = data.quotes[Object.keys(data.quotes).find((key) => key.toLowerCase() === 'titan') ||
131
+ ''];
132
+ if (!route) {
133
+ throw new Error('No routes available');
134
+ }
135
+ if (route.instructions && route.instructions.length > 0) {
136
+ try {
137
+ const { transactionMessage, lookupTables } = await this.getTransactionMessageAndLookupTables(route, userPublicKey);
138
+ return { transactionMessage, lookupTables };
139
+ }
140
+ catch (err) {
141
+ throw new Error('Something went wrong with creating the Titan swap transaction. Please try again.');
142
+ }
143
+ }
144
+ throw new Error('No instructions provided in the route');
145
+ }
146
+ /**
147
+ * Get the titan instructions from transaction by filtering out instructions to compute budget and associated token programs
148
+ * @param transactionMessage the transaction message
149
+ * @param inputMint the input mint
150
+ * @param outputMint the output mint
151
+ */
152
+ getTitanInstructions({ transactionMessage, inputMint, outputMint, }) {
153
+ // Filter out common system instructions that can be handled by DriftClient
154
+ const filteredInstructions = transactionMessage.instructions.filter((instruction) => {
155
+ const programId = instruction.programId.toString();
156
+ // Filter out system programs
157
+ if (programId === 'ComputeBudget111111111111111111111111111111') {
158
+ return false;
159
+ }
160
+ if (programId === 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA') {
161
+ return false;
162
+ }
163
+ if (programId === '11111111111111111111111111111111') {
164
+ return false;
165
+ }
166
+ // Filter out Associated Token Account creation for input/output mints
167
+ if (programId === 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL') {
168
+ if (instruction.keys.length > 3) {
169
+ const mint = instruction.keys[3].pubkey;
170
+ if (mint.equals(inputMint) || mint.equals(outputMint)) {
171
+ return false;
172
+ }
173
+ }
174
+ }
175
+ return true;
176
+ });
177
+ return filteredInstructions;
178
+ }
179
+ async getTransactionMessageAndLookupTables(route, userPublicKey) {
180
+ const solanaInstructions = route.instructions.map((instruction) => ({
181
+ programId: new web3_js_1.PublicKey(instruction.p),
182
+ keys: instruction.a.map((meta) => ({
183
+ pubkey: new web3_js_1.PublicKey(meta.p),
184
+ isSigner: meta.s,
185
+ isWritable: meta.w,
186
+ })),
187
+ data: Buffer.from(instruction.d),
188
+ }));
189
+ // Get recent blockhash
190
+ const { blockhash } = await this.connection.getLatestBlockhash();
191
+ // Build address lookup tables if provided
192
+ const addressLookupTables = [];
193
+ if (route.addressLookupTables && route.addressLookupTables.length > 0) {
194
+ for (const altPubkey of route.addressLookupTables) {
195
+ try {
196
+ const altAccount = await this.connection.getAddressLookupTable(new web3_js_1.PublicKey(altPubkey));
197
+ if (altAccount.value) {
198
+ addressLookupTables.push(altAccount.value);
199
+ }
200
+ }
201
+ catch (err) {
202
+ console.warn(`Failed to fetch address lookup table:`, err);
203
+ }
204
+ }
205
+ }
206
+ const transactionMessage = new web3_js_1.TransactionMessage({
207
+ payerKey: userPublicKey,
208
+ recentBlockhash: blockhash,
209
+ instructions: solanaInstructions,
210
+ });
211
+ return { transactionMessage, lookupTables: addressLookupTables };
212
+ }
213
+ }
214
+ exports.TitanClient = TitanClient;
@@ -1 +1 @@
1
- {"version":3,"file":"grpcDriftClientAccountSubscriberV2.d.ts","sourceRoot":"","sources":["../../../src/accounts/grpcDriftClientAccountSubscriberV2.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"grpcDriftClientAccountSubscriberV2.d.ts","sourceRoot":"","sources":["../../../src/accounts/grpcDriftClientAccountSubscriberV2.ts"],"names":[],"mappings":"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"}
@@ -413,18 +413,6 @@ class grpcDriftClientAccountSubscriberV2 {
413
413
  // Remove accounts in batches - perp markets
414
414
  if (perpMarketPubkeysToRemove.length > 0) {
415
415
  await this.perpMarketsSubscriber.removeAccounts(perpMarketPubkeysToRemove);
416
- // Clean up the mapping for removed perp markets
417
- for (const pubkey of perpMarketPubkeysToRemove) {
418
- const pubkeyString = pubkey.toBase58();
419
- for (const [marketIndex, accountPubkey,] of this.perpMarketIndexToAccountPubkeyMap.entries()) {
420
- if (accountPubkey === pubkeyString) {
421
- this.perpMarketIndexToAccountPubkeyMap.delete(marketIndex);
422
- this.perpOracleMap.delete(marketIndex);
423
- this.perpOracleStringMap.delete(marketIndex);
424
- break;
425
- }
426
- }
427
- }
428
416
  }
429
417
  // Remove accounts in batches - oracles
430
418
  if (oraclePubkeysToRemove.length > 0) {