goosefx-amm-sdk
Version:
SDK for the GooseFx AMM
1 lines • 473 kB
Source Map (JSON)
{"version":3,"sources":["../../../src/gfx/cpmm/cpmm.ts","../../../src/module/amount.ts","../../../src/common/number.ts","../../../src/common/logger.ts","../../../src/module/formatter.ts","../../../src/module/fraction.ts","../../../src/gfx/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/txTool/txType.ts","../../../src/gfx/cpmm/curve/calculator.ts","../../../src/gfx/cpmm/curve/fee.ts","../../../src/gfx/cpmm/curve/common.ts","../../../src/gfx/cpmm/curve/constantProduct.ts","../../../src/common/txTool/txTool.ts","../../../src/common/txTool/txUtils.ts","../../../src/common/txTool/lookupTable.ts","../../../src/common/accountInfo.ts","../../../src/common/utility.ts","../../../src/common/bignumber.ts","../../../node_modules/decimal.js/decimal.mjs","../../../src/common/lodash.ts","../../../src/common/programId.ts","../../../src/common/pda.ts","../../../src/common/transfer.ts","../../../src/gfx/moduleBase.ts","../../../src/gfx/cpmm/pda.ts","../../../src/gfx/cpmm/instruction.ts","../../../src/gfx/token/utils.ts","../../../src/gfx/cpmm/kamino.ts"],"sourcesContent":["import { PublicKey, SystemProgram } from \"@solana/web3.js\";\nimport { NATIVE_MINT, TOKEN_PROGRAM_ID, createSyncNativeInstruction } from \"@solana/spl-token\";\nimport { PoolInfo, PoolKeys, PoolStats } from \"@/api/type\";\nimport { Percent } from \"@/module\";\nimport { BN_ZERO } from \"@/common/number\";\nimport { WSOLMint } from \"@/common/pubKey\";\nimport { InstructionType, TxVersion } from \"@/common/txTool/txType\";\nimport { MakeTxData } from \"@/common/txTool/txTool\";\nimport { CurveCalculator, RoundDirection } from \"./curve/calculator\";\n\nimport ModuleBase, { ModuleBaseProps } from \"../moduleBase\";\nimport {\n CreateCpmmPoolParam,\n CreateCpmmPoolAddress,\n AddCpmmLiquidityParams,\n WithdrawCpmmLiquidityParams,\n CpmmSwapParams,\n ComputePairAmountParams,\n CpmmRpcData,\n CpmmComputeData,\n UserLiquidityAccount,\n CpmmObservationState,\n CpmmPool,\n CpmmPoolPartners,\n CpmmConfig,\n} from \"./type\";\nimport { getCreatePoolKeys, getPdaObservationId, getPdaPoolPartners, getPdaUserLiquidity } from \"./pda\";\nimport {\n makeCreateCpmmPoolInInstruction,\n makeDepositCpmmInInstruction,\n makeInitUserPoolLiquidityInstruction,\n makeWithdrawCpmmInInstruction,\n makeSwapCpmmBaseInInstruction,\n makeSwapCpmmBaseOutInstruction,\n makeSwapCpmmOracleBaseInInstruction,\n makeInitializePartnerInstruction,\n makeAddPartnerInstruction,\n} from \"./instruction\";\nimport BN from \"bn.js\";\nimport Decimal from \"decimal.js\";\nimport { fetchMultipleMintInfos, getTransferAmountFeeV2 } from \"@/common\";\nimport { ComputeBudgetConfig, GetTransferAmountFee, ReturnTypeFetchMultipleMintInfos } from \"@/gfx/type\";\nimport { toGammaApiToken, toFeeConfig, SOL_INFO } from \"../token\";\nimport { getPdaPoolAuthority } from \"./pda\";\nimport { ConstantProductCurve } from \"./curve/constantProduct\";\nimport { Program } from \"@coral-xyz/anchor\";\nimport { Gamma } from \"../idl/gamma.type\";\nimport { getReserveAccountsForWithdraw, getReservesForMarket, KaminoReserve } from \"./kamino\";\n\nexport default class CpmmModule extends ModuleBase {\n private program: Program<Gamma>;\n private kamino?: {\n market?: PublicKey;\n programId?: PublicKey;\n };\n /** map of liquidity mint to kamino reserve */\n private reserves: Map<string, KaminoReserve>;\n\n constructor(params: ModuleBaseProps) {\n super(params);\n this.program = params.scope.program;\n this.kamino = params.scope.kamino;\n this.reserves = new Map();\n }\n\n public async load(): Promise<void> {\n this.checkDisabled();\n }\n\n public async getCpmmPoolKeys(poolId: string): Promise<PoolKeys> {\n return ((await this.scope.api.fetchPoolKeysById({ idList: [poolId] })) as PoolKeys[])[0];\n }\n\n public async getRpcPoolInfo(poolId: string, fetchConfigInfo?: boolean): Promise<CpmmRpcData> {\n return (await this.getRpcPoolInfos([poolId], fetchConfigInfo))[poolId];\n }\n\n public async getTotalDepositsByPartner(\n poolIds: string[],\n partner: PublicKey,\n ): Promise<{\n [poolId: string]: {\n totalInvestedThoughPartnerToken0: BN;\n totalInvestedThoughPartnerToken1: BN;\n totalLpTokensLinked: BN;\n };\n }> {\n const partnerIds = poolIds.map((id) => getPdaPoolPartners(this.program.programId, new PublicKey(id)).publicKey);\n const poolInfos = await this.program.account.poolState.fetchMultiple(poolIds);\n const partnerInfos = await this.program.account.poolPartnerInfos.fetchMultiple(partnerIds);\n\n const returnData: {\n [poolId: string]: {\n totalInvestedThoughPartnerToken0: BN;\n totalInvestedThoughPartnerToken1: BN;\n totalLpTokensLinked: BN;\n };\n } = {};\n\n for (let i = 0; i < poolIds.length; i++) {\n const pool = poolInfos[i];\n const partners = partnerInfos[i];\n if (pool === null) throw Error(\"fetch pool info error: \" + poolIds[i]);\n if (partners === null) throw Error(\"fetch poolPartners info error: \" + partnerIds[i]);\n const { token0, token1, lp } = await this.getTokenInvestedByPartner(pool, partners, partner);\n\n returnData[poolIds[i]] = {\n totalInvestedThoughPartnerToken0: token0,\n totalInvestedThoughPartnerToken1: token1,\n totalLpTokensLinked: lp,\n };\n }\n\n return returnData;\n }\n\n public async getTokenInvestedByPartner(\n poolInfo: CpmmPool,\n partnerInfo: CpmmPoolPartners,\n partner: PublicKey,\n ): Promise<{ token0: BN; token1: BN; lp: BN }> {\n const lpTokensLinked =\n partnerInfo.infos.find((info) => info.partner.toBase58() === partner.toBase58())?.lpTokenLinkedWithPartner ??\n new BN(0);\n if (lpTokensLinked.eqn(0)) {\n return { token0: new BN(0), token1: new BN(0), lp: new BN(0) };\n }\n const lpToTradingToken = ConstantProductCurve.lpTokensToTradingTokens(\n lpTokensLinked,\n poolInfo.lpSupply,\n poolInfo.token0VaultAmount,\n poolInfo.token1VaultAmount,\n RoundDirection.Floor,\n );\n return {\n token0: lpToTradingToken.tokenAmount0,\n token1: lpToTradingToken.tokenAmount1,\n lp: lpTokensLinked,\n };\n }\n\n public async getRpcPoolInfos(\n poolIds: string[],\n fetchConfigInfo?: boolean,\n ): Promise<{\n [poolId: string]: CpmmRpcData;\n }> {\n const partnerIds = poolIds.map((id) => getPdaPoolPartners(this.program.programId, new PublicKey(id)).publicKey);\n const observationIds = poolIds.map(\n (id) => getPdaObservationId(this.program.programId, new PublicKey(id)).publicKey,\n );\n\n const [accounts, partnerInfos, observations] = await Promise.all([\n this.program.account.poolState.fetchMultiple(poolIds),\n this.program.account.poolPartnerInfos.fetchMultiple(partnerIds),\n this.program.account.observationState.fetchMultiple(observationIds),\n ]);\n\n const poolInfos: {\n [poolId: string]: CpmmPool & {\n observationAccount: CpmmObservationState;\n partnerInfo: CpmmPoolPartners;\n programId: PublicKey;\n };\n } = {};\n\n const needFetchConfigId = new Set<string>();\n\n for (let i = 0; i < poolIds.length; i++) {\n const rpc = accounts[i];\n const partnerInfo = partnerInfos[i];\n const observationAccount = observations[i];\n if (rpc === null) throw Error(\"fetch pool info error: \" + String(poolIds[i]));\n if (partnerInfo === null) throw Error(\"failed to fetch poolPartners for pool: \" + poolIds[i]);\n if (observationAccount === null) throw Error(\"failed to fetch observation for pool: \" + poolIds[i]);\n\n poolInfos[String(poolIds[i])] = {\n ...rpc,\n partnerInfo,\n observationAccount,\n programId: this.program.programId,\n };\n needFetchConfigId.add(String(rpc.ammConfig));\n }\n\n const configInfo: { [configId: string]: CpmmConfig } = {};\n\n if (fetchConfigInfo) {\n const configIds = [...needFetchConfigId];\n const configs = await this.program.account.ammConfig.fetchMultiple(configIds);\n\n for (let i = 0; i < configIds.length; i++) {\n const configItemInfo = configs[i];\n if (configItemInfo === null) throw Error(\"fetch pool config error: \" + configIds[i]);\n configInfo[configIds[i]] = configItemInfo;\n }\n }\n\n const returnData: { [poolId: string]: CpmmRpcData } = {};\n\n for (const [id, info] of Object.entries(poolInfos)) {\n const baseReserve = info.token0VaultAmount;\n const quoteReserve = info.token1VaultAmount;\n returnData[id] = {\n ...info,\n baseReserve: info.token0VaultAmount,\n quoteReserve: info.token1VaultAmount,\n vaultAAmount: info.token0VaultAmount\n .add(info.protocolFeesToken0)\n .add(info.fundFeesToken0)\n .add(info.partnerProtocolFeesToken0),\n vaultBAmount: info.token1VaultAmount\n .add(info.protocolFeesToken1)\n .add(info.fundFeesToken1)\n .add(info.partnerProtocolFeesToken1),\n configInfo: configInfo[info.ammConfig.toString()],\n poolPrice: new Decimal(quoteReserve.toString())\n .div(new Decimal(10).pow(info.mint1Decimals))\n .div(new Decimal(baseReserve.toString()).div(new Decimal(10).pow(info.mint0Decimals))),\n };\n }\n\n return returnData;\n }\n\n public toComputePoolInfos({\n pools,\n mintInfos,\n }: {\n pools: Record<string, CpmmRpcData>;\n mintInfos: ReturnTypeFetchMultipleMintInfos;\n }): Record<string, CpmmComputeData> {\n return Object.keys(pools).reduce((acc, cur) => {\n const pool = pools[cur];\n const [mintA, mintB] = [pool.token0Mint.toBase58(), pool.token1Mint.toBase58()];\n\n return {\n ...acc,\n [cur]: {\n ...pool,\n id: new PublicKey(cur),\n configInfo: pool.configInfo!,\n version: 7 as const,\n authority: getPdaPoolAuthority(pool.programId).publicKey,\n mintA: toGammaApiToken({\n address: mintA,\n decimals: pool.mint0Decimals,\n programId: pool.token0Program.toBase58(),\n extensions: {\n feeConfig: mintInfos[mintA]?.feeConfig ? toFeeConfig(mintInfos[mintA]?.feeConfig) : undefined,\n },\n }),\n mintB: toGammaApiToken({\n address: mintB,\n decimals: pool.mint1Decimals,\n programId: pool.token1Program.toBase58(),\n extensions: {\n feeConfig: mintInfos[mintB]?.feeConfig ? toFeeConfig(mintInfos[mintB]?.feeConfig) : undefined,\n },\n }),\n },\n };\n }, {} as Record<string, CpmmComputeData>);\n }\n\n public async getPoolInfoFromRpc(poolId: string): Promise<{\n poolInfo: PoolInfo;\n poolKeys: PoolKeys;\n rpcData: CpmmRpcData;\n }> {\n const rpcData = await this.getRpcPoolInfo(poolId, true);\n const partnerKeys = rpcData\n .partnerInfo!.infos.map((i) => i.partner.toBase58())\n .filter((i) => i !== PublicKey.default.toBase58());\n const partners =\n partnerKeys.length > 0\n ? await this.program.account.partner.fetchMultiple(partnerKeys).then((res) =>\n res\n .filter((r) => r !== null)\n .map((r, index) => {\n return {\n acc: r,\n address: partnerKeys[index],\n };\n }),\n )\n : [];\n\n const mintInfos = await fetchMultipleMintInfos({\n connection: this.scope.connection,\n mints: [rpcData.token0Mint, rpcData.token1Mint],\n });\n\n const mintA = toGammaApiToken({\n address: rpcData.token0Mint.toBase58(),\n decimals: rpcData.mint0Decimals,\n programId: rpcData.token0Program.toBase58(),\n extensions: {\n feeConfig: mintInfos[rpcData.token0Mint.toBase58()].feeConfig\n ? toFeeConfig(mintInfos[rpcData.token0Mint.toBase58()].feeConfig)\n : undefined,\n },\n });\n const mintB = toGammaApiToken({\n address: rpcData.token1Mint.toBase58(),\n decimals: rpcData.mint1Decimals,\n programId: rpcData.token1Program.toBase58(),\n extensions: {\n feeConfig: mintInfos[rpcData.token1Mint.toBase58()].feeConfig\n ? toFeeConfig(mintInfos[rpcData.token1Mint.toBase58()].feeConfig)\n : undefined,\n },\n });\n\n const configInfo = {\n id: rpcData.ammConfig.toBase58(),\n index: rpcData.configInfo!.index,\n protocolFeeRate: rpcData.configInfo!.protocolFeeRate.toNumber(),\n tradeFeeRate: rpcData.configInfo!.tradeFeeRate.toNumber(),\n fundFeeRate: rpcData.configInfo!.fundFeeRate.toNumber(),\n createPoolFee: rpcData.configInfo!.createPoolFee.toString(),\n protocolOwner: rpcData.configInfo!.protocolOwner.toString(),\n fundOwner: rpcData.configInfo!.fundOwner.toString(),\n };\n\n const mockPoolStats: PoolStats = {\n range: \"24H\",\n feesUsd: 0,\n volumeTokenAUsd: 0,\n volumeTokenBUsd: 0,\n feesAprUsd: 0,\n volumeAprUsd: 0,\n withdrawnKaminoProfitTokenAUsd: 0,\n withdrawnKaminoProfitTokenBUsd: 0,\n withdrawnKaminoProfitTokenAAprUsd: 0,\n withdrawnKaminoProfitTokenBAprUsd: 0,\n };\n\n return {\n poolInfo: {\n programId: rpcData.programId.toBase58(),\n id: poolId,\n config: configInfo,\n mintA,\n mintB,\n price: rpcData.poolPrice.toString(),\n liquidityTokenA: new Decimal(rpcData.vaultAAmount.toString()).div(10 ** mintA.decimals).toString(),\n liquidityTokenB: new Decimal(rpcData.vaultBAmount.toString()).div(10 ** mintB.decimals).toString(),\n lpSupply: rpcData.lpSupply.toString(),\n poolCreator: rpcData.poolCreator.toBase58(),\n poolType: \"hyper\",\n mintAVault: rpcData.token0Vault.toBase58(),\n mintBVault: rpcData.token1Vault.toBase58(),\n authority: getPdaPoolAuthority(rpcData.programId).publicKey.toBase58(),\n openTime: rpcData.openTime.toString(),\n tvl: \"0\",\n stats: {\n daily: mockPoolStats,\n weekly: mockPoolStats,\n monthly: mockPoolStats,\n },\n partners: partners.map((p) => {\n return {\n address: p.address,\n name: p.acc.name,\n authority: p.acc.authority.toBase58(),\n token0TokenAccount: p.acc.token0TokenAccount.toBase58(),\n token1TokenAccount: p.acc.token1TokenAccount.toBase58(),\n };\n }),\n },\n poolKeys: {\n programId: rpcData.programId.toBase58(),\n id: poolId,\n mintA: mintA.address,\n mintB: mintB.address,\n openTime: rpcData.openTime.toString(),\n mintAVault: rpcData.token0Vault.toBase58(),\n mintBVault: rpcData.token1Vault.toBase58(),\n authority: getPdaPoolAuthority(rpcData.programId).publicKey.toBase58(),\n config: configInfo,\n mintAProgram: rpcData.token0Program.toBase58(),\n mintBProgram: rpcData.token1Program.toBase58(),\n poolType: \"hyper\",\n },\n rpcData,\n };\n }\n\n public async createPool<T extends TxVersion>({\n programId,\n poolFeeAccount,\n startTime,\n maxTradeFeeRate,\n volatilityFactor,\n ownerInfo,\n associatedOnly = false,\n checkCreateATAOwner = false,\n txVersion,\n feeConfig,\n computeBudgetConfig,\n ...params\n }: CreateCpmmPoolParam<T>): Promise<MakeTxData<T, { address: CreateCpmmPoolAddress }>> {\n const payer = ownerInfo.feePayer || this.scope.owner?.publicKey;\n const isFront = new BN(new PublicKey(params.mintA.address).toBuffer()).lte(\n new BN(new PublicKey(params.mintB.address).toBuffer()),\n );\n\n const [mintA, mintB] = isFront ? [params.mintA, params.mintB] : [params.mintB, params.mintA];\n const [mintAAmount, mintBAmount] = isFront\n ? [params.mintAAmount, params.mintBAmount]\n : [params.mintBAmount, params.mintAAmount];\n\n const mintAUseSOLBalance = ownerInfo.useSOLBalance && mintA.address === NATIVE_MINT.toBase58();\n const mintBUseSOLBalance = ownerInfo.useSOLBalance && mintB.address === NATIVE_MINT.toBase58();\n const [mintAPubkey, mintBPubkey] = [new PublicKey(mintA.address), new PublicKey(mintB.address)];\n const txBuilder = this.createTxBuilder();\n\n const { account: userVaultA, instructionParams: userVaultAInstruction } =\n await this.scope.account.getOrCreateTokenAccount({\n mint: mintAPubkey,\n tokenProgram: mintA.programId,\n owner: this.scope.ownerPubKey,\n createInfo: mintAUseSOLBalance\n ? {\n payer: payer!,\n amount: mintAAmount,\n }\n : undefined,\n notUseTokenAccount: mintAUseSOLBalance,\n skipCloseAccount: !mintAUseSOLBalance,\n associatedOnly: mintAUseSOLBalance ? false : associatedOnly,\n checkCreateATAOwner,\n });\n txBuilder.addInstruction(userVaultAInstruction || {});\n const { account: userVaultB, instructionParams: userVaultBInstruction } =\n await this.scope.account.getOrCreateTokenAccount({\n mint: new PublicKey(mintB.address),\n tokenProgram: mintB.programId,\n owner: this.scope.ownerPubKey,\n createInfo: mintBUseSOLBalance\n ? {\n payer: payer!,\n amount: mintBAmount,\n }\n : undefined,\n\n notUseTokenAccount: mintBUseSOLBalance,\n skipCloseAccount: !mintBUseSOLBalance,\n associatedOnly: mintBUseSOLBalance ? false : associatedOnly,\n checkCreateATAOwner,\n });\n txBuilder.addInstruction(userVaultBInstruction || {});\n\n if (userVaultA === undefined || userVaultB === undefined)\n throw Error(\"One or both of user's token account does not exist\");\n\n const poolKeys = getCreatePoolKeys({\n programId,\n configId: new PublicKey(feeConfig.id),\n mintA: mintAPubkey,\n mintB: mintBPubkey,\n });\n\n txBuilder.addInstruction({\n instructions: [\n await makeCreateCpmmPoolInInstruction(\n this.program,\n this.scope.ownerPubKey,\n new PublicKey(feeConfig.id),\n mintAPubkey,\n mintBPubkey,\n userVaultA,\n userVaultB,\n new PublicKey(mintA.programId ?? TOKEN_PROGRAM_ID),\n new PublicKey(mintB.programId ?? TOKEN_PROGRAM_ID),\n mintAAmount,\n mintBAmount,\n startTime,\n maxTradeFeeRate,\n volatilityFactor,\n ),\n ],\n instructionTypes: [InstructionType.CpmmCreatePool],\n });\n\n txBuilder.addCustomComputeBudget(computeBudgetConfig);\n\n return txBuilder.versionBuild({\n txVersion,\n extInfo: {\n address: { ...poolKeys, mintA, mintB, programId, poolFeeAccount, feeConfig },\n },\n }) as Promise<MakeTxData<T, { address: CreateCpmmPoolAddress }>>;\n }\n\n public async addLiquidity<T extends TxVersion>(params: AddCpmmLiquidityParams<T>): Promise<MakeTxData<T>> {\n const {\n poolInfo,\n poolKeys: propPoolKeys,\n inputAmount,\n baseSpecified,\n slippage,\n computeResult,\n computeBudgetConfig,\n config,\n txVersion,\n partner,\n } = params;\n\n // if (this.scope.availability.addStandardPosition === false)\n // this.logAndCreateError(\"add liquidity feature disabled in your region\");\n\n if (inputAmount.isZero())\n this.logAndCreateError(\"amounts must greater than zero\", \"amountInA\", {\n amountInA: inputAmount.toString(),\n });\n const { account } = this.scope;\n const { bypassAssociatedCheck, checkCreateATAOwner } = {\n // default\n ...{ bypassAssociatedCheck: false, checkCreateATAOwner: false },\n // custom\n ...config,\n };\n const rpcPoolData = computeResult ? undefined : await this.getRpcPoolInfo(poolInfo.id);\n\n const {\n liquidity,\n inputAmountFee,\n anotherAmount: _anotherAmount,\n } = computeResult ||\n this.computePairAmount({\n poolInfo: {\n ...poolInfo,\n },\n baseReserve: rpcPoolData!.baseReserve,\n quoteReserve: rpcPoolData!.quoteReserve,\n slippage: new Percent(0),\n baseSpecified,\n epochInfo: await this.scope.fetchEpochInfo(),\n amount: new Decimal(inputAmount.toString()).div(\n 10 ** (baseSpecified? poolInfo.mintA.decimals : poolInfo.mintB.decimals),\n ),\n });\n\n const anotherAmount = _anotherAmount.amount;\n const mintAUseSOLBalance = poolInfo.mintA.address === NATIVE_MINT.toString();\n const mintBUseSOLBalance = poolInfo.mintB.address === NATIVE_MINT.toString();\n\n const txBuilder = this.createTxBuilder();\n const [mintA, mintB] = [new PublicKey(poolInfo.mintA.address), new PublicKey(poolInfo.mintB.address)];\n\n const poolKeys = propPoolKeys ?? (await this.getCpmmPoolKeys(poolInfo.id));\n const { account: tokenAccountA, instructionParams: _tokenAccountAInstruction } =\n await this.scope.account.getOrCreateTokenAccount({\n tokenProgram: poolKeys.mintAProgram,\n mint: new PublicKey(poolInfo.mintA.address),\n owner: this.scope.ownerPubKey,\n\n createInfo:\n mintAUseSOLBalance || (baseSpecified ? inputAmount : anotherAmount).isZero()\n ? {\n payer: this.scope.ownerPubKey,\n amount: baseSpecified ? inputAmount : anotherAmount,\n }\n : undefined,\n skipCloseAccount: !mintAUseSOLBalance,\n notUseTokenAccount: mintAUseSOLBalance,\n associatedOnly: false,\n checkCreateATAOwner,\n });\n\n txBuilder.addInstruction(_tokenAccountAInstruction || {});\n\n const { account: tokenAccountB, instructionParams: _tokenAccountBInstruction } =\n await this.scope.account.getOrCreateTokenAccount({\n tokenProgram: poolKeys.mintBProgram,\n mint: new PublicKey(poolInfo.mintB.address),\n owner: this.scope.ownerPubKey,\n\n createInfo:\n mintBUseSOLBalance || (baseSpecified ? anotherAmount : inputAmount).isZero()\n ? {\n payer: this.scope.ownerPubKey,\n amount: baseSpecified ? anotherAmount : inputAmount,\n }\n : undefined,\n skipCloseAccount: !mintBUseSOLBalance,\n notUseTokenAccount: mintBUseSOLBalance,\n associatedOnly: false,\n checkCreateATAOwner,\n });\n\n txBuilder.addInstruction(_tokenAccountBInstruction || {});\n\n if (!tokenAccountA && !tokenAccountB)\n this.logAndCreateError(\"cannot found target token accounts\", \"tokenAccounts\", account.tokenAccounts);\n const userLiquidityPda = getPdaUserLiquidity(\n new PublicKey(poolInfo.programId),\n new PublicKey(poolInfo.id),\n this.scope.ownerPubKey,\n );\n const userLiquidity = await this.getRpcUserLiquidityAccounts([userLiquidityPda.publicKey]).then((a) => a[0]);\n if (!userLiquidity) {\n txBuilder.addInstruction({\n instructions: [\n await makeInitUserPoolLiquidityInstruction(\n this.program,\n this.scope.ownerPubKey,\n new PublicKey(poolInfo.id),\n partner ? partner : null,\n ),\n ],\n instructionTypes: [InstructionType.CpmmInitUserLiquidity],\n lookupTableAddress: [],\n });\n }\n\n const _slippage = new Percent(new BN(1)).sub(slippage);\n\n txBuilder.addInstruction({\n instructions: [\n await makeDepositCpmmInInstruction(\n this.program,\n this.scope.ownerPubKey,\n new PublicKey(poolInfo.id),\n tokenAccountA!,\n tokenAccountB!,\n new PublicKey(poolKeys.mintAVault),\n new PublicKey(poolKeys.mintBVault),\n mintA,\n mintB,\n\n computeResult ? computeResult?.liquidity : _slippage.mul(liquidity).quotient,\n baseSpecified ? inputAmountFee.amount : anotherAmount,\n baseSpecified ? anotherAmount : inputAmountFee.amount,\n ),\n ],\n instructionTypes: [InstructionType.CpmmAddLiquidity],\n lookupTableAddress: [],\n });\n txBuilder.addCustomComputeBudget(computeBudgetConfig);\n const builder = txBuilder.versionBuild({ txVersion }) as Promise<MakeTxData<T>>;\n\n return txBuilder.versionBuild({ txVersion }) as Promise<MakeTxData<T>>;\n }\n\n public async withdrawLiquidity<T extends TxVersion>(params: WithdrawCpmmLiquidityParams<T>): Promise<MakeTxData<T>> {\n const { poolInfo, poolKeys: propPoolKeys, lpAmount, slippage, computeBudgetConfig, txVersion } = params;\n let tokenAReserve: KaminoReserve | undefined = this.reserves.get(poolInfo.mintA.address);\n let tokenBReserve: KaminoReserve | undefined = this.reserves.get(poolInfo.mintB.address);\n if (!tokenAReserve || !tokenBReserve) {\n this.reserves = await getReservesForMarket(this.program.provider.connection);\n tokenAReserve = this.reserves.get(poolInfo.mintA.address);\n tokenBReserve = this.reserves.get(poolInfo.mintB.address);\n }\n\n // if (this.scope.availability.addStandardPosition === false)\n // this.logAndCreateError(\"add liquidity feature disabled in your region\");\n\n const rpcPoolData = await this.getRpcPoolInfo(poolInfo.id);\n const kaminoAccounts = getReserveAccountsForWithdraw(\n new PublicKey(poolInfo.id),\n tokenAReserve,\n tokenBReserve,\n rpcPoolData.maxSharedToken0,\n rpcPoolData.maxSharedToken1,\n this.program.programId,\n this.kamino?.programId,\n );\n\n const _slippage = new Percent(new BN(1)).sub(slippage);\n const [amountMintA, amountMintB] = [\n _slippage.mul(lpAmount.mul(rpcPoolData.baseReserve).div(rpcPoolData.lpSupply)).quotient,\n _slippage.mul(lpAmount.mul(rpcPoolData.quoteReserve).div(rpcPoolData.lpSupply)).quotient,\n ];\n\n const epochInfo = await this.scope.fetchEpochInfo();\n const [mintAAmountFee, mintBAmountFee] = [\n getTransferAmountFeeV2(amountMintA, poolInfo.mintA.extensions?.feeConfig, epochInfo, false),\n getTransferAmountFeeV2(amountMintB, poolInfo.mintB.extensions?.feeConfig, epochInfo, false),\n ];\n\n const { account } = this.scope;\n const txBuilder = this.createTxBuilder();\n const [mintA, mintB] = [new PublicKey(poolInfo.mintA.address), new PublicKey(poolInfo.mintB.address)];\n\n const mintAUseSOLBalance = mintA.equals(WSOLMint);\n const mintBUseSOLBalance = mintB.equals(WSOLMint);\n\n const poolKeys = propPoolKeys ?? (await this.getCpmmPoolKeys(poolInfo.id));\n\n let tokenAccountA: PublicKey | undefined = undefined;\n let tokenAccountB: PublicKey | undefined = undefined;\n const { account: _ownerTokenAccountA, instructionParams: accountAInstructions } =\n await this.scope.account.getOrCreateTokenAccount({\n tokenProgram: poolKeys.mintAProgram,\n mint: new PublicKey(poolInfo.mintA.address),\n notUseTokenAccount: mintAUseSOLBalance,\n owner: this.scope.ownerPubKey,\n createInfo: {\n payer: this.scope.ownerPubKey,\n amount: 0,\n },\n skipCloseAccount: !mintAUseSOLBalance,\n associatedOnly: mintAUseSOLBalance ? false : true,\n checkCreateATAOwner: false,\n });\n tokenAccountA = _ownerTokenAccountA;\n accountAInstructions && txBuilder.addInstruction(accountAInstructions);\n\n const { account: _ownerTokenAccountB, instructionParams: accountBInstructions } =\n await this.scope.account.getOrCreateTokenAccount({\n tokenProgram: poolKeys.mintBProgram,\n mint: new PublicKey(poolInfo.mintB.address),\n notUseTokenAccount: mintBUseSOLBalance,\n owner: this.scope.ownerPubKey,\n createInfo: {\n payer: this.scope.ownerPubKey,\n amount: 0,\n },\n skipCloseAccount: !mintBUseSOLBalance,\n associatedOnly: mintBUseSOLBalance ? false : true,\n checkCreateATAOwner: false,\n });\n tokenAccountB = _ownerTokenAccountB;\n accountBInstructions && txBuilder.addInstruction(accountBInstructions);\n\n if (!tokenAccountA || !tokenAccountB)\n this.logAndCreateError(\"cannot found target token accounts\", \"tokenAccounts\", account.tokenAccounts);\n\n const userLiquidityPda = getPdaUserLiquidity(\n new PublicKey(poolInfo.programId),\n new PublicKey(poolInfo.id),\n this.scope.ownerPubKey,\n );\n const userLiquidity = await this.getRpcUserLiquidityAccounts([userLiquidityPda.publicKey]).then((a) => a[0]);\n\n if (!userLiquidity) this.logAndCreateError(\"cannot found userLiquidityAccount\");\n txBuilder.addInstruction({\n instructions: [\n await makeWithdrawCpmmInInstruction(\n this.program,\n this.scope.ownerPubKey,\n new PublicKey(poolInfo.id),\n tokenAccountA!,\n tokenAccountB!,\n new PublicKey(poolKeys.mintAVault),\n new PublicKey(poolKeys.mintBVault),\n mintA,\n mintB,\n\n lpAmount,\n amountMintA.sub(mintAAmountFee.fee ?? new BN(0)),\n amountMintB.sub(mintBAmountFee.fee ?? new BN(0)),\n kaminoAccounts,\n ),\n ],\n instructionTypes: [InstructionType.CpmmWithdrawLiquidity],\n lookupTableAddress: [],\n });\n txBuilder.addCustomComputeBudget(computeBudgetConfig);\n return txBuilder.versionBuild({ txVersion }) as Promise<MakeTxData<T>>;\n }\n\n public async swap<T extends TxVersion>(params: CpmmSwapParams<T>): Promise<MakeTxData<T>> {\n const {\n poolInfo,\n poolKeys: propPoolKeys,\n zeroForOne,\n baseIn,\n swapResult,\n slippage = 0,\n config,\n computeBudgetConfig,\n txVersion,\n wrapSol,\n } = params;\n\n const { bypassAssociatedCheck, checkCreateATAOwner, associatedOnly } = {\n // default\n ...{ bypassAssociatedCheck: false, checkCreateATAOwner: false, associatedOnly: true },\n // custom\n ...config,\n };\n\n const txBuilder = this.createTxBuilder();\n\n const [mintA, mintB] = [new PublicKey(poolInfo.mintA.address), new PublicKey(poolInfo.mintB.address)];\n\n if (baseIn) {\n swapResult.destinationAmountSwapped = swapResult.destinationAmountSwapped\n .mul(new BN((1 - slippage) * 10000))\n .div(new BN(10000));\n } else {\n swapResult.sourceAmountSwapped = swapResult.sourceAmountSwapped\n .mul(new BN((1 + slippage) * 10000))\n .div(new BN(10000));\n }\n\n const poolKeys = propPoolKeys ?? (await this.getCpmmPoolKeys(poolInfo.id));\n\n const mintAUseSOLBalance = poolInfo.mintA.address === WSOLMint.toBase58();\n const mintBUseSOLBalance = poolInfo.mintB.address === WSOLMint.toBase58();\n const { account: mintATokenAcc, instructionParams: mintATokenAccInstruction } =\n await this.scope.account.getOrCreateTokenAccount({\n mint: mintA,\n tokenProgram: new PublicKey(poolKeys.mintAProgram),\n owner: this.scope.ownerPubKey,\n createInfo:\n mintAUseSOLBalance || !zeroForOne\n ? {\n payer: this.scope.ownerPubKey,\n amount: zeroForOne ? swapResult.sourceAmountSwapped : 0,\n }\n : undefined,\n notUseTokenAccount: mintAUseSOLBalance,\n skipCloseAccount: !mintAUseSOLBalance,\n associatedOnly: mintAUseSOLBalance ? false : associatedOnly,\n checkCreateATAOwner,\n });\n mintATokenAccInstruction && txBuilder.addInstruction(mintATokenAccInstruction);\n\n const { account: mintBTokenAcc, instructionParams: mintBTokenAccInstruction } =\n await this.scope.account.getOrCreateTokenAccount({\n mint: mintB,\n tokenProgram: new PublicKey(poolKeys.mintBProgram),\n owner: this.scope.ownerPubKey,\n createInfo:\n mintBUseSOLBalance || zeroForOne\n ? {\n payer: this.scope.ownerPubKey,\n amount: zeroForOne ? 0 : swapResult.sourceAmountSwapped,\n }\n : undefined,\n notUseTokenAccount: mintBUseSOLBalance,\n skipCloseAccount: !mintBUseSOLBalance,\n associatedOnly: mintBUseSOLBalance ? false : associatedOnly,\n checkCreateATAOwner,\n });\n mintBTokenAccInstruction && txBuilder.addInstruction(mintBTokenAccInstruction);\n\n if (!mintATokenAcc || !mintBTokenAcc)\n this.logAndCreateError(\"user do not have token account\", {\n mintA: poolInfo.mintA.symbol || poolInfo.mintA.address,\n mintB: poolInfo.mintB.symbol || poolInfo.mintB.address,\n mintATokenAcc,\n mintBTokenAcc,\n mintAUseSOLBalance,\n mintBUseSOLBalance,\n associatedOnly,\n });\n\n const inputMint = zeroForOne ? poolInfo.mintA.address : poolInfo.mintB.address;\n if (wrapSol && inputMint === SOL_INFO.address) {\n txBuilder.addInstruction({\n instructions: [\n SystemProgram.transfer({\n fromPubkey: this.scope.ownerPubKey,\n toPubkey: zeroForOne ? mintATokenAcc! : mintBTokenAcc!,\n lamports: BigInt(swapResult.sourceAmountSwapped.toString()),\n }),\n createSyncNativeInstruction(new PublicKey(zeroForOne ? mintATokenAcc! : mintBTokenAcc!)),\n ],\n });\n }\n\n txBuilder.addInstruction({\n instructions: [\n baseIn\n ? await makeSwapCpmmBaseInInstruction(\n this.program,\n this.scope.ownerPubKey,\n new PublicKey(poolKeys.config.id),\n new PublicKey(poolInfo.id),\n zeroForOne ? mintATokenAcc! : mintBTokenAcc!,\n zeroForOne ? mintBTokenAcc! : mintATokenAcc!,\n new PublicKey(zeroForOne ? poolKeys.mintAVault : poolKeys.mintBVault),\n new PublicKey(zeroForOne ? poolKeys.mintBVault : poolKeys.mintAVault),\n new PublicKey(zeroForOne ? poolKeys.mintAProgram : poolKeys.mintBProgram),\n new PublicKey(zeroForOne ? poolKeys.mintBProgram : poolKeys.mintAProgram),\n zeroForOne ? mintA : mintB,\n zeroForOne ? mintB : mintA,\n getPdaObservationId(new PublicKey(poolInfo.programId), new PublicKey(poolInfo.id)).publicKey,\n\n swapResult.sourceAmountSwapped,\n swapResult.destinationAmountSwapped,\n params.dflowSegmenterOptions,\n params.referralAccounts,\n )\n : await makeSwapCpmmBaseOutInstruction(\n this.program,\n this.scope.ownerPubKey,\n new PublicKey(poolKeys.config.id),\n new PublicKey(poolInfo.id),\n\n zeroForOne ? mintATokenAcc! : mintBTokenAcc!,\n zeroForOne ? mintBTokenAcc! : mintATokenAcc!,\n\n new PublicKey(zeroForOne ? poolKeys.mintAVault : poolKeys.mintBVault),\n new PublicKey(zeroForOne ? poolKeys.mintBVault : poolKeys.mintAVault),\n new PublicKey(zeroForOne ? poolKeys.mintAProgram : poolKeys.mintBProgram),\n new PublicKey(zeroForOne ? poolKeys.mintBProgram : poolKeys.mintAProgram),\n zeroForOne ? mintA : mintB,\n zeroForOne ? mintB : mintA,\n\n getPdaObservationId(new PublicKey(poolInfo.programId), new PublicKey(poolInfo.id)).publicKey,\n\n swapResult.sourceAmountSwapped,\n swapResult.destinationAmountSwapped,\n params.dflowSegmenterOptions,\n params.referralAccounts,\n ),\n ],\n instructionTypes: [baseIn ? InstructionType.CpmmSwapBaseIn : InstructionType.CpmmSwapBaseOut],\n });\n\n txBuilder.addCustomComputeBudget(computeBudgetConfig);\n\n return txBuilder.versionBuild({ txVersion }) as Promise<MakeTxData<T>>;\n }\n\n public async swapWithOracle<T extends TxVersion>(params: CpmmSwapParams<T>): Promise<MakeTxData<T>> {\n const {\n poolInfo,\n poolKeys: propPoolKeys,\n zeroForOne,\n swapResult,\n slippage = 0,\n config,\n computeBudgetConfig,\n txVersion,\n wrapSol,\n } = params;\n\n const { bypassAssociatedCheck, checkCreateATAOwner, associatedOnly } = {\n // default\n ...{ bypassAssociatedCheck: false, checkCreateATAOwner: false, associatedOnly: true },\n // custom\n ...config,\n };\n\n const txBuilder = this.createTxBuilder();\n\n const [mintA, mintB] = [new PublicKey(poolInfo.mintA.address), new PublicKey(poolInfo.mintB.address)];\n\n swapResult.destinationAmountSwapped = swapResult.destinationAmountSwapped\n .mul(new BN((1 - slippage) * 10000))\n .div(new BN(10000));\n\n const poolKeys = propPoolKeys ?? (await this.getCpmmPoolKeys(poolInfo.id));\n\n const mintAUseSOLBalance = poolInfo.mintA.address === WSOLMint.toBase58();\n const mintBUseSOLBalance = poolInfo.mintB.address === WSOLMint.toBase58();\n const { account: mintATokenAcc, instructionParams: mintATokenAccInstruction } =\n await this.scope.account.getOrCreateTokenAccount({\n mint: mintA,\n tokenProgram: new PublicKey(poolKeys.mintAProgram),\n owner: this.scope.ownerPubKey,\n createInfo:\n mintAUseSOLBalance || !zeroForOne\n ? {\n payer: this.scope.ownerPubKey,\n amount: zeroForOne ? swapResult.sourceAmountSwapped : 0,\n }\n : undefined,\n notUseTokenAccount: mintAUseSOLBalance,\n skipCloseAccount: !mintAUseSOLBalance,\n associatedOnly: mintAUseSOLBalance ? false : associatedOnly,\n checkCreateATAOwner,\n });\n mintATokenAccInstruction && txBuilder.addInstruction(mintATokenAccInstruction);\n\n const { account: mintBTokenAcc, instructionParams: mintBTokenAccInstruction } =\n await this.scope.account.getOrCreateTokenAccount({\n mint: mintB,\n tokenProgram: new PublicKey(poolKeys.mintBProgram),\n owner: this.scope.ownerPubKey,\n createInfo:\n mintBUseSOLBalance || zeroForOne\n ? {\n payer: this.scope.ownerPubKey,\n amount: zeroForOne ? 0 : swapResult.sourceAmountSwapped,\n }\n : undefined,\n notUseTokenAccount: mintBUseSOLBalance,\n skipCloseAccount: !mintBUseSOLBalance,\n associatedOnly: mintBUseSOLBalance ? false : associatedOnly,\n checkCreateATAOwner,\n });\n mintBTokenAccInstruction && txBuilder.addInstruction(mintBTokenAccInstruction);\n\n if (!mintATokenAcc || !mintBTokenAcc)\n this.logAndCreateError(\"user do not have token account\", {\n mintA: poolInfo.mintA.symbol || poolInfo.mintA.address,\n mintB: poolInfo.mintB.symbol || poolInfo.mintB.address,\n mintATokenAcc,\n mintBTokenAcc,\n mintAUseSOLBalance,\n mintBUseSOLBalance,\n associatedOnly,\n });\n\n const inputMint = zeroForOne ? poolInfo.mintA.address : poolInfo.mintB.address;\n if (wrapSol && inputMint === SOL_INFO.address) {\n txBuilder.addInstruction({\n instructions: [\n SystemProgram.transfer({\n fromPubkey: this.scope.ownerPubKey,\n toPubkey: zeroForOne ? mintATokenAcc! : mintBTokenAcc!,\n lamports: BigInt(swapResult.sourceAmountSwapped.toString()),\n }),\n createSyncNativeInstruction(new PublicKey(zeroForOne ? mintATokenAcc! : mintBTokenAcc!)),\n ],\n });\n }\n\n txBuilder.addInstruction({\n instructions: [\n await makeSwapCpmmOracleBaseInInstruction(\n this.program,\n this.scope.ownerPubKey,\n new PublicKey(poolKeys.config.id),\n new PublicKey(poolInfo.id),\n zeroForOne ? mintATokenAcc! : mintBTokenAcc!,\n zeroForOne ? mintBTokenAcc! : mintATokenAcc!,\n new PublicKey(zeroForOne ? poolKeys.mintAVault : poolKeys.mintBVault),\n new PublicKey(zeroForOne ? poolKeys.mintBVault : poolKeys.mintAVault),\n new PublicKey(zeroForOne ? poolKeys.mintAProgram : poolKeys.mintBProgram),\n new PublicKey(zeroForOne ? poolKeys.mintBProgram : poolKeys.mintAProgram),\n zeroForOne ? mintA : mintB,\n zeroForOne ? mintB : mintA,\n getPdaObservationId(new PublicKey(poolInfo.programId), new PublicKey(poolInfo.id)).publicKey,\n\n swapResult.sourceAmountSwapped,\n swapResult.destinationAmountSwapped,\n params.dflowSegmenterOptions,\n params.referralAccounts,\n ),\n ],\n instructionTypes: [InstructionType.CpmmSwapBaseIn],\n });\n\n txBuilder.addCustomComputeBudget(computeBudgetConfig);\n\n return txBuilder.versionBuild({ txVersion }) as Promise<MakeTxData<T>>;\n }\n\n public computeSwapAmount({\n pool,\n amount,\n baseIn,\n zeroForOne,\n slippage,\n observationState,\n }: {\n pool: CpmmComputeData;\n amount: BN;\n baseIn: boolean;\n zeroForOne: boolean;\n slippage: number;\n observationState: CpmmObservationState;\n }): {\n allTrade: boolean;\n amountIn: BN;\n amountOut: BN;\n minAmountOut: BN;\n maxAmountIn: BN;\n fee: BN;\n executionPrice: Decimal;\n priceImpact: Decimal;\n } {\n const [inputToken, outputToken, inputTokenReserves, outputTokenReserves] = zeroForOne\n ? [pool.mintA, pool.mintB, pool.baseReserve, pool.quoteReserve]\n : [pool.mintB, pool.mintA, pool.quoteReserve, pool.baseReserve];\n\n const inputDecimals = inputToken.decimals;\n const outputDecimals = outputToken.decimals;\n\n const swapResult = baseIn\n ? CurveCalculator.swapBaseIn(\n amount,\n new BN(inputTokenReserves),\n new BN(outputTokenReserves),\n new BN(pool.configInfo.tradeFeeRate),\n observationState,\n pool.volatilityFactor,\n )\n : CurveCalculator.swapBaseOut(\n amount,\n new BN(inputTokenReserves),\n new BN(outputTokenReserves),\n new BN(pool.configInfo.tradeFeeRate),\n observationState,\n pool.volatilityFactor,\n );\n\n const currentPrice = zeroForOne ? pool.poolPrice : new Decimal(1).div(pool.poolPrice);\n const numerator = new Decimal(swapResult.destinationAmountSwapped.toString()).div(\n new Decimal(10).pow(inputDecimals),\n );\n const denominator = new Decimal(swapResult.sourceAmountSwapped.toString()).div(new Decimal(10).pow(outputDecimals));\n const executionPrice = numerator.div(denominator);\n\n const otherAmountThreshold = baseIn\n ? swapResult.destinationAmountSwapped.mul(new BN((1 - slippage) * 10000)).div(new BN(10000))\n : swapResult.sourceAmountSwapped.mul(new BN((1 + slippage) * 10000)).div(new BN(10000));\n\n return {\n allTrade: baseIn ? swapResult.sourceAmountSwapped.eq(amount) : swapResult.destinationAmountSwapped.eq(amount),\n amountIn: swapResult.sourceAmountSwapped,\n amountOut: swapResult.destinationAmountSwapped,\n maxAmountIn: baseIn ? swapResult.sourceAmountSwapped : otherAmountThreshold,\n minAmountOut: baseIn ? otherAmountThreshold : swapResult.destinationAmountSwapped,\n executionPrice,\n fee: swapResult.tradeFee,\n priceImpact: currentPrice.sub(executionPrice).div(currentPrice),\n };\n }\n\n public computePairAmount({\n poolInfo,\n baseReserve,\n quoteReserve,\n amount,\n slippage,\n epochInfo,\n baseSpecified\n }: ComputePairAmountParams): {\n inputAmountFee: GetTransferAmountFee;\n anotherAmount: GetTransferAmountFee;\n maxAnotherAmount: GetTransferAmountFee;\n liquidity: BN;\n } {\n const coefficient = 1 - Number(slippage.toSignificant()) / 100;\n const inputAmount = new BN(\n new Decimal(amount)\n .mul(10 ** poolInfo[baseSpecified ? \"mintA\" : \"mintB\"].decimals)\n .mul(coefficient)\n .toFixed(0),\n );\n const inputAmountFee = getTransferAmountFeeV2(\n inputAmount,\n (baseSpecified ? poolInfo.mintA : poolInfo.mintB).extensions?.feeConfig,\n epochInfo,\n false,\n );\n const _inputAmountWithoutFee = inputAmount.sub(inputAmountFee.fee ?? new BN(0));\n\n const lpAmount = new BN(poolInfo.lpSupply ?? \"0\");\n this.logDebug(\"baseReserve:\", baseReserve.toString(), \"quoteReserve:\", quoteReserve.toString());\n\n this.logDebug(\n \"tokenIn:\",\n baseSpecified ? poolInfo.mintA.symbol : poolInfo.mintB.symbol,\n \"amountIn:\",\n inputAmount.toString(),\n \"amountInFee:\",\n inputAmountFee.fee?.toString() ?? 0,\n \"anotherToken:\",\n baseSpecified ? poolInfo.mintB.symbol : poolInfo.mintA.symbol,\n \"slippage:\",\n `${slippage.toSignificant()}%`,\n );\n\n // input is fixed\n const input = baseSpecified ? \"base\" : \"quote\";\n this.logDebug(\"input side:\", input);\n\n const liquidity = _inputAmountWithoutFee.mul(lpAmount).div(input === \"base\" ? baseReserve : quoteReserve);\n let anotherAmountFee: GetTransferAmountFee = {\n amount: BN_ZERO,\n fee: undefined,\n expirationTime: undefined,\n };\n if (!_inputAmountWithoutFee.isZero()) {\n const lpAmountData = lpToAmount(liquidity, baseReserve, quoteReserve, lpAmount);\n this.logDebug(\"lpAmountData:\", {\n amountA: lpAmountData.amountA.toString(),\n amountB: lpAmountData.amountB.toString(),\n });\n anotherAmountFee = getTransferAmountFeeV2(\n lpAmountData[baseSpecified ? \"amountB\" : \"amountA\"],\n (baseSpecified ? poolInfo.mintB : poolInfo.mintA).extensions?.feeConfig,\n epochInfo,\n true,\n );\n }\n\n const _slippage = new Percent(new BN(1)).add(slippage);\n const slippageAdjustedAmount = getTransferAmountFeeV2(\n _slippage.mul(anotherAmountFee.amount.sub(anotherAmountFee.fee ?? new BN(0))).quotient,\n (baseSpecified ? poolInfo.mintB : poolInfo.mintA).extensions?.feeConfig,\n epochInfo,\n true,\n );\n\n this.logDebug(\n \"anotherAmount:\",\n anotherAmountFee.amount.toString(),\n \"anotherAmountFee:\",\n anotherAmountFee.fee?.toString() ?? 0,\n \"maxAnotherAmount:\",\n slippageAdjustedAmount.amount.toString(),\n \"maxAnotherAmountFee:\",\n slippageAdjustedAmount.fee?.toString() ?? 0,\n );\n\n return {\n inputAmountFee,\n anotherAmount: anotherAmountFee,\n maxAnotherAmount: slippageAdjustedAmount,\n liquidity,\n };\n }\n\n public async initializePartner<T extends TxVersion>({\n pool,\n poolKeys,\n partnerKey,\n name,\n token0TokenAccount,\n token1TokenAccount,\n computeBudgetConfig,\n txVersion,\n }: {\n pool: string;\n poolKeys: PoolKeys | undefined;\n partnerKey: PublicKey;\n name: string;\n token0TokenAccount?: PublicKey;\n token1TokenAccount?: PublicKey;\n computeBudgetConfig?: ComputeBudgetConfig;\n txVersion?: T;\n }): Promise<MakeTxData<T>> {\n const txBuilder = this.createTxBuilder();\n const keys = poolKeys ?? (await this.getCpmmPoolKeys(pool));\n const tokenAccount0 =\n token0TokenAccount ??\n this.scope.account.getAssociatedTokenAccount(new PublicKey(keys.mintA), new PublicKey(keys.mintAProgram));\n const tokenAccount1 =\n token1TokenAccount ??\n this.scope.account.getAssociatedTokenAccount(new PublicKey(keys.mintB), new PublicKey(keys.mintBProgram));\n txBuilder.addInstruction({\n instructions: [\n await makeInitializePartnerInstruction(\n this.program,\n this.scope.ownerPubKey,\n this.scope.ownerPubKey,\n new PublicKey(pool),\n partnerKey,\n name,\n tokenAccount0,\n tokenAccount1,\n ),\n ],\n });\n\n txBuilder.addCustomComputeBudget(computeBudgetConfig);\n\n return txBuilder.versionBuild({ txVersion }) as Promise<MakeTxData<T>>;\n }\n\n public async addPartner<T extends TxVersion>({\n pool,\n poolKeys,\n partnerKey,\n computeBudgetConfig,\n txVersion,\n }: {\n pool: string;\n poolKeys: PoolKeys | undefined;\n partnerKey: PublicKey;\n computeBudgetConfig?: ComputeBudgetConfig;\n txVersion?: T;\n }): Promise<MakeTxData<T>> {\n const txBuilder = this.createTxBuilder();\n const keys = poolKeys ?? (await this.getCpmmPoolKeys(pool));\n txBuilder.addInstruction({\n instructions: [\n await makeAddPartnerInstruction(\n this.program,\n new PublicKey(keys.config.id),\n new PublicKey(pool),\n partnerKey,\n this.scope.ownerPubKey,\n ),\n ],\n });\n\n txBuilder.addCustomComputeBudget(computeBudgetConfig);\n\n return txBuilder.versionBuild({ txVersion }) as Promise<MakeTxData<T>>;\n }\n\n public async getRpcUserLiquidityAccounts(addresses: PublicKey[]): Promise<(UserLiquidityAccount | null)[]> {\n return await this.program.account.userPoolLiquidity.fetchMultiple(addresses);\n }\n\n public async getObservationStates(addresses: PublicKey[]): Promise<(CpmmObservationState | null)[]> {\n return await this.program.account.observationState.fetchMultiple(addresses);\n }\n}\n\nfunction lpToAmount(lp: BN, poolAmountA: BN, poolAmountB: BN, supply: BN): { amountA: BN; amountB: BN } {\n let amountA = lp.mul(poolAmountA).div(supply);\n if (!amountA.isZero() && !lp.mul(poolAmountA).mod(supply).is