UNPKG

test-raydium-sdk-v2

Version:

An SDK for building applications on top of Raydium.

803 lines (765 loc) 29.3 kB
import { PublicKey, TransactionInstruction } from "@solana/web3.js"; import { createTransferInstruction } from "@solana/spl-token"; import { forecastTransactionSize, solToWSol, TxBuilder, BN_ZERO, SOLMint, WSOLMint, addComputeBudget } from "@/common"; import { Token } from "@/module"; import { StableLayout } from "../liquidity/stable"; import ModuleBase, { ModuleBaseProps } from "../moduleBase"; import { ComputeAmountOutLayout, ComputeAmountOutRouteLayout, PoolAccountInfoV4, ReturnTypeGetAddLiquidityDefaultPool, } from "./type"; import { makeSwapInstruction } from "./instrument"; import { MakeMultiTransaction, MakeTransaction } from "../type"; import { InstructionType } from "@/common/txTool/txType"; import { BigNumberish, parseBigNumberish } from "@/common/bignumber"; import { createWSolAccountInstructions, closeAccountInstruction, makeTransferInstruction, } from "../account/instruction"; import { TokenAccount } from "../account/types"; import { ComputeBudgetConfig } from "@/raydium/type"; type LiquidityPoolJsonInfo = any; export default class TradeV2 extends ModuleBase { constructor(params: ModuleBaseProps) { super(params); } static getAddLiquidityDefaultPool({ addLiquidityPools, poolInfosCache, }: { addLiquidityPools: LiquidityPoolJsonInfo[]; poolInfosCache: { [ammId: string]: PoolAccountInfoV4 }; }): ReturnTypeGetAddLiquidityDefaultPool { if (addLiquidityPools.length === 0) return undefined; if (addLiquidityPools.length === 1) return addLiquidityPools[0]; addLiquidityPools.sort((a, b) => b.version - a.version); if (addLiquidityPools[0].version !== addLiquidityPools[1].version) return addLiquidityPools[0]; const _addLiquidityPools = addLiquidityPools.filter((i) => i.version === addLiquidityPools[0].version); _addLiquidityPools.sort((a, b) => this.comparePoolSize(a, b, poolInfosCache)); return _addLiquidityPools[0]; } private static comparePoolSize( a: LiquidityPoolJsonInfo, b: LiquidityPoolJsonInfo, ammIdToPoolInfo: { [ammId: string]: PoolAccountInfoV4 }, ): number { const aInfo = ammIdToPoolInfo[a.id]; const bInfo = ammIdToPoolInfo[b.id]; if (aInfo === undefined) return 1; if (bInfo === undefined) return -1; if (a.baseMint === b.baseMint) { const sub = aInfo.baseReserve.sub(bInfo.baseReserve); return sub.gte(BN_ZERO) ? -1 : 1; } else { const sub = aInfo.baseReserve.sub(bInfo.quoteReserve); return sub.gte(BN_ZERO) ? -1 : 1; } } // public async getAllRouteComputeAmountOut({ // inputTokenAmount, // outputToken: orgOut, // directPath, // routePathDict, // simulateCache, // tickCache, // slippage, // chainTime, // feeConfig, // mintInfos, // }: { // directPath: PoolType[]; // routePathDict: RoutePathType; // simulateCache: ReturnTypeFetchMultipleInfo; // tickCache: ReturnTypeFetchMultiplePoolTickArrays; // inputTokenAmount: TokenAmount; // outputToken: Token; // slippage: Percent; // chainTime: number; // feeConfig?: { // feeBps: BN; // feeAccount: PublicKey; // }; // mintInfos: ReturnTypeFetchMultipleMintInfos; // }): Promise<{ // routes: ComputeAmountOutLayout[]; // best?: ComputeAmountOutLayout; // }> { // const epochInfo = await this.scope.fetchEpochInfo(); // const input = this.scope.solToWsolTokenAmount(inputTokenAmount); // const _amountIn = // feeConfig === undefined ? BN_ZERO : input.raw.mul(new BN(10000 - feeConfig.feeBps.toNumber())).div(new BN(10000)); // const amountIn = feeConfig === undefined ? input : new TokenAmount(input.token, _amountIn, true); // const _inFeeConfig = // feeConfig === undefined // ? undefined // : { // feeAmount: _amountIn, // feeAccount: feeConfig.feeAccount, // }; // const outputToken = this.scope.mintToToken(solToWSol(orgOut.mint)); // const outRoute: ComputeAmountOutLayout[] = []; // for (const itemPool of directPath) { // if (itemPool.version === 6) { // try { // const { // realAmountIn, // amountOut, // minAmountOut, // expirationTime, // currentPrice, // executionPrice, // priceImpact, // fee, // remainingAccounts, // } = await PoolUtils.computeAmountOutFormat({ // poolInfo: itemPool as ClmmPoolInfo, // tickArrayCache: tickCache[itemPool.id.toString()], // amountIn, // tokenOut: outputToken, // slippage, // token2022Infos: mintInfos, // epochInfo, // }); // outRoute.push({ // amountIn: realAmountIn, // amountOut, // minAmountOut, // currentPrice, // executionPrice, // priceImpact, // fee: [fee], // remainingAccounts: [remainingAccounts], // routeType: "amm", // poolKey: [itemPool], // poolReady: (itemPool as ClmmPoolInfo).startTime < chainTime, // poolType: "CLMM", // feeConfig: _inFeeConfig, // expirationTime: minExpirationTime(realAmountIn.expirationTime, expirationTime), // }); // } catch (e) { // // // } // } else { // try { // if (![1, 6, 7].includes(simulateCache[itemPool.id as string].status.toNumber())) continue; // // const { amountOut, minAmountOut, currentPrice, executionPrice, priceImpact, fee } = // // this.scope.liquidity.computeAmountOut({ // // poolKeys: jsonInfo2PoolKeys(itemPool) as LiquidityPoolKeys, // // poolInfo: simulateCache[itemPool.id as string], // // amountIn, // // outputToken, // // slippage, // // }); // // outRoute.push({ // // amountIn: { amount: amountIn, fee: undefined, expirationTime: undefined }, // // amountOut: { amount: amountOut, fee: undefined, expirationTime: undefined }, // // minAmountOut: { amount: minAmountOut, fee: undefined, expirationTime: undefined }, // // currentPrice, // // executionPrice, // // priceImpact, // // fee: [fee], // // routeType: "amm", // // poolKey: [itemPool], // // remainingAccounts: [], // // poolReady: simulateCache[itemPool.id as string].startTime.toNumber() < chainTime, // // poolType: itemPool.version === 5 ? "STABLE" : undefined, // // feeConfig: _inFeeConfig, // // expirationTime: undefined, // // }); // } catch (e) { // // // } // } // } // for (const [routeMint, info] of Object.entries(routePathDict)) { // for (const iFromPool of info.in) { // if (!simulateCache[iFromPool.id as string] && !tickCache[iFromPool.id.toString()]) continue; // if (iFromPool.version !== 6 && ![1, 6, 7].includes(simulateCache[iFromPool.id as string].status.toNumber())) // continue; // for (const iOutPool of info.out) { // if (!simulateCache[iOutPool.id as string] && !tickCache[iOutPool.id.toString()]) continue; // if (iOutPool.version !== 6 && ![1, 6, 7].includes(simulateCache[iOutPool.id as string].status.toNumber())) // continue; // try { // const { // amountOut, // minAmountOut, // executionPrice, // priceImpact, // fee, // remainingAccounts, // minMiddleAmountFee, // middleToken, // expirationTime, // realAmountIn, // } = await this.computeAmountOut({ // middleMintInfo: { // mint: new PublicKey(routeMint), // decimals: info.mDecimals, // }, // amountIn, // currencyOut: outputToken, // slippage, // fromPool: iFromPool, // toPool: iOutPool, // simulateCache, // tickCache, // mintInfos, // }); // const infoAPoolOpen = // iFromPool.version === 6 // ? (iFromPool as ClmmPoolInfo).startTime < chainTime // : simulateCache[iFromPool.id as string].startTime.toNumber() < chainTime; // const infoBPoolOpen = // iOutPool.version === 6 // ? (iOutPool as ClmmPoolInfo).startTime < chainTime // : simulateCache[iOutPool.id as string].startTime.toNumber() < chainTime; // const poolTypeA = iFromPool.version === 6 ? "CLMM" : iFromPool.version === 5 ? "STABLE" : undefined; // const poolTypeB = iOutPool.version === 6 ? "CLMM" : iOutPool.version === 5 ? "STABLE" : undefined; // outRoute.push({ // amountIn: realAmountIn, // amountOut, // minAmountOut, // currentPrice: undefined, // executionPrice, // priceImpact, // fee, // routeType: "route", // poolKey: [iFromPool, iOutPool], // remainingAccounts, // minMiddleAmountFee, // middleToken, // poolReady: infoAPoolOpen && infoBPoolOpen, // poolType: [poolTypeA, poolTypeB], // feeConfig: _inFeeConfig, // expirationTime, // }); // } catch (e) { // // // } // } // } // } // outRoute.sort((a, b) => (a.amountOut.amount.raw.sub(b.amountOut.amount.raw).gt(BN_ZERO) ? -1 : 1)); // const isReadyRoutes = outRoute.filter((i) => i.poolReady); // return { // routes: outRoute, // best: isReadyRoutes.length ? isReadyRoutes[0] : outRoute[0], // }; // } // private async computeAmountOut({ // middleMintInfo, // amountIn, // currencyOut, // slippage, // fromPool, // toPool, // simulateCache, // tickCache, // mintInfos, // }: { // middleMintInfo: { mint: PublicKey; decimals: number }; // amountIn: TokenAmount; // currencyOut: Token; // slippage: Percent; // fromPool: PoolType; // toPool: PoolType; // simulateCache: ReturnTypeFetchMultipleInfo; // tickCache: ReturnTypeFetchMultiplePoolTickArrays; // mintInfos: ReturnTypeFetchMultipleMintInfos; // }): Promise<{ // minMiddleAmountFee: TokenAmount | undefined; // middleToken: Token; // realAmountIn: TransferAmountFee; // amountOut: TransferAmountFee; // minAmountOut: TransferAmountFee; // executionPrice: Price | null; // priceImpact: Fraction; // fee: TokenAmount[]; // remainingAccounts: [PublicKey[] | undefined, PublicKey[] | undefined]; // expirationTime: number | undefined; // }> { // const epochInfo = await this.scope.fetchEpochInfo(); // const middleToken = new Token(middleMintInfo); // let firstPriceImpact: Percent; // let firstFee: TokenAmount; // let firstRemainingAccounts: PublicKey[] | undefined = undefined; // let minMiddleAmountOut: TransferAmountFee; // let firstExpirationTime: number | undefined = undefined; // let realAmountIn: TransferAmountFee = { // amount: amountIn, // fee: undefined, // expirationTime: undefined, // }; // const _slippage = new Percent(0, 100); // if (fromPool.version === 6) { // const { // minAmountOut: _minMiddleAmountOut, // priceImpact: _firstPriceImpact, // fee: _firstFee, // remainingAccounts: _firstRemainingAccounts, // expirationTime: _expirationTime, // realAmountIn: _realAmountIn, // } = await PoolUtils.computeAmountOutFormat({ // poolInfo: fromPool as ClmmPoolInfo, // tickArrayCache: tickCache[fromPool.id.toString()], // amountIn, // tokenOut: middleToken, // slippage: _slippage, // epochInfo, // token2022Infos: mintInfos, // }); // minMiddleAmountOut = _minMiddleAmountOut; // firstPriceImpact = _firstPriceImpact; // firstFee = _firstFee; // firstRemainingAccounts = _firstRemainingAccounts; // firstExpirationTime = _expirationTime; // realAmountIn = _realAmountIn; // } else { // const { // minAmountOut: _minMiddleAmountOut, // priceImpact: _firstPriceImpact, // fee: _firstFee, // } = this.scope.liquidity.computeAmountOut({ // poolKeys: jsonInfo2PoolKeys(fromPool) as LiquidityPoolKeys, // poolInfo: simulateCache[fromPool.id as string], // amountIn, // outputToken: middleToken, // slippage: _slippage, // }); // minMiddleAmountOut = { // amount: _minMiddleAmountOut, // fee: undefined, // expirationTime: undefined, // }; // firstPriceImpact = _firstPriceImpact; // firstFee = _firstFee; // } // let amountOut: TransferAmountFee; // let minAmountOut: TransferAmountFee; // let secondPriceImpact: Percent; // let secondFee: TokenAmount; // let secondRemainingAccounts: PublicKey[] | undefined = undefined; // let secondExpirationTime: number | undefined = undefined; // let realAmountRouteIn: TransferAmountFee = minMiddleAmountOut; // if (toPool.version === 6) { // const { // amountOut: _amountOut, // minAmountOut: _minAmountOut, // priceImpact: _secondPriceImpact, // fee: _secondFee, // remainingAccounts: _secondRemainingAccounts, // expirationTime: _expirationTime, // realAmountIn: _realAmountIn, // } = await PoolUtils.computeAmountOutFormat({ // poolInfo: toPool as ClmmPoolInfo, // tickArrayCache: tickCache[toPool.id.toString()], // amountIn: new TokenAmount( // (minMiddleAmountOut.amount as TokenAmount).token, // minMiddleAmountOut.amount.raw.sub( // minMiddleAmountOut.fee === undefined ? BN_ZERO : minMiddleAmountOut.fee.raw, // ), // ), // tokenOut: currencyOut, // slippage, // epochInfo, // token2022Infos: mintInfos, // }); // amountOut = _amountOut; // minAmountOut = _minAmountOut; // secondPriceImpact = _secondPriceImpact; // secondFee = _secondFee; // secondRemainingAccounts = _secondRemainingAccounts; // secondExpirationTime = _expirationTime; // realAmountRouteIn = _realAmountIn; // } else { // const { // amountOut: _amountOut, // minAmountOut: _minAmountOut, // priceImpact: _secondPriceImpact, // fee: _secondFee, // } = this.scope.liquidity.computeAmountOut({ // poolKeys: jsonInfo2PoolKeys(toPool) as LiquidityPoolKeys, // poolInfo: simulateCache[toPool.id as string], // amountIn: new TokenAmount( // minMiddleAmountOut.amount.token, // minMiddleAmountOut.amount.raw.sub( // minMiddleAmountOut.fee === undefined ? BN_ZERO : minMiddleAmountOut.fee.raw, // ), // ), // outputToken: currencyOut, // slippage, // }); // amountOut = { // amount: _amountOut, // fee: undefined, // expirationTime: undefined, // }; // minAmountOut = { // amount: _minAmountOut, // fee: undefined, // expirationTime: undefined, // }; // secondPriceImpact = _secondPriceImpact; // secondFee = _secondFee; // } // let executionPrice: Price | null = null; // const amountInRaw = amountIn.raw; // const amountOutRaw = amountOut.amount.raw; // const currencyIn = amountIn.token; // if (!amountInRaw.isZero() && !amountOutRaw.isZero()) { // executionPrice = new Price({ // baseToken: currencyIn, // denominator: amountInRaw, // quoteToken: currencyOut, // numerator: amountOutRaw, // }); // } // return { // minMiddleAmountFee: // minMiddleAmountOut.fee !== undefined // ? new TokenAmount( // middleToken, // (minMiddleAmountOut.fee?.raw ?? new BN(0)).add(realAmountRouteIn.fee?.raw ?? new BN(0)), // ) // : undefined, // middleToken, // realAmountIn, // amountOut, // minAmountOut, // executionPrice, // priceImpact: firstPriceImpact.add(secondPriceImpact), // fee: [firstFee, secondFee], // remainingAccounts: [firstRemainingAccounts, secondRemainingAccounts], // expirationTime: minExpirationTime(firstExpirationTime, secondExpirationTime), // }; // } private async getWSolAccounts(): Promise<TokenAccount[]> { this.scope.checkOwner(); await this.scope.account.fetchWalletTokenAccounts(); const tokenAccounts = this.scope.account.tokenAccounts.filter((acc) => acc.mint.equals(WSOLMint)); tokenAccounts.sort((a, b) => { if (a.isAssociated) return 1; if (b.isAssociated) return -1; return a.amount.lt(b.amount) ? -1 : 1; }); return tokenAccounts; } public async unWrapWSol(props: { amount: BigNumberish; computeBudgetConfig?: ComputeBudgetConfig; tokenProgram?: PublicKey; }): Promise<MakeTransaction> { const { amount, tokenProgram } = props; const tokenAccounts = await this.getWSolAccounts(); const txBuilder = this.createTxBuilder(); txBuilder.addCustomComputeBudget(props.computeBudgetConfig); const ins = await createWSolAccountInstructions({ connection: this.scope.connection, owner: this.scope.ownerPubKey, payer: this.scope.ownerPubKey, amount: 0, }); txBuilder.addInstruction(ins); const amountBN = parseBigNumberish(amount); for (let i = 0; i < tokenAccounts.length; i++) { if (amountBN.gte(tokenAccounts[i].amount)) { txBuilder.addInstruction({ instructions: [ closeAccountInstruction({ tokenAccount: tokenAccounts[i].publicKey!, payer: this.scope.ownerPubKey, owner: this.scope.ownerPubKey, programId: tokenProgram, }), ], }); amountBN.sub(tokenAccounts[i].amount); } else { txBuilder.addInstruction({ instructions: [ closeAccountInstruction({ tokenAccount: tokenAccounts[i].publicKey!, payer: this.scope.ownerPubKey, owner: this.scope.ownerPubKey, programId: tokenProgram, }), ], }); makeTransferInstruction({ destination: ins.addresses.newAccount, source: tokenAccounts[i].publicKey!, amount: amountBN, owner: this.scope.ownerPubKey, tokenProgram, }); } } return txBuilder.build(); } public async wrapWSol(amount: BigNumberish, tokenProgram?: PublicKey): Promise<MakeTransaction> { const tokenAccounts = await this.getWSolAccounts(); const txBuilder = this.createTxBuilder(); const ins = await createWSolAccountInstructions({ connection: this.scope.connection, owner: this.scope.ownerPubKey, payer: this.scope.ownerPubKey, amount, skipCloseAccount: true, }); txBuilder.addInstruction(ins); if (tokenAccounts.length) { // already have wsol account txBuilder.addInstruction({ instructions: [ makeTransferInstruction({ // destination: ins.signers![0].publicKey, destination: tokenAccounts[0].publicKey!, source: ins.addresses.newAccount, amount, owner: this.scope.ownerPubKey, tokenProgram, }), ], endInstructions: [ closeAccountInstruction({ tokenAccount: ins.addresses.newAccount, payer: this.scope.ownerPubKey, owner: this.scope.ownerPubKey, programId: tokenProgram, }), ], }); } return txBuilder.build(); } public async swap({ swapInfo: orgSwapInfo, associatedOnly, checkCreateATAOwner, checkTransaction, routeProgram = new PublicKey("routeUGWgWzqBWFcrCfv8tritsqukccJPu3q5GPP3xS"), }: { swapInfo: ComputeAmountOutLayout; associatedOnly: boolean; checkCreateATAOwner: boolean; checkTransaction: boolean; routeProgram: PublicKey; }): Promise<MakeMultiTransaction> { const swapInfo = { ...orgSwapInfo, amountIn: this.scope.solToWsolTransferAmountFee(orgSwapInfo.amountIn), amountOut: this.scope.solToWsolTransferAmountFee(orgSwapInfo.amountOut), minAmountOut: this.scope.solToWsolTransferAmountFee(orgSwapInfo.minAmountOut), middleMint: (orgSwapInfo as ComputeAmountOutRouteLayout).minMiddleAmountFee ? solToWSol((orgSwapInfo as ComputeAmountOutRouteLayout).middleToken.mint) : undefined, }; const amountIn = swapInfo.amountIn; const amountOut = swapInfo.amountOut; const useSolBalance = amountIn.amount.token.mint.equals(Token.WSOL.mint) || amountIn.amount.token.mint.equals(SOLMint); const outSolBalance = amountOut.amount.token.mint.equals(Token.WSOL.mint) || amountOut.amount.token.mint.equals(SOLMint); const inputMint = amountIn.amount.token.mint; const middleMint = swapInfo.middleMint!; const outputMint = amountOut.amount.token.mint; const txBuilder = this.createTxBuilder(); const { account: sourceToken, instructionParams: sourceInstructionParams } = await this.scope.account.getOrCreateTokenAccount({ mint: inputMint, notUseTokenAccount: useSolBalance, createInfo: useSolBalance ? { payer: this.scope.ownerPubKey, amount: amountIn.amount.raw, } : undefined, owner: this.scope.ownerPubKey, skipCloseAccount: !useSolBalance, associatedOnly: useSolBalance ? false : associatedOnly, checkCreateATAOwner, }); sourceInstructionParams && txBuilder.addInstruction(sourceInstructionParams); if (sourceToken === undefined) throw Error("input account check error"); const { account: destinationToken, instructionParams: destinationInstructionParams } = await this.scope.account.getOrCreateTokenAccount({ mint: outputMint, skipCloseAccount: !outSolBalance, createInfo: { payer: this.scope.ownerPubKey, amount: 0, }, owner: this.scope.ownerPubKey, associatedOnly, checkCreateATAOwner, }); destinationInstructionParams && txBuilder.addInstruction(destinationInstructionParams); let routeToken: PublicKey | undefined = undefined; if (swapInfo.routeType === "route") { const res = await this.scope.account.getOrCreateTokenAccount({ mint: middleMint, createInfo: { payer: this.scope.ownerPubKey, amount: 0, }, owner: this.scope.ownerPubKey, associatedOnly: false, checkCreateATAOwner, }); routeToken = res.account; res.instructionParams && txBuilder.addInstruction(res.instructionParams); } const ins = await makeSwapInstruction({ routeProgram, inputMint, swapInfo, ownerInfo: { wallet: this.scope.ownerPubKey, sourceToken, routeToken, destinationToken: destinationToken!, }, }); const transferIns = swapInfo.feeConfig !== undefined ? [ createTransferInstruction( sourceToken, swapInfo.feeConfig.feeAccount, this.scope.ownerPubKey, swapInfo.feeConfig.feeAmount.toNumber(), ), ] : []; const transferInsType = swapInfo.feeConfig !== undefined ? [InstructionType.TransferAmount] : []; const instructions: TransactionInstruction[] = []; const instructionsTypes: string[] = []; const config = await txBuilder.getComputeBudgetConfig(); if (config) { const { instructions: _ins, instructionTypes: _insType } = addComputeBudget(config); instructions.push(..._ins); instructionsTypes.push(..._insType); } const allTxBuilder: TxBuilder[] = []; const tempIns = [ ...instructions, ...transferIns, ...txBuilder.AllTxData.instructions, ...ins.instructions, ...txBuilder.AllTxData.endInstructions, ]; const tempInsType = [ ...instructionsTypes, ...transferInsType, ...txBuilder.AllTxData.instructionTypes, ...ins.instructionTypes, ...txBuilder.AllTxData.endInstructionTypes, ]; const tempSigner = [...txBuilder.AllTxData.signers, ...ins.signers]; if (checkTransaction) { if (forecastTransactionSize(tempIns, [this.scope.ownerPubKey, ...tempSigner.map((i) => i.publicKey)])) { allTxBuilder.push( this.createTxBuilder().addInstruction({ instructions: tempIns, signers: tempSigner, instructionTypes: tempInsType, }), ); } else { if (txBuilder.AllTxData.instructions.length > 0) { allTxBuilder.push( this.createTxBuilder().addInstruction({ instructions: txBuilder.AllTxData.instructions, signers: txBuilder.AllTxData.signers, instructionTypes: txBuilder.AllTxData.instructionTypes, }), ); } if (forecastTransactionSize([...instructions, ...transferIns, ...ins.instructions], [this.scope.ownerPubKey])) { allTxBuilder.push( this.createTxBuilder().addInstruction({ instructions: [...instructions, ...transferIns, ...ins.instructions], signers: ins.signers, instructionTypes: [...instructionsTypes, ...transferInsType, ...ins.instructionTypes], }), ); } else if (forecastTransactionSize([...instructions, ...ins.instructions], [this.scope.ownerPubKey])) { allTxBuilder.push( this.createTxBuilder().addInstruction({ instructions: [...instructions, ...ins.instructions], signers: ins.signers, instructionTypes: ins.instructionTypes, }), ); } else if (forecastTransactionSize(ins.instructions, [this.scope.ownerPubKey])) { allTxBuilder.push( this.createTxBuilder().addInstruction({ instructions: [...ins.instructions], signers: ins.signers, instructionTypes: ins.instructionTypes, }), ); } else { for (let index = 0; index < ins.instructions.length; index++) { allTxBuilder.push( this.createTxBuilder().addInstruction({ instructions: [...instructions, ins.instructions[index]], signers: ins.signers, instructionTypes: [...instructionsTypes, ins.instructionTypes[index]], }), ); } } if (txBuilder.AllTxData.endInstructions.length > 0) { allTxBuilder.push( this.createTxBuilder().addInstruction({ instructions: txBuilder.AllTxData.endInstructions, instructionTypes: txBuilder.AllTxData.endInstructionTypes, }), ); } } } else { if (swapInfo.routeType === "amm") { allTxBuilder.push( this.createTxBuilder().addInstruction({ instructions: tempIns, signers: tempSigner, instructionTypes: tempInsType, }), ); } else { if (txBuilder.AllTxData.instructions.length > 0) { allTxBuilder.push( this.createTxBuilder().addInstruction({ instructions: txBuilder.AllTxData.instructions, signers: txBuilder.AllTxData.signers, instructionTypes: txBuilder.AllTxData.instructionTypes, }), ); } allTxBuilder.push( this.createTxBuilder().addInstruction({ instructions: ins.instructions, signers: ins.signers, instructionTypes: ins.instructionTypes, }), ); if (txBuilder.AllTxData.endInstructions.length > 0) { allTxBuilder.push( this.createTxBuilder().addInstruction({ instructions: txBuilder.AllTxData.endInstructions, instructionTypes: txBuilder.AllTxData.endInstructionTypes, }), ); } } } const firstBuilder = allTxBuilder.shift()!; return firstBuilder.buildMultiTx({ extraPreBuildData: allTxBuilder.map((builder) => builder.build()) }); } }