Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 152 additions & 9 deletions sdk/src/driftClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,8 @@ import { isSpotPositionAvailable } from './math/spotPosition';
import { calculateMarketMaxAvailableInsurance } from './math/market';
import { fetchUserStatsAccount } from './accounts/fetch';
import { castNumberToSpotPrecision } from './math/spotMarket';
import {
JupiterClient,
QuoteResponse,
SwapMode,
} from './jupiter/jupiterClient';
import { JupiterClient, QuoteResponse } from './jupiter/jupiterClient';
import { SwapMode } from './swap/UnifiedSwapClient';
import { getNonIdleUserFilter } from './memcmp';
import { UserStatsSubscriptionConfig } from './userStatsConfig';
import { getMarinadeDepositIx, getMarinadeFinanceProgram } from './marinade';
Expand Down Expand Up @@ -210,9 +207,11 @@ import {
isBuilderOrderCompleted,
} from './math/builder';
import { TitanClient, SwapMode as TitanSwapMode } from './titan/titanClient';
import { UnifiedSwapClient } from './swap/UnifiedSwapClient';

/**
* Union type for swap clients (Titan and Jupiter)
* Union type for swap clients (Titan and Jupiter) - Legacy type
* @deprecated Use UnifiedSwapClient class instead
*/
export type SwapClient = TitanClient | JupiterClient;

Expand Down Expand Up @@ -5772,7 +5771,7 @@ export class DriftClient {
quote,
onlyDirectRoutes = false,
}: {
swapClient: SwapClient;
swapClient: UnifiedSwapClient | SwapClient;
outMarketIndex: number;
inMarketIndex: number;
outAssociatedTokenAccount?: PublicKey;
Expand All @@ -5793,7 +5792,23 @@ export class DriftClient {
lookupTables: AddressLookupTableAccount[];
};

if (swapClient instanceof TitanClient) {
// Use unified SwapClient if available
if (swapClient instanceof UnifiedSwapClient) {
res = await this.getSwapIxV2({
swapClient,
outMarketIndex,
inMarketIndex,
outAssociatedTokenAccount,
inAssociatedTokenAccount,
amount,
slippageBps,
swapMode,
onlyDirectRoutes,
reduceOnly,
quote,
v6,
});
} else if (swapClient instanceof TitanClient) {
res = await this.getTitanSwapIx({
titanClient: swapClient,
outMarketIndex,
Expand Down Expand Up @@ -5823,7 +5838,7 @@ export class DriftClient {
});
} else {
throw new Error(
'Invalid swap client type. Must be TitanClient or JupiterClient.'
'Invalid swap client type. Must be SwapClient, TitanClient, or JupiterClient.'
);
}

Expand Down Expand Up @@ -6243,6 +6258,134 @@ export class DriftClient {
return { beginSwapIx, endSwapIx };
}

public async getSwapIxV2({
swapClient,
outMarketIndex,
inMarketIndex,
outAssociatedTokenAccount,
inAssociatedTokenAccount,
amount,
slippageBps,
swapMode,
onlyDirectRoutes,
reduceOnly,
quote,
v6,
}: {
swapClient: UnifiedSwapClient;
outMarketIndex: number;
inMarketIndex: number;
outAssociatedTokenAccount?: PublicKey;
inAssociatedTokenAccount?: PublicKey;
amount: BN;
slippageBps?: number;
swapMode?: SwapMode;
onlyDirectRoutes?: boolean;
reduceOnly?: SwapReduceOnly;
quote?: QuoteResponse;
v6?: {
quote?: QuoteResponse;
};
}): Promise<{
ixs: TransactionInstruction[];
lookupTables: AddressLookupTableAccount[];
}> {
// Get market accounts to determine mints
const outMarket = this.getSpotMarketAccount(outMarketIndex);
const inMarket = this.getSpotMarketAccount(inMarketIndex);

const isExactOut = swapMode === 'ExactOut';
const exactOutBufferedAmountIn = amount.muln(1001).divn(1000); // Add 10bp buffer

const preInstructions: TransactionInstruction[] = [];

// Handle token accounts if not provided
let finalOutAssociatedTokenAccount = outAssociatedTokenAccount;
let finalInAssociatedTokenAccount = inAssociatedTokenAccount;

if (!finalOutAssociatedTokenAccount) {
const tokenProgram = this.getTokenProgramForSpotMarket(outMarket);
finalOutAssociatedTokenAccount = await this.getAssociatedTokenAccount(
outMarket.marketIndex,
false,
tokenProgram
);

const accountInfo = await this.connection.getAccountInfo(
finalOutAssociatedTokenAccount
);
if (!accountInfo) {
preInstructions.push(
this.createAssociatedTokenAccountIdempotentInstruction(
finalOutAssociatedTokenAccount,
this.provider.wallet.publicKey,
this.provider.wallet.publicKey,
outMarket.mint,
tokenProgram
)
);
}
}

if (!finalInAssociatedTokenAccount) {
const tokenProgram = this.getTokenProgramForSpotMarket(inMarket);
finalInAssociatedTokenAccount = await this.getAssociatedTokenAccount(
inMarket.marketIndex,
false,
tokenProgram
);

const accountInfo = await this.connection.getAccountInfo(
finalInAssociatedTokenAccount
);
if (!accountInfo) {
preInstructions.push(
this.createAssociatedTokenAccountIdempotentInstruction(
finalInAssociatedTokenAccount,
this.provider.wallet.publicKey,
this.provider.wallet.publicKey,
inMarket.mint,
tokenProgram
)
);
}
}

// Get drift swap instructions for begin and end
const { beginSwapIx, endSwapIx } = await this.getSwapIx({
outMarketIndex,
inMarketIndex,
amountIn: isExactOut ? exactOutBufferedAmountIn : amount,
inTokenAccount: finalInAssociatedTokenAccount,
outTokenAccount: finalOutAssociatedTokenAccount,
reduceOnly,
});

// Get core swap instructions from SwapClient
const swapResult = await swapClient.getSwapInstructions({
inputMint: inMarket.mint,
outputMint: outMarket.mint,
amount,
userPublicKey: this.provider.wallet.publicKey,
slippageBps,
swapMode,
onlyDirectRoutes,
quote: quote ?? v6?.quote,
});

const allInstructions = [
...preInstructions,
beginSwapIx,
...swapResult.instructions,
endSwapIx,
];

return {
ixs: allInstructions,
lookupTables: swapResult.lookupTables,
};
}

public async stakeForMSOL({ amount }: { amount: BN }): Promise<TxSigAndSlot> {
const ixs = await this.getStakeForMSOLIx({ amount });
const tx = await this.buildTransaction(ixs);
Expand Down
3 changes: 2 additions & 1 deletion sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ export * from './events/webSocketLogProvider';
export * from './events/parse';
export * from './events/pollingLogProvider';
export * from './jupiter/jupiterClient';
export { TitanClient } from './titan/titanClient';
// Primary swap client interface - use this for all swap operations
export * from './swap/UnifiedSwapClient';
export * from './math/auction';
export * from './math/builder';
export * from './math/spotMarket';
Expand Down
3 changes: 1 addition & 2 deletions sdk/src/jupiter/jupiterClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import {
} from '@solana/web3.js';
import fetch from 'node-fetch';
import { BN } from '@coral-xyz/anchor';

export type SwapMode = 'ExactIn' | 'ExactOut';
import { SwapMode } from '../swap/UnifiedSwapClient';

export interface MarketInfo {
id: string;
Expand Down
Loading
Loading