@drift-labs/sdk 2.144.0-beta.6 → 2.145.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UnifiedSwapClient = void 0;
4
+ const web3_js_1 = require("@solana/web3.js");
5
+ const anchor_1 = require("@coral-xyz/anchor");
6
+ const jupiterClient_1 = require("../jupiter/jupiterClient");
7
+ const titanClient_1 = require("../titan/titanClient");
8
+ class UnifiedSwapClient {
9
+ constructor({ clientType, connection, authToken, url, }) {
10
+ this.clientType = clientType;
11
+ if (clientType === 'jupiter') {
12
+ this.client = new jupiterClient_1.JupiterClient({
13
+ connection,
14
+ url,
15
+ });
16
+ }
17
+ else if (clientType === 'titan') {
18
+ if (!authToken) {
19
+ throw new Error('authToken is required for Titan client');
20
+ }
21
+ this.client = new titanClient_1.TitanClient({
22
+ connection,
23
+ authToken,
24
+ url,
25
+ });
26
+ }
27
+ else {
28
+ throw new Error(`Unsupported client type: ${clientType}`);
29
+ }
30
+ }
31
+ /**
32
+ * Get a swap quote from the underlying client
33
+ */
34
+ async getQuote(params) {
35
+ if (this.clientType === 'jupiter') {
36
+ const jupiterClient = this.client;
37
+ const { userPublicKey: _userPublicKey, // Not needed for Jupiter
38
+ sizeConstraint: _sizeConstraint, // Jupiter-specific params to exclude
39
+ accountsLimitWritable: _accountsLimitWritable, ...jupiterParams } = params;
40
+ return await jupiterClient.getQuote(jupiterParams);
41
+ }
42
+ else {
43
+ const titanClient = this.client;
44
+ const { autoSlippage: _autoSlippage, // Titan-specific params to exclude
45
+ maxAutoSlippageBps: _maxAutoSlippageBps, usdEstimate: _usdEstimate, ...titanParams } = params;
46
+ if (!titanParams.userPublicKey) {
47
+ throw new Error('userPublicKey is required for Titan quotes');
48
+ }
49
+ // Cast to ensure TypeScript knows userPublicKey is defined
50
+ const titanParamsWithUser = {
51
+ ...titanParams,
52
+ userPublicKey: titanParams.userPublicKey,
53
+ swapMode: titanParams.swapMode, // Titan expects string
54
+ };
55
+ return await titanClient.getQuote(titanParamsWithUser);
56
+ }
57
+ }
58
+ /**
59
+ * Get a swap transaction from the underlying client
60
+ */
61
+ async getSwap(params) {
62
+ if (this.clientType === 'jupiter') {
63
+ const jupiterClient = this.client;
64
+ // Cast the quote to Jupiter's QuoteResponse type
65
+ const jupiterParams = {
66
+ ...params,
67
+ quote: params.quote,
68
+ };
69
+ const transaction = await jupiterClient.getSwap(jupiterParams);
70
+ return { transaction };
71
+ }
72
+ else {
73
+ const titanClient = this.client;
74
+ const { quote, userPublicKey, slippageBps } = params;
75
+ // For Titan, we need to reconstruct the parameters from the quote
76
+ const titanQuote = quote;
77
+ const result = await titanClient.getSwap({
78
+ inputMint: new web3_js_1.PublicKey(titanQuote.inputMint),
79
+ outputMint: new web3_js_1.PublicKey(titanQuote.outputMint),
80
+ amount: new anchor_1.BN(titanQuote.inAmount),
81
+ userPublicKey,
82
+ slippageBps: slippageBps || titanQuote.slippageBps,
83
+ swapMode: titanQuote.swapMode,
84
+ });
85
+ return {
86
+ transactionMessage: result.transactionMessage,
87
+ lookupTables: result.lookupTables,
88
+ };
89
+ }
90
+ }
91
+ /**
92
+ * Get swap instructions from the underlying client (Jupiter or Titan)
93
+ * This is the core swap logic without any context preparation
94
+ */
95
+ async getSwapInstructions({ inputMint, outputMint, amount, userPublicKey, slippageBps, swapMode = 'ExactIn', onlyDirectRoutes = false, quote, sizeConstraint, }) {
96
+ const isExactOut = swapMode === 'ExactOut';
97
+ let swapInstructions;
98
+ let lookupTables;
99
+ if (this.clientType === 'jupiter') {
100
+ const jupiterClient = this.client;
101
+ // Get quote if not provided
102
+ let finalQuote = quote;
103
+ if (!finalQuote) {
104
+ finalQuote = await jupiterClient.getQuote({
105
+ inputMint,
106
+ outputMint,
107
+ amount,
108
+ slippageBps,
109
+ swapMode,
110
+ onlyDirectRoutes,
111
+ });
112
+ }
113
+ if (!finalQuote) {
114
+ throw new Error("Could not fetch Jupiter's quote. Please try again.");
115
+ }
116
+ // Get swap transaction and extract instructions
117
+ const transaction = await jupiterClient.getSwap({
118
+ quote: finalQuote,
119
+ userPublicKey,
120
+ slippageBps,
121
+ });
122
+ const { transactionMessage, lookupTables: jupiterLookupTables } = await jupiterClient.getTransactionMessageAndLookupTables({
123
+ transaction,
124
+ });
125
+ swapInstructions = jupiterClient.getJupiterInstructions({
126
+ transactionMessage,
127
+ inputMint,
128
+ outputMint,
129
+ });
130
+ lookupTables = jupiterLookupTables;
131
+ }
132
+ else {
133
+ const titanClient = this.client;
134
+ // For Titan, get swap directly (it handles quote internally)
135
+ const { transactionMessage, lookupTables: titanLookupTables } = await titanClient.getSwap({
136
+ inputMint,
137
+ outputMint,
138
+ amount,
139
+ userPublicKey,
140
+ slippageBps,
141
+ swapMode: isExactOut ? titanClient_1.SwapMode.ExactOut : titanClient_1.SwapMode.ExactIn,
142
+ onlyDirectRoutes,
143
+ sizeConstraint: sizeConstraint || 1280 - 375, // MAX_TX_BYTE_SIZE - buffer for drift instructions
144
+ });
145
+ swapInstructions = titanClient.getTitanInstructions({
146
+ transactionMessage,
147
+ inputMint,
148
+ outputMint,
149
+ });
150
+ lookupTables = titanLookupTables;
151
+ }
152
+ return { instructions: swapInstructions, lookupTables };
153
+ }
154
+ /**
155
+ * Get the underlying client instance
156
+ */
157
+ getClient() {
158
+ return this.client;
159
+ }
160
+ /**
161
+ * Get the client type
162
+ */
163
+ getClientType() {
164
+ return this.clientType;
165
+ }
166
+ /**
167
+ * Check if this is a Jupiter client
168
+ */
169
+ isJupiter() {
170
+ return this.clientType === 'jupiter';
171
+ }
172
+ /**
173
+ * Check if this is a Titan client
174
+ */
175
+ isTitan() {
176
+ return this.clientType === 'titan';
177
+ }
178
+ }
179
+ exports.UnifiedSwapClient = UnifiedSwapClient;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.144.0-beta.6",
3
+ "version": "2.145.0-beta.1",
4
4
  "main": "lib/node/index.js",
5
5
  "types": "lib/node/index.d.ts",
6
6
  "module": "./lib/browser/index.js",
@@ -157,11 +157,8 @@ import { isSpotPositionAvailable } from './math/spotPosition';
157
157
  import { calculateMarketMaxAvailableInsurance } from './math/market';
158
158
  import { fetchUserStatsAccount } from './accounts/fetch';
159
159
  import { castNumberToSpotPrecision } from './math/spotMarket';
160
- import {
161
- JupiterClient,
162
- QuoteResponse,
163
- SwapMode,
164
- } from './jupiter/jupiterClient';
160
+ import { JupiterClient, QuoteResponse } from './jupiter/jupiterClient';
161
+ import { SwapMode } from './swap/UnifiedSwapClient';
165
162
  import { getNonIdleUserFilter } from './memcmp';
166
163
  import { UserStatsSubscriptionConfig } from './userStatsConfig';
167
164
  import { getMarinadeDepositIx, getMarinadeFinanceProgram } from './marinade';
@@ -210,9 +207,11 @@ import {
210
207
  isBuilderOrderCompleted,
211
208
  } from './math/builder';
212
209
  import { TitanClient, SwapMode as TitanSwapMode } from './titan/titanClient';
210
+ import { UnifiedSwapClient } from './swap/UnifiedSwapClient';
213
211
 
214
212
  /**
215
- * Union type for swap clients (Titan and Jupiter)
213
+ * Union type for swap clients (Titan and Jupiter) - Legacy type
214
+ * @deprecated Use UnifiedSwapClient class instead
216
215
  */
217
216
  export type SwapClient = TitanClient | JupiterClient;
218
217
 
@@ -5772,7 +5771,7 @@ export class DriftClient {
5772
5771
  quote,
5773
5772
  onlyDirectRoutes = false,
5774
5773
  }: {
5775
- swapClient: SwapClient;
5774
+ swapClient: UnifiedSwapClient | SwapClient;
5776
5775
  outMarketIndex: number;
5777
5776
  inMarketIndex: number;
5778
5777
  outAssociatedTokenAccount?: PublicKey;
@@ -5793,7 +5792,23 @@ export class DriftClient {
5793
5792
  lookupTables: AddressLookupTableAccount[];
5794
5793
  };
5795
5794
 
5796
- if (swapClient instanceof TitanClient) {
5795
+ // Use unified SwapClient if available
5796
+ if (swapClient instanceof UnifiedSwapClient) {
5797
+ res = await this.getSwapIxV2({
5798
+ swapClient,
5799
+ outMarketIndex,
5800
+ inMarketIndex,
5801
+ outAssociatedTokenAccount,
5802
+ inAssociatedTokenAccount,
5803
+ amount,
5804
+ slippageBps,
5805
+ swapMode,
5806
+ onlyDirectRoutes,
5807
+ reduceOnly,
5808
+ quote,
5809
+ v6,
5810
+ });
5811
+ } else if (swapClient instanceof TitanClient) {
5797
5812
  res = await this.getTitanSwapIx({
5798
5813
  titanClient: swapClient,
5799
5814
  outMarketIndex,
@@ -5823,7 +5838,7 @@ export class DriftClient {
5823
5838
  });
5824
5839
  } else {
5825
5840
  throw new Error(
5826
- 'Invalid swap client type. Must be TitanClient or JupiterClient.'
5841
+ 'Invalid swap client type. Must be SwapClient, TitanClient, or JupiterClient.'
5827
5842
  );
5828
5843
  }
5829
5844
 
@@ -6243,6 +6258,134 @@ export class DriftClient {
6243
6258
  return { beginSwapIx, endSwapIx };
6244
6259
  }
6245
6260
 
6261
+ public async getSwapIxV2({
6262
+ swapClient,
6263
+ outMarketIndex,
6264
+ inMarketIndex,
6265
+ outAssociatedTokenAccount,
6266
+ inAssociatedTokenAccount,
6267
+ amount,
6268
+ slippageBps,
6269
+ swapMode,
6270
+ onlyDirectRoutes,
6271
+ reduceOnly,
6272
+ quote,
6273
+ v6,
6274
+ }: {
6275
+ swapClient: UnifiedSwapClient;
6276
+ outMarketIndex: number;
6277
+ inMarketIndex: number;
6278
+ outAssociatedTokenAccount?: PublicKey;
6279
+ inAssociatedTokenAccount?: PublicKey;
6280
+ amount: BN;
6281
+ slippageBps?: number;
6282
+ swapMode?: SwapMode;
6283
+ onlyDirectRoutes?: boolean;
6284
+ reduceOnly?: SwapReduceOnly;
6285
+ quote?: QuoteResponse;
6286
+ v6?: {
6287
+ quote?: QuoteResponse;
6288
+ };
6289
+ }): Promise<{
6290
+ ixs: TransactionInstruction[];
6291
+ lookupTables: AddressLookupTableAccount[];
6292
+ }> {
6293
+ // Get market accounts to determine mints
6294
+ const outMarket = this.getSpotMarketAccount(outMarketIndex);
6295
+ const inMarket = this.getSpotMarketAccount(inMarketIndex);
6296
+
6297
+ const isExactOut = swapMode === 'ExactOut';
6298
+ const exactOutBufferedAmountIn = amount.muln(1001).divn(1000); // Add 10bp buffer
6299
+
6300
+ const preInstructions: TransactionInstruction[] = [];
6301
+
6302
+ // Handle token accounts if not provided
6303
+ let finalOutAssociatedTokenAccount = outAssociatedTokenAccount;
6304
+ let finalInAssociatedTokenAccount = inAssociatedTokenAccount;
6305
+
6306
+ if (!finalOutAssociatedTokenAccount) {
6307
+ const tokenProgram = this.getTokenProgramForSpotMarket(outMarket);
6308
+ finalOutAssociatedTokenAccount = await this.getAssociatedTokenAccount(
6309
+ outMarket.marketIndex,
6310
+ false,
6311
+ tokenProgram
6312
+ );
6313
+
6314
+ const accountInfo = await this.connection.getAccountInfo(
6315
+ finalOutAssociatedTokenAccount
6316
+ );
6317
+ if (!accountInfo) {
6318
+ preInstructions.push(
6319
+ this.createAssociatedTokenAccountIdempotentInstruction(
6320
+ finalOutAssociatedTokenAccount,
6321
+ this.provider.wallet.publicKey,
6322
+ this.provider.wallet.publicKey,
6323
+ outMarket.mint,
6324
+ tokenProgram
6325
+ )
6326
+ );
6327
+ }
6328
+ }
6329
+
6330
+ if (!finalInAssociatedTokenAccount) {
6331
+ const tokenProgram = this.getTokenProgramForSpotMarket(inMarket);
6332
+ finalInAssociatedTokenAccount = await this.getAssociatedTokenAccount(
6333
+ inMarket.marketIndex,
6334
+ false,
6335
+ tokenProgram
6336
+ );
6337
+
6338
+ const accountInfo = await this.connection.getAccountInfo(
6339
+ finalInAssociatedTokenAccount
6340
+ );
6341
+ if (!accountInfo) {
6342
+ preInstructions.push(
6343
+ this.createAssociatedTokenAccountIdempotentInstruction(
6344
+ finalInAssociatedTokenAccount,
6345
+ this.provider.wallet.publicKey,
6346
+ this.provider.wallet.publicKey,
6347
+ inMarket.mint,
6348
+ tokenProgram
6349
+ )
6350
+ );
6351
+ }
6352
+ }
6353
+
6354
+ // Get drift swap instructions for begin and end
6355
+ const { beginSwapIx, endSwapIx } = await this.getSwapIx({
6356
+ outMarketIndex,
6357
+ inMarketIndex,
6358
+ amountIn: isExactOut ? exactOutBufferedAmountIn : amount,
6359
+ inTokenAccount: finalInAssociatedTokenAccount,
6360
+ outTokenAccount: finalOutAssociatedTokenAccount,
6361
+ reduceOnly,
6362
+ });
6363
+
6364
+ // Get core swap instructions from SwapClient
6365
+ const swapResult = await swapClient.getSwapInstructions({
6366
+ inputMint: inMarket.mint,
6367
+ outputMint: outMarket.mint,
6368
+ amount,
6369
+ userPublicKey: this.provider.wallet.publicKey,
6370
+ slippageBps,
6371
+ swapMode,
6372
+ onlyDirectRoutes,
6373
+ quote: quote ?? v6?.quote,
6374
+ });
6375
+
6376
+ const allInstructions = [
6377
+ ...preInstructions,
6378
+ beginSwapIx,
6379
+ ...swapResult.instructions,
6380
+ endSwapIx,
6381
+ ];
6382
+
6383
+ return {
6384
+ ixs: allInstructions,
6385
+ lookupTables: swapResult.lookupTables,
6386
+ };
6387
+ }
6388
+
6246
6389
  public async stakeForMSOL({ amount }: { amount: BN }): Promise<TxSigAndSlot> {
6247
6390
  const ixs = await this.getStakeForMSOLIx({ amount });
6248
6391
  const tx = await this.buildTransaction(ixs);
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.143.0",
2
+ "version": "2.144.0",
3
3
  "name": "drift",
4
4
  "instructions": [
5
5
  {
package/src/index.ts CHANGED
@@ -53,7 +53,8 @@ export * from './events/webSocketLogProvider';
53
53
  export * from './events/parse';
54
54
  export * from './events/pollingLogProvider';
55
55
  export * from './jupiter/jupiterClient';
56
- export { TitanClient } from './titan/titanClient';
56
+ // Primary swap client interface - use this for all swap operations
57
+ export * from './swap/UnifiedSwapClient';
57
58
  export * from './math/auction';
58
59
  export * from './math/builder';
59
60
  export * from './math/spotMarket';
@@ -8,8 +8,7 @@ import {
8
8
  } from '@solana/web3.js';
9
9
  import fetch from 'node-fetch';
10
10
  import { BN } from '@coral-xyz/anchor';
11
-
12
- export type SwapMode = 'ExactIn' | 'ExactOut';
11
+ import { SwapMode } from '../swap/UnifiedSwapClient';
13
12
 
14
13
  export interface MarketInfo {
15
14
  id: string;