test-rrr-sdk
Version:
An SDK for building applications on top of Raydium.
1 lines • 774 kB
Source Map (JSON)
{"version":3,"sources":["../../../src/raydium/cpmm/cpmm.ts","../../../src/common/bignumber.ts","../../../node_modules/decimal.js/decimal.mjs","../../../src/module/amount.ts","../../../src/common/logger.ts","../../../src/common/accountInfo.ts","../../../src/common/constant.ts","../../../src/raydium/token/constant.ts","../../../src/module/token.ts","../../../src/common/pubKey.ts","../../../src/module/currency.ts","../../../src/module/formatter.ts","../../../src/module/fraction.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/raydium/cpmm/curve/calculator.ts","../../../src/raydium/cpmm/curve/constantProduct.ts","../../../src/raydium/cpmm/curve/fee.ts","../../../src/raydium/moduleBase.ts","../../../src/marshmallow/index.ts","../../../src/marshmallow/buffer-layout.ts","../../../src/raydium/token/layout.ts","../../../src/raydium/token/utils.ts","../../../src/raydium/cpmm/instruction.ts","../../../src/raydium/cpmm/pda.ts","../../../src/raydium/clmm/clmm.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/pda.ts","../../../src/raydium/clmm/utils/pool.ts","../../../src/raydium/clmm/utils/position.ts","../../../src/raydium/clmm/utils/tickarrayBitmap.ts","../../../src/raydium/clmm/layout.ts","../../../src/raydium/cpmm/layout.ts"],"sourcesContent":["import { PublicKey } from \"@solana/web3.js\";\nimport { ApiV3PoolInfoStandardItemCpmm, CpmmKeys } from \"../../api/type\";\nimport { AccountLayout, NATIVE_MINT, TOKEN_PROGRAM_ID } from \"@solana/spl-token\";\nimport { BN_ZERO } from \"@/common/bignumber\";\nimport { getATAAddress } from \"@/common/pda\";\nimport { WSOLMint } from \"@/common/pubKey\";\nimport { MakeTxData } from \"@/common/txTool/txTool\";\nimport { InstructionType, TxVersion } from \"@/common/txTool/txType\";\nimport { Percent } from \"../../module\";\nimport { CurveCalculator } from \"./curve/calculator\";\n\nimport BN from \"bn.js\";\nimport Decimal from \"decimal.js\";\nimport {\n fetchMultipleMintInfos,\n getMultipleAccountsInfoWithCustomFlags,\n getTransferAmountFeeV2,\n LOCK_CPMM_AUTH,\n LOCK_CPMM_PROGRAM,\n} from \"@/common\";\nimport { GetTransferAmountFee, ReturnTypeFetchMultipleMintInfos } from \"../../raydium/type\";\nimport ModuleBase, { ModuleBaseProps } from \"../moduleBase\";\nimport { toApiV3Token, toFeeConfig } from \"../token\";\nimport {\n makeCreateCpmmPoolInInstruction,\n makeDepositCpmmInInstruction,\n makeSwapCpmmBaseInInstruction,\n makeSwapCpmmBaseOutInstruction,\n makeWithdrawCpmmInInstruction,\n makeCpmmLockInstruction,\n collectCpFeeInstruction,\n} from \"./instruction\";\nimport { CpmmConfigInfoLayout, CpmmPoolInfoLayout } from \"./layout\";\nimport { getCreatePoolKeys, getPdaObservationId, getPdaPoolAuthority } from \"./pda\";\nimport {\n AddCpmmLiquidityParams,\n ComputePairAmountParams,\n CpmmComputeData,\n CpmmLockExtInfo,\n CpmmRpcData,\n CpmmSwapParams,\n CreateCpmmPoolAddress,\n CreateCpmmPoolParam,\n LockCpmmLpParams,\n HarvestLockCpmmLpParams,\n WithdrawCpmmLiquidityParams,\n} from \"./type\";\nimport { getCpLockPda } from \"./pda\";\n\nexport default class CpmmModule extends ModuleBase {\n constructor(params: ModuleBaseProps) {\n super(params);\n }\n\n public async load(): Promise<void> {\n this.checkDisabled();\n }\n\n public async getCpmmPoolKeys(poolId: string): Promise<CpmmKeys> {\n return ((await this.scope.api.fetchPoolKeysById({ idList: [poolId] })) as CpmmKeys[])[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 getRpcPoolInfos(\n poolIds: string[],\n fetchConfigInfo?: boolean,\n ): Promise<{\n [poolId: string]: CpmmRpcData;\n }> {\n const accounts = await getMultipleAccountsInfoWithCustomFlags(\n this.scope.connection,\n poolIds.map((i) => ({ pubkey: new PublicKey(i) })),\n );\n const poolInfos: { [poolId: string]: ReturnType<typeof CpmmPoolInfoLayout.decode> & { programId: PublicKey } } = {};\n\n const needFetchConfigId = new Set<string>();\n const needFetchVaults: PublicKey[] = [];\n\n for (let i = 0; i < poolIds.length; i++) {\n const item = accounts[i];\n if (item.accountInfo === null) throw Error(\"fetch pool info error: \" + String(poolIds[i]));\n const rpc = CpmmPoolInfoLayout.decode(item.accountInfo.data);\n poolInfos[String(poolIds[i])] = {\n ...rpc,\n programId: item.accountInfo.owner,\n };\n needFetchConfigId.add(String(rpc.configId));\n\n needFetchVaults.push(rpc.vaultA, rpc.vaultB);\n }\n\n const configInfo: { [configId: string]: ReturnType<typeof CpmmConfigInfoLayout.decode> } = {};\n\n if (fetchConfigInfo) {\n const configIds = [...needFetchConfigId];\n const configState = await getMultipleAccountsInfoWithCustomFlags(\n this.scope.connection,\n configIds.map((i) => ({ pubkey: new PublicKey(i) })),\n );\n\n for (let i = 0; i < configIds.length; i++) {\n const configItemInfo = configState[i].accountInfo;\n if (configItemInfo === null) throw Error(\"fetch pool config error: \" + configIds[i]);\n configInfo[configIds[i]] = CpmmConfigInfoLayout.decode(configItemInfo.data);\n }\n }\n\n const vaultInfo: { [vaultId: string]: BN } = {};\n\n const vaultAccountInfo = await getMultipleAccountsInfoWithCustomFlags(\n this.scope.connection,\n needFetchVaults.map((i) => ({ pubkey: new PublicKey(i) })),\n );\n\n for (let i = 0; i < needFetchVaults.length; i++) {\n const vaultItemInfo = vaultAccountInfo[i].accountInfo;\n if (vaultItemInfo === null) throw Error(\"fetch vault info error: \" + needFetchVaults[i]);\n\n vaultInfo[String(needFetchVaults[i])] = new BN(AccountLayout.decode(vaultItemInfo.data).amount.toString());\n }\n\n const returnData: { [poolId: string]: CpmmRpcData } = {};\n\n for (const [id, info] of Object.entries(poolInfos)) {\n const baseReserve = vaultInfo[info.vaultA.toString()].sub(info.protocolFeesMintA).sub(info.fundFeesMintA);\n const quoteReserve = vaultInfo[info.vaultB.toString()].sub(info.protocolFeesMintB).sub(info.fundFeesMintB);\n returnData[id] = {\n ...info,\n baseReserve,\n quoteReserve,\n vaultAAmount: vaultInfo[info.vaultA.toString()],\n vaultBAmount: vaultInfo[info.vaultB.toString()],\n configInfo: configInfo[info.configId.toString()],\n poolPrice: new Decimal(quoteReserve.toString())\n .div(new Decimal(10).pow(info.mintDecimalB))\n .div(new Decimal(baseReserve.toString()).div(new Decimal(10).pow(info.mintDecimalA))),\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.mintA.toBase58(), pool.mintB.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: toApiV3Token({\n address: mintA,\n decimals: pool.mintDecimalA,\n programId: pool.mintProgramA.toBase58(),\n extensions: {\n feeConfig: mintInfos[mintA]?.feeConfig ? toFeeConfig(mintInfos[mintA]?.feeConfig) : undefined,\n },\n }),\n mintB: toApiV3Token({\n address: mintB,\n decimals: pool.mintDecimalB,\n programId: pool.mintProgramB.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: ApiV3PoolInfoStandardItemCpmm;\n poolKeys: CpmmKeys;\n rpcData: CpmmRpcData;\n }> {\n const rpcData = await this.getRpcPoolInfo(poolId, true);\n const mintInfos = await fetchMultipleMintInfos({\n connection: this.scope.connection,\n mints: [rpcData.mintA, rpcData.mintB],\n });\n\n const mintA = toApiV3Token({\n address: rpcData.mintA.toBase58(),\n decimals: rpcData.mintDecimalA,\n programId: rpcData.mintProgramA.toBase58(),\n extensions: {\n feeConfig: mintInfos[rpcData.mintA.toBase58()].feeConfig\n ? toFeeConfig(mintInfos[rpcData.mintA.toBase58()].feeConfig)\n : undefined,\n },\n });\n const mintB = toApiV3Token({\n address: rpcData.mintB.toBase58(),\n decimals: rpcData.mintDecimalB,\n programId: rpcData.mintProgramB.toBase58(),\n extensions: {\n feeConfig: mintInfos[rpcData.mintB.toBase58()].feeConfig\n ? toFeeConfig(mintInfos[rpcData.mintB.toBase58()].feeConfig)\n : undefined,\n },\n });\n\n const lpMint = toApiV3Token({\n address: rpcData.mintLp.toBase58(),\n decimals: rpcData.lpDecimals,\n programId: TOKEN_PROGRAM_ID.toBase58(),\n });\n\n const configInfo = {\n id: rpcData.configId.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 };\n\n const mockRewardData = {\n volume: 0,\n volumeQuote: 0,\n volumeFee: 0,\n apr: 0,\n feeApr: 0,\n priceMin: 0,\n priceMax: 0,\n rewardApr: [],\n };\n\n return {\n poolInfo: {\n programId: rpcData.programId.toBase58(),\n id: poolId,\n type: \"Standard\",\n lpMint,\n lpPrice: 0,\n lpAmount: rpcData.lpAmount.toNumber(),\n config: configInfo,\n mintA,\n mintB,\n rewardDefaultInfos: [],\n rewardDefaultPoolInfos: \"Ecosystem\",\n price: rpcData.poolPrice.toNumber(),\n mintAmountA: new Decimal(rpcData.vaultAAmount.toString()).div(10 ** mintA.decimals).toNumber(),\n mintAmountB: new Decimal(rpcData.vaultBAmount.toString()).div(10 ** mintB.decimals).toNumber(),\n feeRate: rpcData.configInfo!.tradeFeeRate.toNumber(),\n openTime: rpcData.openTime.toString(),\n tvl: 0,\n burnPercent: 0,\n\n day: mockRewardData,\n week: mockRewardData,\n month: mockRewardData,\n pooltype: [],\n\n farmUpcomingCount: 0,\n farmOngoingCount: 0,\n farmFinishedCount: 0,\n },\n poolKeys: {\n programId: rpcData.programId.toBase58(),\n id: poolId,\n mintA,\n mintB,\n openTime: rpcData.openTime.toString(),\n vault: { A: rpcData.vaultA.toBase58(), B: rpcData.vaultB.toBase58() },\n authority: getPdaPoolAuthority(rpcData.programId).publicKey.toBase58(),\n mintLp: lpMint,\n config: configInfo,\n observationId: getPdaObservationId(rpcData.programId, new PublicKey(poolId)).publicKey.toBase58(),\n },\n rpcData,\n };\n }\n\n public async createPool<T extends TxVersion>({\n poolId,\n programId,\n poolFeeAccount,\n startTime,\n ownerInfo,\n associatedOnly = false,\n checkCreateATAOwner = false,\n txVersion,\n feeConfig,\n computeBudgetConfig,\n txTipConfig,\n feePayer,\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(feePayer);\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) throw Error(\"you don't has some token account\");\n\n const poolKeys = getCreatePoolKeys({\n poolId,\n programId,\n configId: new PublicKey(feeConfig.id),\n mintA: mintAPubkey,\n mintB: mintBPubkey,\n });\n\n txBuilder.addInstruction({\n instructions: [\n makeCreateCpmmPoolInInstruction(\n programId,\n this.scope.ownerPubKey,\n new PublicKey(feeConfig.id),\n poolKeys.authority,\n poolKeys.poolId,\n mintAPubkey,\n mintBPubkey,\n poolKeys.lpMint,\n userVaultA,\n userVaultB,\n getATAAddress(this.scope.ownerPubKey, poolKeys.lpMint).publicKey,\n poolKeys.vaultA,\n poolKeys.vaultB,\n poolFeeAccount,\n new PublicKey(mintA.programId ?? TOKEN_PROGRAM_ID),\n new PublicKey(mintB.programId ?? TOKEN_PROGRAM_ID),\n poolKeys.observationId,\n mintAAmount,\n mintBAmount,\n startTime,\n ),\n ],\n instructionTypes: [InstructionType.CpmmCreatePool],\n });\n\n txBuilder.addCustomComputeBudget(computeBudgetConfig);\n txBuilder.addTipInstruction(txTipConfig);\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 baseIn,\n slippage,\n computeResult,\n computeBudgetConfig,\n txTipConfig,\n config,\n txVersion,\n feePayer,\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 lpAmount: new Decimal(rpcPoolData!.lpAmount.toString()).div(10 ** poolInfo.lpMint.decimals).toNumber(),\n },\n baseReserve: rpcPoolData!.baseReserve,\n quoteReserve: rpcPoolData!.quoteReserve,\n slippage: new Percent(0),\n baseIn,\n epochInfo: await this.scope.fetchEpochInfo(),\n amount: new Decimal(inputAmount.toString()).div(\n 10 ** (baseIn ? 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(feePayer);\n const [mintA, mintB] = [new PublicKey(poolInfo.mintA.address), new PublicKey(poolInfo.mintB.address)];\n\n const { account: tokenAccountA, instructionParams: _tokenAccountAInstruction } =\n await this.scope.account.getOrCreateTokenAccount({\n tokenProgram: poolInfo.mintA.programId,\n mint: new PublicKey(poolInfo.mintA.address),\n owner: this.scope.ownerPubKey,\n\n createInfo:\n mintAUseSOLBalance || (baseIn ? inputAmount : anotherAmount).isZero()\n ? {\n payer: this.scope.ownerPubKey,\n amount: baseIn ? 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: poolInfo.mintB.programId,\n mint: new PublicKey(poolInfo.mintB.address),\n owner: this.scope.ownerPubKey,\n\n createInfo:\n mintBUseSOLBalance || (baseIn ? anotherAmount : inputAmount).isZero()\n ? {\n payer: this.scope.ownerPubKey,\n amount: baseIn ? 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 lpTokenAccount = await account.getCreatedTokenAccount({\n mint: new PublicKey(poolInfo.lpMint.address),\n });\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 const poolKeys = propPoolKeys ?? (await this.getCpmmPoolKeys(poolInfo.id));\n const _slippage = new Percent(new BN(1)).sub(slippage);\n\n txBuilder.addInstruction({\n instructions: [\n makeDepositCpmmInInstruction(\n new PublicKey(poolInfo.programId),\n this.scope.ownerPubKey,\n new PublicKey(poolKeys.authority),\n new PublicKey(poolInfo.id),\n _lpTokenAccount!,\n tokenAccountA!,\n tokenAccountB!,\n new PublicKey(poolKeys.vault.A),\n new PublicKey(poolKeys.vault.B),\n mintA,\n mintB,\n new PublicKey(poolInfo.lpMint.address),\n\n computeResult ? computeResult?.liquidity : _slippage.mul(liquidity).quotient,\n baseIn ? inputAmountFee.amount : anotherAmount,\n baseIn ? anotherAmount : inputAmountFee.amount,\n ),\n ],\n instructionTypes: [InstructionType.CpmmAddLiquidity],\n lookupTableAddress: poolKeys.lookupTableAccount ? [poolKeys.lookupTableAccount] : [],\n });\n txBuilder.addCustomComputeBudget(computeBudgetConfig);\n txBuilder.addTipInstruction(txTipConfig);\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 {\n poolInfo,\n poolKeys: propPoolKeys,\n lpAmount,\n slippage,\n computeBudgetConfig,\n txTipConfig,\n txVersion,\n feePayer,\n closeWsol = true,\n } = params;\n\n if (this.scope.availability.addStandardPosition === false)\n this.logAndCreateError(\"add liquidity feature disabled in your region\");\n\n const _slippage = new Percent(new BN(1)).sub(slippage);\n\n const rpcPoolData = await this.getRpcPoolInfo(poolInfo.id);\n const [amountMintA, amountMintB] = [\n _slippage.mul(lpAmount.mul(rpcPoolData.baseReserve).div(rpcPoolData.lpAmount)).quotient,\n _slippage.mul(lpAmount.mul(rpcPoolData.quoteReserve).div(rpcPoolData.lpAmount)).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(feePayer);\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 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: poolInfo.mintA.programId,\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 && closeWsol),\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: poolInfo.mintB.programId,\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 && closeWsol),\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 lpTokenAccount = await account.getCreatedTokenAccount({\n mint: new PublicKey(poolInfo.lpMint.address),\n });\n\n if (!lpTokenAccount)\n this.logAndCreateError(\"cannot found lp token account\", \"tokenAccounts\", account.tokenAccounts);\n const poolKeys = propPoolKeys ?? (await this.getCpmmPoolKeys(poolInfo.id));\n txBuilder.addInstruction({\n instructions: [\n makeWithdrawCpmmInInstruction(\n new PublicKey(poolInfo.programId),\n this.scope.ownerPubKey,\n new PublicKey(poolKeys.authority),\n new PublicKey(poolInfo.id),\n lpTokenAccount!,\n tokenAccountA!,\n tokenAccountB!,\n new PublicKey(poolKeys.vault.A),\n new PublicKey(poolKeys.vault.B),\n mintA,\n mintB,\n new PublicKey(poolInfo.lpMint.address),\n\n lpAmount,\n amountMintA.sub(mintAAmountFee.fee ?? new BN(0)),\n amountMintB.sub(mintBAmountFee.fee ?? new BN(0)),\n ),\n ],\n instructionTypes: [InstructionType.CpmmWithdrawLiquidity],\n lookupTableAddress: poolKeys.lookupTableAccount ? [poolKeys.lookupTableAccount] : [],\n });\n txBuilder.addCustomComputeBudget(computeBudgetConfig);\n txBuilder.addTipInstruction(txTipConfig);\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 baseIn,\n fixedOut,\n inputAmount,\n swapResult,\n slippage = 0,\n config,\n computeBudgetConfig,\n txTipConfig,\n txVersion,\n feePayer,\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(feePayer);\n\n const [mintA, mintB] = [new PublicKey(poolInfo.mintA.address), new PublicKey(poolInfo.mintB.address)];\n\n if (!fixedOut) {\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 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(poolInfo.mintA.programId ?? TOKEN_PROGRAM_ID),\n owner: this.scope.ownerPubKey,\n createInfo:\n mintAUseSOLBalance || !baseIn\n ? {\n payer: this.scope.ownerPubKey,\n amount: baseIn ? 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(poolInfo.mintB.programId ?? TOKEN_PROGRAM_ID),\n owner: this.scope.ownerPubKey,\n createInfo:\n mintBUseSOLBalance || baseIn\n ? {\n payer: this.scope.ownerPubKey,\n amount: baseIn ? 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 poolKeys = propPoolKeys ?? (await this.getCpmmPoolKeys(poolInfo.id));\n\n txBuilder.addInstruction({\n instructions: [\n !fixedOut\n ? makeSwapCpmmBaseInInstruction(\n new PublicKey(poolInfo.programId),\n this.scope.ownerPubKey,\n new PublicKey(poolKeys.authority),\n new PublicKey(poolKeys.config.id),\n new PublicKey(poolInfo.id),\n baseIn ? mintATokenAcc! : mintBTokenAcc!,\n baseIn ? mintBTokenAcc! : mintATokenAcc!,\n new PublicKey(poolKeys.vault[baseIn ? \"A\" : \"B\"]),\n new PublicKey(poolKeys.vault[baseIn ? \"B\" : \"A\"]),\n new PublicKey(poolInfo[baseIn ? \"mintA\" : \"mintB\"].programId ?? TOKEN_PROGRAM_ID),\n new PublicKey(poolInfo[baseIn ? \"mintB\" : \"mintA\"].programId ?? TOKEN_PROGRAM_ID),\n baseIn ? mintA : mintB,\n baseIn ? mintB : mintA,\n getPdaObservationId(new PublicKey(poolInfo.programId), new PublicKey(poolInfo.id)).publicKey,\n\n inputAmount,\n swapResult.destinationAmountSwapped,\n )\n : makeSwapCpmmBaseOutInstruction(\n new PublicKey(poolInfo.programId),\n this.scope.ownerPubKey,\n new PublicKey(poolKeys.authority),\n new PublicKey(poolKeys.config.id),\n new PublicKey(poolInfo.id),\n\n baseIn ? mintATokenAcc! : mintBTokenAcc!,\n baseIn ? mintBTokenAcc! : mintATokenAcc!,\n\n new PublicKey(poolKeys.vault[baseIn ? \"A\" : \"B\"]),\n new PublicKey(poolKeys.vault[baseIn ? \"B\" : \"A\"]),\n new PublicKey(poolInfo[baseIn ? \"mintA\" : \"mintB\"].programId ?? TOKEN_PROGRAM_ID),\n new PublicKey(poolInfo[baseIn ? \"mintB\" : \"mintA\"].programId ?? TOKEN_PROGRAM_ID),\n baseIn ? mintA : mintB,\n baseIn ? mintB : mintA,\n\n getPdaObservationId(new PublicKey(poolInfo.programId), new PublicKey(poolInfo.id)).publicKey,\n\n swapResult.sourceAmountSwapped,\n swapResult.destinationAmountSwapped,\n ),\n ],\n instructionTypes: [fixedOut ? InstructionType.CpmmSwapBaseOut : InstructionType.ClmmSwapBaseIn],\n });\n\n txBuilder.addCustomComputeBudget(computeBudgetConfig);\n txBuilder.addTipInstruction(txTipConfig);\n return txBuilder.versionBuild({ txVersion }) as Promise<MakeTxData<T>>;\n }\n\n public async lockLp<T extends TxVersion>(params: LockCpmmLpParams<T>): Promise<MakeTxData<CpmmLockExtInfo>> {\n const { poolInfo, lpAmount, computeBudgetConfig, txTipConfig, txVersion, feePayer, feeNftOwner } = params;\n\n if (lpAmount.isZero())\n this.logAndCreateError(\"lpAmount must greater than zero\", {\n lpAmount: lpAmount.toString(),\n });\n\n const txBuilder = this.createTxBuilder(feePayer);\n\n const poolKeys = params.poolKeys ?? (await this.getCpmmPoolKeys(poolInfo.id));\n\n const insData = await makeCpmmLockInstruction({\n poolInfo,\n poolKeys,\n ownerInfo: {\n wallet: this.scope.ownerPubKey,\n feePayer: params.feePayer ?? this.scope.ownerPubKey,\n },\n feeNftOwner: feeNftOwner ?? this.scope.ownerPubKey,\n lockProgram: params.programId ?? LOCK_CPMM_PROGRAM,\n lockAuthProgram: params.authProgram ?? LOCK_CPMM_AUTH,\n lpAmount,\n withMetadata: params.withMetadata ?? true,\n getEphemeralSigners: params.getEphemeralSigners,\n });\n\n txBuilder.addInstruction(insData);\n txBuilder.addCustomComputeBudget(computeBudgetConfig);\n txBuilder.addTipInstruction(txTipConfig);\n return txBuilder.versionBuild({ txVersion, extInfo: insData.address }) as Promise<MakeTxData<CpmmLockExtInfo>>;\n }\n\n public async harvestLockLp<T extends TxVersion>(params: HarvestLockCpmmLpParams<T>): Promise<MakeTxData> {\n const {\n poolInfo,\n lpFeeAmount,\n nftMint,\n programId = LOCK_CPMM_PROGRAM,\n authProgram = LOCK_CPMM_AUTH,\n cpmmProgram,\n computeBudgetConfig,\n txTipConfig,\n txVersion,\n closeWsol = true,\n } = params;\n\n if (lpFeeAmount.isZero())\n this.logAndCreateError(\"lpFeeAmount must greater than zero\", {\n lpAmount: lpFeeAmount.toString(),\n });\n\n const feePayer = params.feePayer || this.scope.ownerPubKey;\n\n const txBuilder = this.createTxBuilder(feePayer);\n\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 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: poolInfo.mintA.programId,\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 && closeWsol),\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: poolInfo.mintB.programId,\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 && closeWsol),\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\", { tokenAccountA, tokenAccountB });\n\n const poolKeys = params.poolKeys ?? (await this.getCpmmPoolKeys(poolInfo.id));\n\n const { publicKey: nftAccount } = getATAAddress(feePayer, nftMint, TOKEN_PROGRAM_ID);\n const { publicKey: lockPda } = getCpLockPda(programId, nftMint);\n const { publicKey: lockLpVault } = getATAAddress(\n authProgram,\n new PublicKey(poolInfo.lpMint.address),\n TOKEN_PROGRAM_ID,\n );\n\n txBuilder.addInstruction({\n instructions: [\n collectCpFeeInstruction({\n programId: programId ?? LOCK_CPMM_PROGRAM,\n nftOwner: this.scope.ownerPubKey,\n auth: authProgram ?? LOCK_CPMM_AUTH,\n\n nftMint,\n nftAccount,\n\n lockPda,\n poolId: new PublicKey(poolInfo.id),\n mintLp: new PublicKey(poolKeys.mintLp.address),\n\n userVaultA: tokenAccountA!,\n userVaultB: tokenAccountB!,\n poolVaultA: new PublicKey(poolKeys.vault.A),\n poolVaultB: new PublicKey(poolKeys.vault.B),\n\n mintA,\n mintB,\n lockLpVault,\n lpFeeAmount,\n\n cpmmProgram: cpmmProgram?.programId,\n cpmmAuthProgram: cpmmProgram?.authProgram,\n }),\n ],\n instructionTypes: [InstructionType.CpmmCollectLockFee],\n });\n\n txBuilder.addCustomComputeBudget(computeBudgetConfig);\n txBuilder.addTipInstruction(txTipConfig);\n return txBuilder.versionBuild({ txVersion }) as Promise<MakeTxData>;\n }\n\n public computeSwapAmount({\n pool,\n amountIn,\n outputMint,\n slippage,\n }: {\n pool: CpmmComputeData;\n amountIn: BN;\n outputMint: string | PublicKey;\n slippage: number;\n }): {\n allTrade: boolean;\n amountIn: BN;\n amountOut: BN;\n minAmountOut: BN;\n fee: BN;\n executionPrice: Decimal;\n priceImpact: any;\n } {\n const isBaseIn = outputMint.toString() === pool.mintB.address;\n\n const swapResult = CurveCalculator.swap(\n amountIn,\n isBaseIn ? pool.baseReserve : pool.quoteReserve,\n isBaseIn ? pool.quoteReserve : pool.baseReserve,\n pool.configInfo.tradeFeeRate,\n );\n\n const executionPrice = new Decimal(swapResult.destinationAmountSwapped.toString()).div(\n swapResult.sourceAmountSwapped.toString(),\n );\n\n const minAmountOut = swapResult.destinationAmountSwapped.mul(new BN((1 - slippage) * 10000)).div(new BN(10000));\n\n return {\n allTrade: swapResult.sourceAmountSwapped.eq(amountIn),\n amountIn,\n amountOut: swapResult.destinationAmountSwapped,\n minAmountOut,\n executionPrice,\n fee: swapResult.tradeFee,\n priceImpact: pool.poolPrice.sub(executionPrice).div(pool.poolPrice),\n };\n }\n\n public computePairAmount({\n poolInfo,\n baseReserve,\n quoteReserve,\n amount,\n slippage,\n epochInfo,\n baseIn,\n }: ComputePairAmountParams): {\n inputAmountFee: GetTransferAmountFee;\n anotherAmount: GetTransferAmountFee;\n maxAnotherAmount: GetTransferAmountFee;\n minAnotherAmount: 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[baseIn ? \"mintA\" : \"mintB\"].decimals)\n .mul(coefficient)\n .toFixed(0),\n );\n const inputAmountFee = getTransferAmountFeeV2(\n inputAmount,\n poolInfo[baseIn ? \"mintA\" : \"mintB\"].extensions.feeConfig,\n epochInfo,\n false,\n );\n const _inputAmountWithoutFee = inputAmount.sub(inputAmountFee.fee ?? new BN(0));\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 \"amountInFee:\",\n inputAmountFee.fee?.toString() ?? 0,\n \"anotherToken:\",\n baseIn ? poolInfo.mintB.symbol : poolInfo.mintA.symbol,\n \"slippage:\",\n `${slippage.toSignificant()}%`,\n );\n\n // input is fixed\n const input = baseIn ? \"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[baseIn ? \"amountB\" : \"amountA\"],\n poolInfo[baseIn ? \"mintB\" : \"mintA\"].extensions.feeConfig,\n epochInfo,\n true,\n );\n }\n\n const _slippage = new Percent(new BN(1)).add(slippage);\n const _slippageMin = new Percent(new BN(1)).sub(slippage);\n const slippageAdjustedAmount = getTransferAmountFeeV2(\n _slippage.mul(anotherAmountFee.amount.sub(anotherAmountFee.fee ?? new BN(0))).quotient,\n poolInfo[baseIn ? \"mintB\" : \"mintA\"].extensions.feeConfig,\n epochInfo,\n true,\n );\n const slippageAdjustedMinAmount = getTransferAmountFeeV2(\n _slippageMin.mul(anotherAmountFee.amount.sub(anotherAmountFee.fee ?? new BN(0))).quotient,\n poolInfo[baseIn ? \"mintB\" : \"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 minAnotherAmount: slippageAdjustedMinAmount,\n liquidity,\n };\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).isZero()) amountA = amountA.add(new BN(1));\n let amountB = lp.mul(poolAmountB).div(supply);\n if (!amountB.isZero() && !lp.mul(poolAmountB).mod(supply).isZero()) amountB = amountB.add(new BN(1));\n\n return {\n amountA,\n amountB,\n };\n}\n","import BN from \"bn.js\";\nimport Decimal from \"decimal.js\";\nimport { CurrencyAmount, TokenAmount } from \"../module/amount\";\nimport { Currency } from \"../module/currency\";\nimport { Fraction } from \"../module/fraction\";\nimport { Percent } from \"../module/percent\";\nimport { Price } from \"../module/price\";\nimport { Token } from \"../module/token\";\nimport { SplToken, TokenJson } from \"../raydium/token/type\";\nimport { ReplaceType } from \"../raydium/type\";\nimport { parseBigNumberish } from \"./constant\";\nimport { mul } from \"./fractionUtil\";\nimport { notInnerObject } from \"./utility\";\n\nexport const BN_ZERO = new BN(0);\nexport const BN_ONE = new BN(1);\nexport const BN_TWO = new BN(2);\nexport const BN_THREE = new BN(3);\nexport const BN_FIVE = new BN(5);\nexport const BN_TEN = new BN(10);\nexport const BN_100 = new BN(100);\nexport const BN_1000 = new BN(1000);\nexport const BN_10000 = new BN(10000);\nexport type BigNumberish = BN | string | number | bigint;\nexport type Numberish = number | string | bigint | Fraction | BN;\n\nexport function tenExponential(shift: BigNumberish): BN {\n return BN_TEN.pow(parseBigNumberish(shift));\n}\n\n/**\n *\n * @example\n * getIntInfo(0.34) => { numerator: '34', denominator: '100'}\n * getIntInfo('0.34') //=> { numerator: '34', denominator: '100'}\n */\nexport function parseNumberInfo(n: Numberish | undefined): {\n denominator: string;\n numerator: string;\n sign?: string;\n int?: string;\n dec?: string;\n} {\n if (n === undefined) return { denominator: \"1\", numerator: \"0\" };\n if (n instanceof BN) {\n return { numerator: n.toString(), denominator: \"1\" };\n }\n\n if (n instanceof Fraction) {\n return { denominator: n.denominator.toString(), numerator: n.numerator.toString() };\n }\n\n const s = String(n);\n const [, sign = \"\", int = \"\", dec = \"\"] = s.replace(\",\", \"\").match(/(-?)(\\d*)\\.?(\\d*)/) ?? [];\n const denominator = \"1\" + \"0\".repeat(dec.length);\n const numerator = sign + (int === \"0\" ? \"\" : int) + dec || \"0\";\n return { denominator, numerator, sign, int, dec };\n}\n\n// round up\nexport function divCeil(a: BN, b: BN): BN {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n const dm = a.divmod(b);\n\n // Fast case - exact division\n if (dm.mod.isZero()) return dm.div;\n\n // Round up\n return dm.div.isNeg() ? dm.div.isubn(1) : dm.div.iaddn(1);\n}\n\nexport function shakeFractionDecimal(n: Fraction): string {\n const [, sign = \"\", int = \"\"] = n.toFixed(2).match(/(-?)(\\d*)\\.?(\\d*)/) ?? [];\n return `${sign}${int}`;\n}\n\nexport function toBN(n: Numberish, decimal: BigNumberish = 0): BN {\n if (n instanceof BN) return n;\n return new BN(shakeFractionDecimal(toFraction(n).mul(BN_TEN.pow(new BN(String(decimal))))));\n}\n\nexport function toFraction(value: Numberish): Fraction {\n // to complete math format(may have decimal), not int\n if (value instanceof Percent) return new Fraction(value.numerator, value.denominator);\n\n if (value instanceof Price) return value.adjusted;\n\n // to complete math format(may have decimal), not BN\n if (value instanceof TokenAmount)\n try {\n return toFraction(value.toExact());\n } catch {\n return new Fraction(BN_ZERO);\n }\n\n // do not ideal with other fraction value\n if (value instanceof Fraction) return value;\n\n // wrap to Fraction\n const n = String(value);\n const details = parseNumberInfo(n);\n return new Fraction(details.numerator, details.denominator);\n}\n\nexport function ceilDiv(tokenAmount: BN, feeNumerator: BN, feeDenominator: BN): BN {\n return tokenAmount.mul(feeNumerator).add(feeDenominator).sub(new BN(1)).div(feeDenominator);\n}\n\nexport function floorDiv(tokenAmount: BN, feeNumerator: BN, feeDenominator: BN): BN {\n return tokenAmount.mul(feeNumerator).div(feeDenominator);\n}\n\n/**\n * @example\n * toPercent(3.14) // => Percent { 314.00% }\n * toPercent(3.14, { alreadyDecimaled: true }) // => Percent {3.14%}\n */\nexport function toPercent(\n n: Numberish,\n options?: { /* usually used for backend data */ alreadyDecimaled?: boolean },\n): Percent {\n const { numerator, denominator } = parseNumberInfo(n);\n return new Percent(new BN(numerator), new BN(denominator).mul(options?.alreadyDecimaled ? new BN(100) : new BN(1)));\n}\n\nexport function toTokenPrice(params: {\n token: TokenJson | Token | SplToken;\n numberPrice: Numberish;\n decimalDone?: boolean;\n}): Price {\n const { token, numberPrice, decimalDone } = params;\n const usdCurrency = new Token({ mint: \"\", decimals: 6, symbol: \"usd\", name: \"usd\", skipMint: true });\n const { numerator, denominator } = parseNumberInfo(numberPrice);\n const parsedNumerator = decimalDone ? new BN(numerator).mul(BN_TEN.pow(new BN(token.decimals))) : numerator;\n const parsedDenominator = new BN(denominator).mul(BN_TEN.pow(new BN(usdCurrency.decimals)));\n\n return new Price({\n baseToken: usdCurrency,\n denominator: parsedDenominator.toString(),\n quoteToken: new Token({ ...token, skipMint: true, mint: \"\" }),\n numerator: parsedNumerator.toString(),\n });\n}\n\nexport function toUsdCurrency(amount: Numberish): CurrencyAmount {\n const usdCurrency = new Currency({ decimals: 6, symbol: \"usd\", name: \"usd\" });\n const amountBigNumber = toBN(mul(amount, 10 ** usdCurrency.decimals)!);\n return new CurrencyAmount(usdCurrency, amountBigNumber);\n}\n\nexport function toTotalPrice(amount: Numberish | undefined, price: Price | undefined): CurrencyAmount {\n if (!price || !amount) return toUsdCurrency(0);\n return toUsdCurrency(mul(amount, price)!);\n}\n\nexport function decimalToFraction(n: Decimal | undefined): Fraction | undefined {\n if (n == null) return undefined;\n const { numerator, denominator } = parseNumberInfo(n.toString());\n return new Fraction(numerator, denominator);\n}\n\nexport function isDecimal(val: unknown): boolean {\n return val instanceof Decimal;\n}\n\nexport function recursivelyDecimalToFraction<T>(info: T): ReplaceType<T, Decimal, Fraction> {\n // @ts-expect-error no need type for inner code\n return isDecimal(info)\n ? decimalToFraction(info as any)\n : Array.isArray(info)\n ? info.map((k) => recursivelyDecimalToFraction(k))\n : notInnerObject(info)\n ? Object.fromEntries(Object.entries(info as any).map(([k, v]) => [k, recursivelyDecimalToFraction(v)]))\n : info;\n}\n","/*\r\n * decimal.js v10.3.1\r\n * An arbitrary-precision Decimal type for JavaScript.\r\n * https://github.com/MikeMcl/decimal.js\r\n * Copyright (c) 2021 Michael Mclaughlin <M8ch88l@gmail.com>\r\n * MIT Licence\r\n */\r\n\r\n\r\n// ----------------------------------- EDITABLE DEFAULTS ------------------------------------ //\r\n\r\n\r\n // The maximum exponent magnitude.\r\n // The limit on the value of `toExpNeg`, `toExpPos`, `minE` and `maxE`.\r\nvar EXP_LIMIT = 9e15, // 0 to 9e15\r\n\r\n // The limit on the value of `precision`, and on the value of the first argument to\r\n // `toDecimalPlaces`, `toExponential`, `toFixed`, `toPrecision` an