@raydium-io/raydium-sdk-v2
Version:
An SDK for building applications on top of Raydium.
1 lines • 943 kB
Source Map (JSON)
{"version":3,"sources":["../../../src/raydium/liquidity/liquidity.ts","../../../src/common/accountInfo.ts","../../../src/common/bignumber.ts","../../../node_modules/decimal.js/decimal.mjs","../../../src/module/amount.ts","../../../src/common/logger.ts","../../../src/module/formatter.ts","../../../src/module/fraction.ts","../../../src/common/constant.ts","../../../src/raydium/token/constant.ts","../../../src/module/token.ts","../../../src/common/pubKey.ts","../../../src/module/currency.ts","../../../src/module/percent.ts","../../../src/module/price.ts","../../../src/common/lodash.ts","../../../src/common/pda.ts","../../../src/common/txTool/txUtils.ts","../../../src/common/txTool/txType.ts","../../../src/common/programId.ts","../../../src/common/transfer.ts","../../../src/common/txTool/lookupTable.ts","../../../src/common/txTool/txTool.ts","../../../src/common/utility.ts","../../../src/common/fee.ts","../../../src/marshmallow/index.ts","../../../src/marshmallow/buffer-layout.ts","../../../src/raydium/farm/config.ts","../../../src/raydium/farm/layout.ts","../../../src/raydium/farm/util.ts","../../../src/raydium/account/layout.ts","../../../src/raydium/farm/instruction.ts","../../../src/raydium/clmm/instrument.ts","../../../src/raydium/clmm/utils/tick.ts","../../../src/raydium/clmm/utils/constants.ts","../../../src/raydium/clmm/utils/math.ts","../../../src/raydium/clmm/utils/util.ts","../../../src/raydium/clmm/utils/pda.ts","../../../src/raydium/clmm/utils/pool.ts","../../../src/raydium/clmm/utils/position.ts","../../../src/raydium/clmm/utils/tickQuery.ts","../../../src/raydium/clmm/utils/tickarrayBitmap.ts","../../../src/raydium/clmm/layout.ts","../../../src/raydium/moduleBase.ts","../../../src/raydium/token/layout.ts","../../../src/raydium/token/utils.ts","../../../src/raydium/liquidity/constant.ts","../../../src/raydium/liquidity/instruction.ts","../../../src/raydium/liquidity/layout.ts","../../../src/raydium/liquidity/stable.ts","../../../src/raydium/liquidity/utils.ts","../../../src/raydium/liquidity/serum.ts","../../../src/raydium/account/util.ts","../../../node_modules/@noble/hashes/src/_assert.ts","../../../node_modules/@noble/hashes/src/utils.ts","../../../node_modules/@noble/hashes/src/_md.ts","../../../node_modules/@noble/hashes/src/sha256.ts","../../../src/raydium/account/instruction.ts","../../../src/raydium/marketV2/createMarket.ts","../../../src/raydium/marketV2/instrument.ts","../../../src/raydium/marketV2/layout.ts"],"sourcesContent":["import { PublicKey, TransactionInstruction } from \"@solana/web3.js\";\nimport {\n AmmV4Keys,\n AmmV5Keys,\n ApiV3PoolInfoConcentratedItem,\n ApiV3PoolInfoStandardItem,\n FormatFarmInfoOutV6,\n} from \"../../api/type\";\nimport { AccountLayout, NATIVE_MINT, TOKEN_PROGRAM_ID } from \"@solana/spl-token\";\nimport { getMultipleAccountsInfoWithCustomFlags } from \"@/common/accountInfo\";\nimport { BN_ZERO, divCeil } from \"@/common/bignumber\";\nimport { getATAAddress } from \"@/common/pda\";\nimport { BNDivCeil } from \"@/common/transfer\";\nimport { MakeMultiTxData, MakeTxData } from \"@/common/txTool/txTool\";\nimport { InstructionType, TxVersion } from \"@/common/txTool/txType\";\nimport { Percent, Token, TokenAmount } from \"../../module\";\nimport {\n FARM_PROGRAM_TO_VERSION,\n FarmLedger,\n createAssociatedLedgerAccountInstruction,\n getAssociatedLedgerAccount,\n getFarmLedgerLayout,\n makeWithdrawInstructionV3,\n makeWithdrawInstructionV5,\n makeWithdrawInstructionV6,\n} from \"../../raydium/farm\";\nimport { ClmmInstrument } from \"../clmm/instrument\";\nimport ModuleBase, { ModuleBaseProps } from \"../moduleBase\";\nimport { toToken } from \"../token\";\nimport { ComputeBudgetConfig } from \"../type\";\nimport { LIQUIDITY_FEES_DENOMINATOR, LIQUIDITY_FEES_NUMERATOR } from \"./constant\";\nimport {\n createPoolV4InstructionV2,\n makeAMMSwapInstruction,\n makeAMMSwapV2Instruction,\n makeAddLiquidityInstruction,\n removeLiquidityInstruction,\n swapBaseInV2Instruction,\n} from \"./instruction\";\nimport { createPoolFeeLayout, liquidityStateV4Layout } from \"./layout\";\nimport { StableLayout, getDxByDyBaseIn, getDyByDxBaseIn, getStablePrice } from \"./stable\";\nimport {\n AddLiquidityParams,\n AmmRpcData,\n AmountSide,\n ComputeAmountInParam,\n ComputeAmountOutParam,\n CreatePoolAddress,\n CreatePoolParam,\n CreateMarketAndPoolParam,\n RemoveParams,\n SwapParam,\n} from \"./type\";\nimport { getAssociatedConfigId, getAssociatedPoolKeys, toAmmComputePoolInfo } from \"./utils\";\n\nimport BN from \"bn.js\";\nimport Decimal from \"decimal.js\";\nimport { AMM_V4, DEVNET_PROGRAM_ID, FEE_DESTINATION_ID, OPEN_BOOK_PROGRAM, WSOLMint } from \"@/common\";\nimport { generatePubKey } from \"../account\";\nimport { makeCreateMarketInstruction, MarketExtInfo } from \"../marketV2\";\n\nexport default class LiquidityModule extends ModuleBase {\n public stableLayout: StableLayout;\n\n constructor(params: ModuleBaseProps) {\n super(params);\n this.stableLayout = new StableLayout({\n connection: this.scope.connection,\n modelDataPubKey: this.scope.cluster === \"mainnet\" ? undefined : DEVNET_PROGRAM_ID.MODEL_DATA_PUBKEY,\n });\n }\n\n public async initLayout(): Promise<void> {\n await this.stableLayout.initStableModelLayout();\n }\n\n public async load(): Promise<void> {\n this.checkDisabled();\n }\n\n public computePairAmount({\n poolInfo,\n amount,\n // anotherToken,\n slippage,\n baseIn,\n }: {\n poolInfo: ApiV3PoolInfoStandardItem;\n amount: string | Decimal;\n slippage: Percent;\n baseIn?: boolean;\n }): { anotherAmount: TokenAmount; maxAnotherAmount: TokenAmount; minAnotherAmount: TokenAmount; liquidity: BN } {\n const inputAmount = new BN(new Decimal(amount).mul(10 ** poolInfo[baseIn ? \"mintA\" : \"mintB\"].decimals).toFixed(0));\n const _anotherToken = toToken(poolInfo[baseIn ? \"mintB\" : \"mintA\"]);\n\n const [baseReserve, quoteReserve] = [\n new BN(new Decimal(poolInfo.mintAmountA).mul(10 ** poolInfo.mintA.decimals).toString()),\n new BN(new Decimal(poolInfo.mintAmountB).mul(10 ** poolInfo.mintB.decimals).toString()),\n ];\n const lpAmount = new BN(\n new Decimal(poolInfo.lpAmount).mul(10 ** poolInfo.lpMint.decimals).toFixed(0, Decimal.ROUND_DOWN),\n );\n this.logDebug(\"baseReserve:\", baseReserve.toString(), \"quoteReserve:\", quoteReserve.toString());\n\n this.logDebug(\n \"tokenIn:\",\n baseIn ? poolInfo.mintA.symbol : poolInfo.mintB.symbol,\n \"amountIn:\",\n inputAmount.toString(),\n \"anotherToken:\",\n baseIn ? poolInfo.mintB.symbol : poolInfo.mintA.symbol,\n \"slippage:\",\n `${slippage.toSignificant()}%`,\n \"baseReserve\",\n baseReserve.toString(),\n \"quoteReserve\",\n quoteReserve.toString(),\n );\n\n // input is fixed\n const input = baseIn ? \"base\" : \"quote\";\n this.logDebug(\"input side:\", input);\n\n // round up\n let amountRaw = BN_ZERO;\n if (!inputAmount.isZero()) {\n amountRaw =\n input === \"base\"\n ? divCeil(inputAmount.mul(quoteReserve), baseReserve)\n : divCeil(inputAmount.mul(baseReserve), quoteReserve);\n }\n\n this.logDebug(\"amountRaw:\", amountRaw.toString(), \"lpAmount:\", lpAmount.toString());\n\n const liquidity = divCeil(inputAmount.mul(lpAmount), input === \"base\" ? baseReserve : quoteReserve);\n\n this.logDebug(\"liquidity:\", liquidity.toString());\n\n const _slippage = new Percent(new BN(1)).add(slippage);\n const _slippageMin = new Percent(new BN(1)).sub(slippage);\n const slippageAdjustedAmount = _slippage.mul(amountRaw).quotient;\n const slippageAdjustedMinAmount = _slippageMin.mul(amountRaw).quotient;\n\n const _anotherAmount = new TokenAmount(_anotherToken, amountRaw);\n const _maxAnotherAmount = new TokenAmount(_anotherToken, slippageAdjustedAmount);\n const _minAnotherAmount = new TokenAmount(_anotherToken, slippageAdjustedMinAmount);\n this.logDebug(\"anotherAmount:\", _anotherAmount.toFixed(), \"maxAnotherAmount:\", _maxAnotherAmount.toFixed());\n\n return {\n anotherAmount: _anotherAmount,\n maxAnotherAmount: _maxAnotherAmount,\n minAnotherAmount: _minAnotherAmount,\n liquidity,\n };\n }\n\n public async getAmmPoolKeys(poolId: string): Promise<AmmV4Keys | AmmV5Keys> {\n return ((await this.scope.api.fetchPoolKeysById({ idList: [poolId] })) as (AmmV4Keys | AmmV5Keys)[])[0];\n }\n\n public async addLiquidity<T extends TxVersion>(params: AddLiquidityParams<T>): Promise<MakeTxData<T>> {\n const {\n poolInfo,\n poolKeys: propPoolKeys,\n amountInA,\n amountInB,\n otherAmountMin,\n fixedSide,\n config,\n txVersion,\n computeBudgetConfig,\n txTipConfig,\n feePayer,\n } = params;\n\n if (this.scope.availability.addStandardPosition === false)\n this.logAndCreateError(\"add liquidity feature disabled in your region\");\n\n this.logDebug(\"amountInA:\", amountInA, \"amountInB:\", amountInB);\n if (amountInA.isZero() || amountInB.isZero())\n this.logAndCreateError(\"amounts must greater than zero\", \"amountInA & amountInB\", {\n amountInA: amountInA.toFixed(),\n amountInB: amountInB.toFixed(),\n });\n const { account } = this.scope;\n const { bypassAssociatedCheck, checkCreateATAOwner } = {\n // default\n ...{ bypassAssociatedCheck: false, checkCreateATAOwner: false },\n // custom\n ...config,\n };\n const [tokenA, tokenB] = [amountInA.token, amountInB.token];\n const tokenAccountA = await account.getCreatedTokenAccount({\n mint: tokenA.mint,\n associatedOnly: false,\n });\n const tokenAccountB = await account.getCreatedTokenAccount({\n mint: tokenB.mint,\n associatedOnly: false,\n });\n if (!tokenAccountA && !tokenAccountB)\n this.logAndCreateError(\"cannot found target token accounts\", \"tokenAccounts\", account.tokenAccounts);\n\n const lpTokenAccount = await account.getCreatedTokenAccount({\n mint: new PublicKey(poolInfo.lpMint.address),\n });\n\n const tokens = [tokenA, tokenB];\n const _tokenAccounts = [tokenAccountA, tokenAccountB];\n const rawAmounts = [amountInA.raw, amountInB.raw];\n\n // handle amount a & b and direction\n const sideA = amountInA.token.mint.toBase58() === poolInfo.mintA.address ? \"base\" : \"quote\";\n let _fixedSide: AmountSide = \"base\";\n if (![\"quote\", \"base\"].includes(sideA)) this.logAndCreateError(\"invalid fixedSide\", \"fixedSide\", fixedSide);\n if (sideA === \"quote\") {\n tokens.reverse();\n _tokenAccounts.reverse();\n rawAmounts.reverse();\n _fixedSide = fixedSide === \"a\" ? \"quote\" : \"base\";\n } else if (sideA === \"base\") {\n _fixedSide = fixedSide === \"a\" ? \"base\" : \"quote\";\n }\n\n const [baseToken, quoteToken] = tokens;\n const [baseTokenAccount, quoteTokenAccount] = _tokenAccounts;\n const [baseAmountRaw, quoteAmountRaw] = rawAmounts;\n\n const poolKeys = propPoolKeys ?? (await this.getAmmPoolKeys(poolInfo.id));\n\n const txBuilder = this.createTxBuilder(feePayer);\n\n const { tokenAccount: _baseTokenAccount, ...baseInstruction } = await account.handleTokenAccount({\n side: \"in\",\n amount: baseAmountRaw,\n mint: baseToken.mint,\n tokenAccount: baseTokenAccount,\n bypassAssociatedCheck,\n checkCreateATAOwner,\n });\n txBuilder.addInstruction(baseInstruction);\n const { tokenAccount: _quoteTokenAccount, ...quoteInstruction } = await account.handleTokenAccount({\n side: \"in\",\n amount: quoteAmountRaw,\n mint: quoteToken.mint,\n tokenAccount: quoteTokenAccount,\n bypassAssociatedCheck,\n checkCreateATAOwner,\n });\n txBuilder.addInstruction(quoteInstruction);\n const { tokenAccount: _lpTokenAccount, ...lpInstruction } = await account.handleTokenAccount({\n side: \"out\",\n amount: 0,\n mint: new PublicKey(poolInfo.lpMint.address),\n tokenAccount: lpTokenAccount,\n bypassAssociatedCheck,\n checkCreateATAOwner,\n });\n txBuilder.addInstruction(lpInstruction);\n txBuilder.addInstruction({\n instructions: [\n makeAddLiquidityInstruction({\n poolInfo,\n poolKeys: poolKeys as AmmV4Keys | AmmV5Keys,\n userKeys: {\n baseTokenAccount: _baseTokenAccount!,\n quoteTokenAccount: _quoteTokenAccount!,\n lpTokenAccount: _lpTokenAccount!,\n owner: this.scope.ownerPubKey,\n },\n baseAmountIn: baseAmountRaw,\n quoteAmountIn: quoteAmountRaw,\n otherAmountMin: otherAmountMin.raw,\n fixedSide: _fixedSide,\n }),\n ],\n instructionTypes: [\n poolInfo.pooltype.includes(\"StablePool\")\n ? InstructionType.AmmV5AddLiquidity\n : InstructionType.AmmV4AddLiquidity,\n ],\n lookupTableAddress: poolKeys.lookupTableAccount ? [poolKeys.lookupTableAccount] : [],\n });\n txBuilder.addCustomComputeBudget(computeBudgetConfig);\n txBuilder.addTipInstruction(txTipConfig);\n if (txVersion === TxVersion.V0) return (await txBuilder.buildV0()) as MakeTxData<T>;\n return txBuilder.build() as MakeTxData<T>;\n }\n\n public async removeLiquidity<T extends TxVersion>(params: RemoveParams<T>): Promise<Promise<MakeTxData<T>>> {\n if (this.scope.availability.removeStandardPosition === false)\n this.logAndCreateError(\"remove liquidity feature disabled in your region\");\n const {\n poolInfo,\n poolKeys: propPoolKeys,\n lpAmount,\n baseAmountMin,\n quoteAmountMin,\n config,\n txVersion,\n computeBudgetConfig,\n txTipConfig,\n feePayer,\n } = params;\n const poolKeys = propPoolKeys ?? (await this.getAmmPoolKeys(poolInfo.id));\n const [baseMint, quoteMint, lpMint] = [\n new PublicKey(poolInfo.mintA.address),\n new PublicKey(poolInfo.mintB.address),\n new PublicKey(poolInfo.lpMint.address),\n ];\n this.logDebug(\"lpAmount:\", lpAmount);\n this.logDebug(\"baseAmountMin:\", baseAmountMin);\n this.logDebug(\"quoteAmountMin:\", quoteAmountMin);\n if (lpAmount.isZero()) this.logAndCreateError(\"amount must greater than zero\", \"lpAmount\", lpAmount.toString());\n\n const { account } = this.scope;\n const lpTokenAccount = await account.getCreatedTokenAccount({\n mint: lpMint,\n associatedOnly: false,\n });\n if (!lpTokenAccount) this.logAndCreateError(\"cannot found lpTokenAccount\", \"tokenAccounts\", account.tokenAccounts);\n\n const baseTokenAccount = await account.getCreatedTokenAccount({\n mint: baseMint,\n });\n const quoteTokenAccount = await account.getCreatedTokenAccount({\n mint: quoteMint,\n });\n\n const txBuilder = this.createTxBuilder(feePayer);\n const { bypassAssociatedCheck, checkCreateATAOwner } = {\n // default\n ...{ bypassAssociatedCheck: false, checkCreateATAOwner: false },\n // custom\n ...config,\n };\n\n const { tokenAccount: _baseTokenAccount, ...baseInstruction } = await account.handleTokenAccount({\n side: \"out\",\n amount: 0,\n mint: baseMint,\n tokenAccount: baseTokenAccount,\n bypassAssociatedCheck,\n checkCreateATAOwner,\n });\n txBuilder.addInstruction(baseInstruction);\n const { tokenAccount: _quoteTokenAccount, ...quoteInstruction } = await account.handleTokenAccount({\n side: \"out\",\n amount: 0,\n mint: quoteMint,\n tokenAccount: quoteTokenAccount,\n bypassAssociatedCheck,\n checkCreateATAOwner,\n });\n txBuilder.addInstruction(quoteInstruction);\n\n txBuilder.addInstruction({\n instructions: [\n removeLiquidityInstruction({\n poolInfo,\n poolKeys,\n userKeys: {\n lpTokenAccount: lpTokenAccount!,\n baseTokenAccount: _baseTokenAccount!,\n quoteTokenAccount: _quoteTokenAccount!,\n owner: this.scope.ownerPubKey,\n },\n lpAmount,\n baseAmountMin,\n quoteAmountMin,\n }),\n ],\n lookupTableAddress: poolKeys.lookupTableAccount ? [poolKeys.lookupTableAccount] : [],\n instructionTypes: [\n poolInfo.pooltype.includes(\"StablePool\")\n ? InstructionType.AmmV5RemoveLiquidity\n : InstructionType.AmmV4RemoveLiquidity,\n ],\n });\n txBuilder.addCustomComputeBudget(computeBudgetConfig);\n txBuilder.addTipInstruction(txTipConfig);\n if (txVersion === TxVersion.V0) return (await txBuilder.buildV0()) as MakeTxData<T>;\n return txBuilder.build() as MakeTxData<T>;\n }\n\n public async removeAllLpAndCreateClmmPosition<T extends TxVersion>({\n poolInfo,\n clmmPoolInfo,\n removeLpAmount,\n createPositionInfo,\n farmInfo,\n userFarmLpAmount,\n base,\n computeBudgetConfig,\n payer,\n userAuxiliaryLedgers,\n tokenProgram = TOKEN_PROGRAM_ID,\n checkCreateATAOwner = true,\n getEphemeralSigners,\n txVersion,\n feePayer,\n }: {\n poolInfo: ApiV3PoolInfoStandardItem;\n clmmPoolInfo: ApiV3PoolInfoConcentratedItem;\n removeLpAmount: BN;\n createPositionInfo: {\n tickLower: number;\n tickUpper: number;\n baseAmount: BN;\n otherAmountMax: BN;\n };\n farmInfo?: FormatFarmInfoOutV6;\n userFarmLpAmount?: BN;\n userAuxiliaryLedgers?: PublicKey[];\n base: \"MintA\" | \"MintB\";\n payer?: PublicKey;\n computeBudgetConfig?: ComputeBudgetConfig;\n tokenProgram?: PublicKey;\n checkCreateATAOwner?: boolean;\n txVersion?: T;\n getEphemeralSigners?: (k: number) => any;\n feePayer?: PublicKey;\n }): Promise<MakeMultiTxData<T>> {\n if (\n this.scope.availability.removeStandardPosition === false ||\n this.scope.availability.createConcentratedPosition === false\n )\n this.logAndCreateError(\"remove liquidity or create position feature disabled in your region\");\n\n if (\n !(poolInfo.mintA.address === clmmPoolInfo.mintA.address || poolInfo.mintA.address === clmmPoolInfo.mintB.address)\n )\n throw Error(\"mint check error\");\n if (\n !(poolInfo.mintB.address === clmmPoolInfo.mintA.address || poolInfo.mintB.address === clmmPoolInfo.mintB.address)\n )\n throw Error(\"mint check error\");\n\n const txBuilder = this.createTxBuilder(feePayer);\n const mintToAccount: { [mint: string]: PublicKey } = {};\n for (const item of this.scope.account.tokenAccountRawInfos) {\n if (\n mintToAccount[item.accountInfo.mint.toString()] === undefined ||\n getATAAddress(this.scope.ownerPubKey, item.accountInfo.mint, TOKEN_PROGRAM_ID).publicKey.equals(item.pubkey)\n ) {\n mintToAccount[item.accountInfo.mint.toString()] = item.pubkey;\n }\n }\n\n const lpTokenAccount = mintToAccount[poolInfo.lpMint.address];\n if (lpTokenAccount === undefined) throw Error(\"find lp account error in trade accounts\");\n\n const amountIn = removeLpAmount.add(userFarmLpAmount ?? new BN(0));\n const mintBaseUseSOLBalance = poolInfo.mintA.address === Token.WSOL.mint.toString();\n const mintQuoteUseSOLBalance = poolInfo.mintB.address === Token.WSOL.mint.toString();\n\n const { account: baseTokenAccount, instructionParams: ownerTokenAccountBaseInstruction } =\n await this.scope.account.getOrCreateTokenAccount({\n tokenProgram: TOKEN_PROGRAM_ID,\n mint: new PublicKey(poolInfo.mintA.address),\n owner: this.scope.ownerPubKey,\n\n createInfo: mintBaseUseSOLBalance\n ? {\n payer: this.scope.ownerPubKey,\n }\n : undefined,\n skipCloseAccount: !mintBaseUseSOLBalance,\n notUseTokenAccount: mintBaseUseSOLBalance,\n associatedOnly: true,\n checkCreateATAOwner,\n });\n txBuilder.addInstruction(ownerTokenAccountBaseInstruction || {});\n if (baseTokenAccount === undefined) throw new Error(\"base token account not found\");\n\n const { account: quoteTokenAccount, instructionParams: ownerTokenAccountQuoteInstruction } =\n await this.scope.account.getOrCreateTokenAccount({\n tokenProgram: TOKEN_PROGRAM_ID,\n mint: new PublicKey(poolInfo.mintB.address),\n owner: this.scope.ownerPubKey,\n createInfo: mintQuoteUseSOLBalance\n ? {\n payer: this.scope.ownerPubKey!,\n amount: 0,\n }\n : undefined,\n skipCloseAccount: !mintQuoteUseSOLBalance,\n notUseTokenAccount: mintQuoteUseSOLBalance,\n associatedOnly: true,\n checkCreateATAOwner,\n });\n txBuilder.addInstruction(ownerTokenAccountQuoteInstruction || {});\n if (quoteTokenAccount === undefined) throw new Error(\"quote token account not found\");\n\n mintToAccount[poolInfo.mintA.address] = baseTokenAccount;\n mintToAccount[poolInfo.mintB.address] = quoteTokenAccount;\n\n if (farmInfo !== undefined && !userFarmLpAmount?.isZero()) {\n const farmVersion = FARM_PROGRAM_TO_VERSION[farmInfo.programId];\n const ledger = getAssociatedLedgerAccount({\n programId: new PublicKey(farmInfo.programId),\n poolId: new PublicKey(farmInfo.id),\n owner: this.scope.ownerPubKey,\n version: farmVersion as 3 | 5 | 6,\n });\n let ledgerInfo: FarmLedger | undefined = undefined;\n const ledgerData = await this.scope.connection.getAccountInfo(ledger);\n if (ledgerData) {\n const ledgerLayout = getFarmLedgerLayout(farmVersion)!;\n ledgerInfo = ledgerLayout.decode(ledgerData.data);\n }\n if (farmVersion !== 6 && !ledgerInfo) {\n const { instruction, instructionType } = createAssociatedLedgerAccountInstruction({\n id: new PublicKey(farmInfo.id),\n programId: new PublicKey(farmInfo.programId),\n version: farmVersion,\n ledger,\n owner: this.scope.ownerPubKey,\n });\n txBuilder.addInstruction({ instructions: [instruction], instructionTypes: [instructionType] });\n }\n\n const rewardTokenAccounts: PublicKey[] = [];\n for (const item of farmInfo.rewardInfos) {\n const rewardIsWsol = item.mint.address === Token.WSOL.mint.toString();\n if (mintToAccount[item.mint.address]) rewardTokenAccounts.push(mintToAccount[item.mint.address]);\n else {\n const { account: farmRewardAccount, instructionParams: ownerTokenAccountFarmInstruction } =\n await this.scope.account.getOrCreateTokenAccount({\n mint: new PublicKey(item.mint.address),\n tokenProgram,\n owner: this.scope.ownerPubKey,\n skipCloseAccount: !rewardIsWsol,\n createInfo: {\n payer: payer || this.scope.ownerPubKey,\n },\n associatedOnly: true,\n checkCreateATAOwner,\n });\n if (!farmRewardAccount) this.logAndCreateError(\"farm reward account not found:\", item.mint.address);\n ownerTokenAccountFarmInstruction && txBuilder.addInstruction(ownerTokenAccountFarmInstruction);\n rewardTokenAccounts.push(farmRewardAccount!);\n }\n }\n const farmKeys = (await this.scope.api.fetchFarmKeysById({ ids: farmInfo.id }))[0];\n const insParams = {\n userAuxiliaryLedgers,\n amount: userFarmLpAmount!,\n owner: this.scope.ownerPubKey,\n farmInfo,\n farmKeys,\n lpAccount: lpTokenAccount,\n rewardAccounts: rewardTokenAccounts,\n };\n const version = FARM_PROGRAM_TO_VERSION[farmInfo.programId];\n const newInstruction =\n version === 6\n ? makeWithdrawInstructionV6(insParams)\n : version === 5\n ? makeWithdrawInstructionV5(insParams)\n : makeWithdrawInstructionV3(insParams);\n const insType = {\n 3: InstructionType.FarmV3Withdraw,\n 5: InstructionType.FarmV5Withdraw,\n 6: InstructionType.FarmV6Withdraw,\n };\n txBuilder.addInstruction({\n instructions: [newInstruction],\n instructionTypes: [insType[version]],\n });\n }\n\n const poolKeys = await this.getAmmPoolKeys(poolInfo.id);\n\n const removeIns = removeLiquidityInstruction({\n poolInfo,\n poolKeys,\n userKeys: {\n lpTokenAccount,\n baseTokenAccount,\n quoteTokenAccount,\n owner: this.scope.ownerPubKey,\n },\n lpAmount: amountIn,\n baseAmountMin: 0,\n quoteAmountMin: 0,\n });\n\n txBuilder.addInstruction({\n instructions: [removeIns],\n instructionTypes: [\n !poolInfo.pooltype.includes(\"StablePool\")\n ? InstructionType.AmmV4RemoveLiquidity\n : InstructionType.AmmV5RemoveLiquidity,\n ],\n lookupTableAddress: poolKeys.lookupTableAccount ? [poolKeys.lookupTableAccount] : [],\n });\n\n const [tokenAccountA, tokenAccountB] =\n poolInfo.mintA.address === clmmPoolInfo.mintA.address\n ? [baseTokenAccount, quoteTokenAccount]\n : [quoteTokenAccount, baseTokenAccount];\n\n const clmmPoolKeys = await this.scope.clmm.getClmmPoolKeys(clmmPoolInfo.id);\n\n const createPositionIns = await ClmmInstrument.openPositionFromBaseInstructions({\n poolInfo: clmmPoolInfo,\n poolKeys: clmmPoolKeys,\n ownerInfo: {\n feePayer: this.scope.ownerPubKey,\n wallet: this.scope.ownerPubKey,\n tokenAccountA,\n tokenAccountB,\n },\n withMetadata: \"create\",\n ...createPositionInfo,\n base,\n getEphemeralSigners,\n });\n\n txBuilder.addInstruction({\n instructions: [...createPositionIns.instructions],\n signers: createPositionIns.signers,\n instructionTypes: [...createPositionIns.instructionTypes],\n lookupTableAddress: clmmPoolKeys.lookupTableAccount ? [clmmPoolKeys.lookupTableAccount] : [],\n });\n\n if (txVersion === TxVersion.V0)\n return txBuilder.sizeCheckBuildV0({ computeBudgetConfig }) as Promise<MakeMultiTxData<T>>;\n return txBuilder.sizeCheckBuild({ computeBudgetConfig }) as Promise<MakeMultiTxData<T>>;\n }\n\n public async createPoolV4<T extends TxVersion>({\n programId,\n marketInfo,\n baseMintInfo,\n quoteMintInfo,\n baseAmount,\n quoteAmount,\n startTime,\n ownerInfo,\n associatedOnly = false,\n checkCreateATAOwner = false,\n tokenProgram,\n txVersion,\n feeDestinationId,\n computeBudgetConfig,\n txTipConfig,\n feePayer,\n }: CreatePoolParam<T>): Promise<MakeTxData<T, { address: CreatePoolAddress }>> {\n const payer = ownerInfo.feePayer || this.scope.owner?.publicKey;\n const mintAUseSOLBalance = ownerInfo.useSOLBalance && baseMintInfo.mint.equals(NATIVE_MINT);\n const mintBUseSOLBalance = ownerInfo.useSOLBalance && quoteMintInfo.mint.equals(NATIVE_MINT);\n\n const txBuilder = this.createTxBuilder(feePayer);\n\n const { account: ownerTokenAccountBase, instructionParams: ownerTokenAccountBaseInstruction } =\n await this.scope.account.getOrCreateTokenAccount({\n mint: baseMintInfo.mint,\n owner: this.scope.ownerPubKey,\n createInfo: mintAUseSOLBalance\n ? {\n payer: payer!,\n amount: baseAmount,\n }\n : undefined,\n notUseTokenAccount: mintAUseSOLBalance,\n skipCloseAccount: !mintAUseSOLBalance,\n associatedOnly: mintAUseSOLBalance ? false : associatedOnly,\n checkCreateATAOwner,\n });\n txBuilder.addInstruction(ownerTokenAccountBaseInstruction || {});\n\n const { account: ownerTokenAccountQuote, instructionParams: ownerTokenAccountQuoteInstruction } =\n await this.scope.account.getOrCreateTokenAccount({\n mint: quoteMintInfo.mint,\n owner: this.scope.ownerPubKey,\n createInfo: mintBUseSOLBalance\n ? {\n payer: payer!,\n amount: quoteAmount,\n }\n : undefined,\n\n notUseTokenAccount: mintBUseSOLBalance,\n skipCloseAccount: !mintBUseSOLBalance,\n associatedOnly: mintBUseSOLBalance ? false : associatedOnly,\n checkCreateATAOwner,\n });\n txBuilder.addInstruction(ownerTokenAccountQuoteInstruction || {});\n\n if (ownerTokenAccountBase === undefined || ownerTokenAccountQuote === undefined)\n throw Error(\"you don't has some token account\");\n\n const poolInfo = getAssociatedPoolKeys({\n version: 4,\n marketVersion: 3,\n marketId: marketInfo.marketId,\n baseMint: baseMintInfo.mint,\n quoteMint: quoteMintInfo.mint,\n baseDecimals: baseMintInfo.decimals,\n quoteDecimals: quoteMintInfo.decimals,\n programId,\n marketProgramId: marketInfo.programId,\n });\n\n const createPoolKeys = {\n programId,\n ammId: poolInfo.id,\n ammAuthority: poolInfo.authority,\n ammOpenOrders: poolInfo.openOrders,\n lpMint: poolInfo.lpMint,\n coinMint: poolInfo.baseMint,\n pcMint: poolInfo.quoteMint,\n coinVault: poolInfo.baseVault,\n pcVault: poolInfo.quoteVault,\n withdrawQueue: poolInfo.withdrawQueue,\n ammTargetOrders: poolInfo.targetOrders,\n poolTempLp: poolInfo.lpVault,\n marketProgramId: poolInfo.marketProgramId,\n marketId: poolInfo.marketId,\n ammConfigId: poolInfo.configId,\n feeDestinationId,\n };\n\n const { instruction, instructionType } = createPoolV4InstructionV2({\n ...createPoolKeys,\n userWallet: this.scope.ownerPubKey,\n userCoinVault: ownerTokenAccountBase,\n userPcVault: ownerTokenAccountQuote,\n userLpVault: getATAAddress(this.scope.ownerPubKey, poolInfo.lpMint, tokenProgram).publicKey,\n\n nonce: poolInfo.nonce,\n openTime: startTime,\n coinAmount: baseAmount,\n pcAmount: quoteAmount,\n });\n\n txBuilder.addInstruction({\n instructions: [instruction],\n instructionTypes: [instructionType],\n });\n\n txBuilder.addCustomComputeBudget(computeBudgetConfig);\n txBuilder.addTipInstruction(txTipConfig);\n return txBuilder.versionBuild({\n txVersion,\n extInfo: {\n address: createPoolKeys,\n },\n }) as Promise<MakeTxData<T, { address: CreatePoolAddress }>>;\n }\n\n public async createMarketAndPoolV4<T extends TxVersion>({\n programId = AMM_V4,\n marketProgram = OPEN_BOOK_PROGRAM,\n feeDestinationId = FEE_DESTINATION_ID,\n tokenProgram,\n\n baseMintInfo,\n quoteMintInfo,\n baseAmount,\n quoteAmount,\n startTime,\n\n ownerInfo,\n lowestFeeMarket,\n assignSeed,\n\n associatedOnly = false,\n checkCreateATAOwner = false,\n\n lotSize = 1,\n tickSize = 0.01,\n\n txVersion,\n computeBudgetConfig,\n txTipConfig,\n feePayer,\n }: CreateMarketAndPoolParam<T>): Promise<\n MakeMultiTxData<T, { address: CreatePoolAddress & MarketExtInfo[\"address\"] }>\n > {\n const wallet = this.scope.ownerPubKey;\n const payer = ownerInfo.feePayer || this.scope.owner?.publicKey;\n const mintAUseSOLBalance = ownerInfo.useSOLBalance && baseMintInfo.mint.equals(NATIVE_MINT);\n const mintBUseSOLBalance = ownerInfo.useSOLBalance && quoteMintInfo.mint.equals(NATIVE_MINT);\n\n const seed = assignSeed\n ? `${baseMintInfo.mint.toBase58().slice(0, 7)}-${quoteMintInfo.mint.toBase58().slice(0, 7)}-${assignSeed}`\n : undefined;\n\n const market = generatePubKey({\n fromPublicKey: wallet,\n programId: marketProgram,\n assignSeed: seed ? `${seed}-market` : seed,\n });\n const requestQueue = generatePubKey({\n fromPublicKey: wallet,\n programId: marketProgram,\n assignSeed: seed ? `${seed}-request` : seed,\n });\n const eventQueue = generatePubKey({\n fromPublicKey: wallet,\n programId: marketProgram,\n assignSeed: seed ? `${seed}-event` : seed,\n });\n const bids = generatePubKey({\n fromPublicKey: wallet,\n programId: marketProgram,\n assignSeed: seed ? `${seed}-bids` : seed,\n });\n const asks = generatePubKey({\n fromPublicKey: wallet,\n programId: marketProgram,\n assignSeed: seed ? `${seed}-asks` : seed,\n });\n const baseVault = generatePubKey({\n fromPublicKey: wallet,\n programId: TOKEN_PROGRAM_ID,\n assignSeed: seed ? `${seed}-baseVault` : seed,\n });\n const quoteVault = generatePubKey({\n fromPublicKey: wallet,\n programId: TOKEN_PROGRAM_ID,\n assignSeed: seed ? `${seed}-quoteVault` : seed,\n });\n\n const feeRateBps = 0;\n const quoteDustThreshold = new BN(100);\n function getVaultOwnerAndNonce() {\n const vaultSignerNonce = new BN(0);\n // eslint-disable-next-line no-constant-condition\n while (true) {\n try {\n const vaultOwner = PublicKey.createProgramAddressSync(\n [market.publicKey.toBuffer(), vaultSignerNonce.toArrayLike(Buffer, \"le\", 8)],\n marketProgram,\n );\n return { vaultOwner, vaultSignerNonce };\n } catch (e) {\n vaultSignerNonce.iaddn(1);\n if (vaultSignerNonce.gt(new BN(25555))) throw Error(\"find vault owner error\");\n }\n }\n }\n const { vaultOwner, vaultSignerNonce } = getVaultOwnerAndNonce();\n const baseLotSize = new BN(Math.round(10 ** baseMintInfo.decimals * lotSize));\n const quoteLotSize = new BN(Math.round(lotSize * 10 ** quoteMintInfo.decimals * tickSize));\n\n if (baseLotSize.eq(BN_ZERO)) throw Error(\"lot size is too small\");\n if (quoteLotSize.eq(BN_ZERO)) throw Error(\"tick size or lot size is too small\");\n const allTxArr = await makeCreateMarketInstruction({\n connection: this.scope.connection,\n wallet: this.scope.ownerPubKey,\n marketInfo: {\n programId: marketProgram,\n vaultOwner,\n baseMint: baseMintInfo.mint,\n quoteMint: quoteMintInfo.mint,\n\n id: market,\n baseVault,\n quoteVault,\n requestQueue,\n eventQueue,\n bids,\n asks,\n\n feeRateBps,\n quoteDustThreshold,\n vaultSignerNonce,\n baseLotSize,\n quoteLotSize,\n lowestFeeMarket,\n },\n });\n\n const txBuilder = this.createTxBuilder(feePayer);\n txBuilder.addInstruction({\n instructions: allTxArr[0].transaction.instructions,\n signers: allTxArr[0].signer,\n });\n\n for await (const txData of allTxArr.slice(1, allTxArr.length)) {\n txBuilder.addInstruction({\n instructions: txData.transaction.instructions,\n signers: txData.signer,\n instructionTypes: txData.instructionTypes,\n });\n }\n\n const { account: ownerTokenAccountBase, instructionParams: ownerTokenAccountBaseInstruction } =\n await this.scope.account.getOrCreateTokenAccount({\n mint: baseMintInfo.mint,\n owner: this.scope.ownerPubKey,\n createInfo: mintAUseSOLBalance\n ? {\n payer: payer!,\n amount: baseAmount,\n }\n : undefined,\n notUseTokenAccount: mintAUseSOLBalance,\n skipCloseAccount: !mintAUseSOLBalance,\n associatedOnly: mintAUseSOLBalance ? false : associatedOnly,\n checkCreateATAOwner,\n assignSeed: mintAUseSOLBalance && seed ? `${seed}-wsol` : undefined,\n });\n\n txBuilder.addInstruction(ownerTokenAccountBaseInstruction || {});\n\n const { account: ownerTokenAccountQuote, instructionParams: ownerTokenAccountQuoteInstruction } =\n await this.scope.account.getOrCreateTokenAccount({\n mint: quoteMintInfo.mint,\n owner: this.scope.ownerPubKey,\n createInfo: mintBUseSOLBalance\n ? {\n payer: payer!,\n amount: quoteAmount,\n }\n : undefined,\n\n notUseTokenAccount: mintBUseSOLBalance,\n skipCloseAccount: !mintBUseSOLBalance,\n associatedOnly: mintBUseSOLBalance ? false : associatedOnly,\n checkCreateATAOwner,\n assignSeed: mintBUseSOLBalance && seed ? `${seed}-wsol` : undefined,\n });\n txBuilder.addInstruction(ownerTokenAccountQuoteInstruction || {});\n\n if (ownerTokenAccountBase === undefined) throw Error(\"you don't has base token account\");\n if (ownerTokenAccountQuote === undefined) throw Error(\"you don't has quote token account\");\n\n // create pool ins\n const poolInfo = getAssociatedPoolKeys({\n version: 4,\n marketVersion: 3,\n marketId: market.publicKey,\n baseMint: baseMintInfo.mint,\n quoteMint: quoteMintInfo.mint,\n baseDecimals: baseMintInfo.decimals,\n quoteDecimals: quoteMintInfo.decimals,\n programId,\n marketProgramId: marketProgram,\n });\n\n const createPoolKeys = {\n programId,\n ammId: poolInfo.id,\n ammAuthority: poolInfo.authority,\n ammOpenOrders: poolInfo.openOrders,\n lpMint: poolInfo.lpMint,\n coinMint: poolInfo.baseMint,\n pcMint: poolInfo.quoteMint,\n coinVault: poolInfo.baseVault,\n pcVault: poolInfo.quoteVault,\n withdrawQueue: poolInfo.withdrawQueue,\n ammTargetOrders: poolInfo.targetOrders,\n poolTempLp: poolInfo.lpVault,\n marketProgramId: poolInfo.marketProgramId,\n marketId: poolInfo.marketId,\n ammConfigId: poolInfo.configId,\n feeDestinationId,\n };\n\n const { instruction, instructionType } = createPoolV4InstructionV2({\n ...createPoolKeys,\n userWallet: this.scope.ownerPubKey,\n userCoinVault: ownerTokenAccountBase,\n userPcVault: ownerTokenAccountQuote,\n userLpVault: getATAAddress(this.scope.ownerPubKey, poolInfo.lpMint, tokenProgram).publicKey,\n\n nonce: poolInfo.nonce,\n openTime: startTime,\n coinAmount: baseAmount,\n pcAmount: quoteAmount,\n });\n\n txBuilder.addInstruction({\n instructions: [instruction],\n instructionTypes: [instructionType],\n });\n\n const splitIns =\n mintAUseSOLBalance || mintBUseSOLBalance\n ? ([\n ownerTokenAccountBaseInstruction?.instructions?.[0] || ownerTokenAccountQuoteInstruction?.instructions?.[0],\n ].filter((i) => !!i) as TransactionInstruction[])\n : undefined;\n\n if (txVersion === TxVersion.V0)\n return txBuilder.sizeCheckBuildV0({\n computeBudgetConfig,\n splitIns,\n address: {\n requestQueue: requestQueue.publicKey,\n eventQueue: eventQueue.publicKey,\n bids: bids.publicKey,\n asks: asks.publicKey,\n baseVault: baseVault.publicKey,\n quoteVault: quoteVault.publicKey,\n baseMint: new PublicKey(baseMintInfo.mint),\n quoteMint: new PublicKey(quoteMintInfo.mint),\n ...createPoolKeys,\n },\n }) as Promise<MakeMultiTxData<T, { address: CreatePoolAddress & MarketExtInfo[\"address\"] }>>;\n\n return txBuilder.sizeCheckBuild({\n computeBudgetConfig,\n splitIns,\n address: {\n requestQueue: requestQueue.publicKey,\n eventQueue: eventQueue.publicKey,\n bids: bids.publicKey,\n asks: asks.publicKey,\n baseVault: baseVault.publicKey,\n quoteVault: quoteVault.publicKey,\n baseMint: new PublicKey(baseMintInfo.mint),\n quoteMint: new PublicKey(quoteMintInfo.mint),\n ...createPoolKeys,\n },\n }) as Promise<MakeMultiTxData<T, { address: CreatePoolAddress & MarketExtInfo[\"address\"] }>>;\n }\n\n public async getCreatePoolFee({ programId }: { programId: PublicKey }): Promise<BN> {\n const configId = getAssociatedConfigId({ programId });\n\n const account = await this.scope.connection.getAccountInfo(configId, { dataSlice: { offset: 536, length: 8 } });\n if (account === null) throw Error(\"get config account error\");\n\n return createPoolFeeLayout.decode(account.data).fee;\n }\n\n public computeAmountOut({\n poolInfo,\n amountIn,\n mintIn: propMintIn,\n mintOut: propMintOut,\n slippage,\n }: ComputeAmountOutParam): {\n amountOut: BN;\n minAmountOut: BN;\n currentPrice: Decimal;\n executionPrice: Decimal;\n priceImpact: Decimal;\n fee: BN;\n } {\n const [mintIn, mintOut] = [propMintIn.toString(), propMintOut.toString()];\n if (mintIn !== poolInfo.mintA.address && mintIn !== poolInfo.mintB.address) throw new Error(\"toke not match\");\n if (mintOut !== poolInfo.mintA.address && mintOut !== poolInfo.mintB.address) throw new Error(\"toke not match\");\n\n const { baseReserve, quoteReserve } = poolInfo;\n\n const reserves = [baseReserve, quoteReserve];\n const mintDecimals = [poolInfo.mintA.decimals, poolInfo.mintB.decimals];\n\n // input is fixed\n const input = mintIn == poolInfo.mintA.address ? \"base\" : \"quote\";\n if (input === \"quote\") {\n reserves.reverse();\n mintDecimals.reverse();\n }\n\n const [reserveIn, reserveOut] = reserves;\n const [mintInDecimals, mintOutDecimals] = mintDecimals;\n const isVersion4 = poolInfo.version === 4;\n let currentPrice: Decimal;\n if (isVersion4) {\n currentPrice = new Decimal(reserveOut.toString())\n .div(10 ** mintOutDecimals)\n .div(new Decimal(reserveIn.toString()).div(10 ** mintInDecimals));\n } else {\n const p = getStablePrice(\n this.stableLayout.stableModelData,\n baseReserve.toNumber(),\n quoteReserve.toNumber(),\n false,\n );\n if (input === \"quote\") currentPrice = new Decimal(1e6).div(p * 1e6);\n else currentPrice = new Decimal(p * 1e6).div(1e6);\n }\n\n const amountInRaw = amountIn;\n let amountOutRaw = new BN(0);\n let feeRaw = new BN(0);\n\n if (!amountInRaw.isZero()) {\n if (isVersion4) {\n feeRaw = BNDivCeil(amountInRaw.mul(LIQUIDITY_FEES_NUMERATOR), LIQUIDITY_FEES_DENOMINATOR);\n const amountInWithFee = amountInRaw.sub(feeRaw);\n\n const denominator = reserveIn.add(amountInWithFee);\n amountOutRaw = reserveOut.mul(amountInWithFee).div(denominator);\n } else {\n feeRaw = amountInRaw.mul(new BN(2)).div(new BN(10000));\n const amountInWithFee = amountInRaw.sub(feeRaw);\n if (input === \"quote\")\n amountOutRaw = new BN(\n getDyByDxBaseIn(\n this.stableLayout.stableModelData,\n quoteReserve.toNumber(),\n baseReserve.toNumber(),\n amountInWithFee.toNumber(),\n ),\n );\n else {\n amountOutRaw = new BN(\n getDxByDyBaseIn(\n this.stableLayout.stableModelData,\n quoteReserve.toNumber(),\n baseReserve.toNumber(),\n amountInWithFee.toNumber(),\n ),\n );\n }\n }\n }\n\n const minAmountOutRaw = new BN(new Decimal(amountOutRaw.toString()).mul(1 - slippage).toFixed(0));\n\n const amountOut = amountOutRaw;\n const minAmountOut = minAmountOutRaw;\n\n let executionPrice = new Decimal(amountOutRaw.toString()).div(\n new Decimal(amountInRaw.sub(feeRaw).toString()).toFixed(0),\n );\n if (!amountInRaw.isZero() && !amountOutRaw.isZero()) {\n executionPrice = new Decimal(amountOutRaw.toString())\n .div(10 ** mintOutDecimals)\n .div(new Decimal(amountInRaw.sub(feeRaw).toString()).div(10 ** mintInDecimals));\n }\n\n const priceImpact = currentPrice.sub(executionPrice).div(currentPrice).mul(100);\n\n const fee = feeRaw;\n\n return {\n amountOut,\n minAmountOut,\n currentPrice,\n executionPrice,\n priceImpact,\n fee,\n };\n }\n\n public computeAmountIn({ poolInfo, amountOut, mintIn, mintOut, slippage }: ComputeAmountInParam): {\n amountIn: BN;\n maxAmountIn: BN;\n currentPrice: Decimal;\n executionPrice: Decimal | null;\n priceImpact: Decimal;\n } {\n const { baseReserve, quoteReserve } = poolInfo;\n if (mintIn.toString() !== poolInfo.mintA.address && mintIn.toString() !== poolInfo.mintB.address)\n this.logAndCreateError(\"mintIn does not match pool\");\n if (mintOut.toString() !== poolInfo.mintA.address && mintOut.toString() !== poolInfo.mintB.address)\n this.logAndCreateError(\"mintOut does not match pool\");\n this.logDebug(\"baseReserve:\", baseReserve.toString());\n this.logDebug(\"quoteReserve:\", quoteReserve.toString());\n\n const baseIn = mintIn.toString() === poolInfo.mintA.address;\n const [tokenIn, tokenOut] = baseIn ? [poolInfo.mintA, poolInfo.mintB] : [poolInfo.mintB, poolInfo.mintA];\n\n this.logDebug(\"currencyOut:\", tokenOut.symbol || tokenOut.address);\n this.logDebug(\n \"amountOut:\",\n new Decimal(amountOut.toString())\n .div(10 ** tokenOut.decimals)\n .toDecimalPlaces(tokenOut.decimals)\n .toString(),\n tokenIn.symbol || tokenIn.address,\n );\n this.logDebug(\"slippage:\", `${slippage * 100}%`);\n\n const reserves = [baseReserve, quoteReserve];\n\n // output is fixed\n const output = !baseIn ? \"base\" : \"quote\";\n if (output === \"base\") {\n reserves.reverse();\n }\n this.logDebug(\"output side:\", output);\n\n const [reserveIn, reserveOut] = reserves;\n\n const currentPrice = new Decimal(reserveOut.toString())\n .div(10 ** poolInfo[baseIn ? \"mintB\" : \"mintA\"].decimals)\n .div(new Decimal(reserveIn.toString()).div(10 ** poolInfo[baseIn ? \"mintA\" : \"mintB\"].decimals));\n this.logDebug(\n \"currentPrice:\",\n `1 ${tokenIn.symbol || tokenIn.address} ≈ ${currentPrice.toString()} ${tokenOut.symbol || tokenOut.address}`,\n );\n this.logDebug(\n \"currentPrice invert:\",\n `1 ${tokenOut.symbol || tokenOut.address} ≈ ${new Decimal(1).div(currentPrice).toString()} ${\n tokenIn.symbol || tokenIn.address\n }`,\n );\n\n let amountInRaw = new BN(0);\n let amountOutRaw = amountOut;\n if (!amountOutRaw.isZero()) {\n // if out > reserve, out = reserve - 1\n if (amountOutRaw.gt(reserveOut)) {\n amountOutRaw = reserveOut.sub(new BN(1));\n }\n\n const denominator = reserveOut.sub(amountOutRaw);\n const amountInWithoutFee = reserveIn.mul(amountOutRaw).div(denominator);\n\n amountInRaw = amountInWithoutFee\n .mul(LIQUIDITY_FEES_DENOMINATOR)\n .div(LIQUIDITY_FEES_DENOMINATOR.sub(LIQUIDITY_FEES_NUMERATOR));\n }\n\n const maxAmountInRaw = new BN(new Decimal(amountInRaw.toString()).mul(1 + slippage).toFixed(0));\n\n const amountIn = amountInRaw;\n const maxAmountIn = maxAmountInRaw;\n this.logDebug(\n \"amountIn:\",\n new Decimal(amountIn.toString())\n .div(10 ** tokenIn.decimals)\n .toDecimalPlaces(tokenIn.decimals)\n .toString(),\n );\n this.logDebug(\n \"maxAmountIn:\",\n new Decimal(maxAmountIn.toString())\n .div(10 ** tokenIn.decimals)\n .toDecimalPlaces(tokenIn.decimals)\n .toString(),\n );\n\n let executionPrice: Decimal | null = null;\n if (!amountInRaw.isZero() && !amountOutRaw.isZero()) {\n executionPrice = new Decimal(amountOutRaw.toString())\n .div(10 ** tokenOut.decimals)\n .div(new Decimal(amountInRaw.toString()).div(10 ** tokenIn.decimals));\n this.logDebug(\n \"executionPrice:\",\n `1 ${tokenOut.symbol || tokenOut.address} ≈ ${executionPrice\n .toDecimalPlaces(Math.max(poolInfo.mintA.decimals, poolInfo.mintB.decimals))\n .toString()} ${tokenIn.symbol || tokenIn.address}`,\n );\n this.logDebug(\n \"executionPrice invert:\",\n `1 ${tokenOut.symbol || tokenOut.address} ≈ ${new Decimal(1)\n .div(executionPrice)\n .toDecimalPlaces(Math.max(poolInfo.mintA.decimals, poolInfo.mintB.decimals))\n .toString()} ${tokenIn.symbol || tokenIn.address}`,\n );\n }\n\n const exactQuote = currentPrice.mul(amountIn.toString());\n const priceImpact = exactQuote.sub(amountOut.toString()).abs().div(exactQuote);\n this.logDebug(\"priceImpact:\", `${priceImpact.toString()}%`);\n\n return {\n amountIn,\n maxAmountIn,\n currentPrice,\n executionPrice,\n priceImpact,\n };\n }\n\n public async swap<T extends TxVersion>({\n poolInfo,\n poolKeys: propPoolKeys,\n amountIn,\n amountOut,\n inputMint,\n fixedSide,\n txVersion,\n config,\n computeBudgetConfig,\n txTipConfig,\n feePayer,\n }: SwapParam<T>): Promise<MakeTxData<T>> {\n const txBuilder = this.createTxBuilder(feePayer);\n const { associatedOnly = true, inputUseSolBalance = true, outputUseSolBalance = true } = config || {};\n\n const [tokenIn, tokenOut] =\n inputMint === poolInfo.mintA.address ? [poolInfo.mintA, poolInfo.mintB] : [poolInfo.mintB, poolInfo.mintA];\n\n const inputTokenUseSolBalance = inputUseSolBalance && tokenIn.address === WSOLMint.toBase58();\n const outputTokenUseSolBalance = outputUseSolBalance && tokenOut.address === WSOLMint.toBase58();\n\n const { account: _tokenAccountIn, instructionParams: ownerTokenAccountBaseInstruction } =\n await this.scope.account.getOrCreateTokenAccount({\n tokenProgram: TOKEN_PROGRAM_ID,\n mint: new PublicKey(tokenIn.address),\n owner: this.scope.ownerPubKey,\n\n createInfo: inputTokenUseSolBalance\n ? {\n payer: this.scope.ownerPubKey,\n amount: amountIn,\n }\n : undefined,\n skipCloseAccount: !inputTok