UNPKG

snapper-sdk

Version:

An SDK for building applications on top of Snapper.

1 lines 552 kB
{"version":3,"sources":["../../../../src/raydium/clmm/utils/pool.ts","../../../../node_modules/decimal.js/decimal.mjs","../../../../src/common/accountInfo.ts","../../../../src/common/logger.ts","../../../../src/common/bignumber.ts","../../../../src/module/amount.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/utility.ts","../../../../src/common/lodash.ts","../../../../src/common/pda.ts","../../../../src/common/txTool/txUtils.ts","../../../../src/common/programId.ts","../../../../src/common/transfer.ts","../../../../src/common/txTool/lookupTable.ts","../../../../src/common/txTool/txTool.ts","../../../../src/marshmallow/index.ts","../../../../src/marshmallow/buffer-layout.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/tickQuery.ts","../../../../src/raydium/clmm/utils/tickarrayBitmap.ts","../../../../src/raydium/clmm/layout.ts","../../../../src/raydium/clmm/utils/position.ts"],"sourcesContent":["import { Connection, EpochInfo, PublicKey } from \"@solana/web3.js\";\nimport { TOKEN_2022_PROGRAM_ID } from \"@solana/spl-token\";\nimport BN from \"bn.js\";\n\nimport {\n ClmmPoolInfo,\n ClmmPoolRewardInfo,\n ClmmPoolRewardLayoutInfo,\n ComputeClmmPoolInfo,\n ReturnTypeComputeAmountOut,\n ReturnTypeComputeAmountOutBaseOut,\n ReturnTypeComputeAmountOutFormat,\n ReturnTypeFetchExBitmaps,\n ReturnTypeFetchMultiplePoolTickArrays,\n ReturnTypeGetLiquidityAmountOut,\n SDKParsedConcentratedInfo,\n TickArrayBitmapExtensionType,\n} from \"../type\";\n\nimport { ApiV3PoolInfoConcentratedItem, ApiV3Token } from \"@/api/type\";\n\nimport Decimal from \"decimal.js\";\nimport {\n getMultipleAccountsInfo,\n getMultipleAccountsInfoWithCustomFlags,\n getTransferAmountFeeV2,\n minExpirationTime,\n solToWSol,\n} from \"@/common\";\nimport { Percent, Price, Token, TokenAmount } from \"@/module\";\nimport { TokenAccountRaw } from \"@/raydium/account/types\";\nimport { PoolInfoLayout, PositionInfoLayout, TickArrayBitmapExtensionLayout, TickArrayLayout } from \"../layout\";\nimport { MAX_SQRT_PRICE_X64, MAX_TICK, MIN_SQRT_PRICE_X64, MIN_TICK, NEGATIVE_ONE, Q64, ZERO } from \"./constants\";\nimport { LiquidityMath, MathUtil, SqrtPriceMath, SwapMath } from \"./math\";\nimport { getPdaExBitmapAccount, getPdaPersonalPositionAddress, getPdaTickArrayAddress } from \"./pda\";\nimport { PositionUtils } from \"./position\";\nimport { TICK_ARRAY_BITMAP_SIZE, Tick, TickArray, TickUtils } from \"./tick\";\nimport { TickArrayBitmap, TickArrayBitmapExtensionUtils } from \"./tickarrayBitmap\";\nimport { TickQuery } from \"./tickQuery\";\n\nexport class PoolUtils {\n public static getOutputAmountAndRemainAccounts(\n poolInfo: ComputeClmmPoolInfo,\n tickArrayCache: { [key: string]: TickArray },\n inputTokenMint: PublicKey,\n inputAmount: BN,\n sqrtPriceLimitX64?: BN,\n catchLiquidityInsufficient = false,\n ): {\n allTrade: boolean;\n expectedAmountOut: BN;\n remainingAccounts: PublicKey[];\n executionPrice: BN;\n feeAmount: BN;\n } {\n const zeroForOne = inputTokenMint.toBase58() === poolInfo.mintA.address;\n\n const allNeededAccounts: PublicKey[] = [];\n const {\n isExist,\n startIndex: firstTickArrayStartIndex,\n nextAccountMeta,\n } = this.getFirstInitializedTickArray(poolInfo, zeroForOne);\n if (!isExist || firstTickArrayStartIndex === undefined || !nextAccountMeta) throw new Error(\"Invalid tick array\");\n\n // try {\n // const preTick = this.preInitializedTickArrayStartIndex(poolInfo, !zeroForOne)\n // if (preTick.isExist) {\n // const { publicKey: address } = getPdaTickArrayAddress(\n // poolInfo.programId,\n // poolInfo.id,\n // preTick.nextStartIndex\n // );\n // allNeededAccounts.push(address)\n // }\n // } catch (e) { /* empty */ }\n\n allNeededAccounts.push(nextAccountMeta);\n const {\n allTrade,\n amountCalculated: outputAmount,\n accounts: reaminAccounts,\n sqrtPriceX64: executionPrice,\n feeAmount,\n } = SwapMath.swapCompute(\n poolInfo.programId,\n poolInfo.id,\n tickArrayCache,\n poolInfo.tickArrayBitmap,\n poolInfo.exBitmapInfo,\n zeroForOne,\n poolInfo.ammConfig.tradeFeeRate,\n poolInfo.liquidity,\n poolInfo.tickCurrent,\n poolInfo.tickSpacing,\n poolInfo.sqrtPriceX64,\n inputAmount,\n firstTickArrayStartIndex,\n sqrtPriceLimitX64,\n catchLiquidityInsufficient,\n );\n allNeededAccounts.push(...reaminAccounts);\n return {\n allTrade,\n expectedAmountOut: outputAmount.mul(NEGATIVE_ONE),\n remainingAccounts: allNeededAccounts,\n executionPrice,\n feeAmount,\n };\n }\n\n public static getInputAmountAndRemainAccounts(\n poolInfo: ComputeClmmPoolInfo,\n tickArrayCache: { [key: string]: TickArray },\n outputTokenMint: PublicKey,\n outputAmount: BN,\n sqrtPriceLimitX64?: BN,\n ): { expectedAmountIn: BN; remainingAccounts: PublicKey[]; executionPrice: BN; feeAmount: BN } {\n const zeroForOne = outputTokenMint.toBase58() === poolInfo.mintB.address;\n\n const allNeededAccounts: PublicKey[] = [];\n const {\n isExist,\n startIndex: firstTickArrayStartIndex,\n nextAccountMeta,\n } = this.getFirstInitializedTickArray(poolInfo, zeroForOne);\n if (!isExist || firstTickArrayStartIndex === undefined || !nextAccountMeta) throw new Error(\"Invalid tick array\");\n\n try {\n const preTick = this.preInitializedTickArrayStartIndex(poolInfo, zeroForOne);\n if (preTick.isExist) {\n const { publicKey: address } = getPdaTickArrayAddress(poolInfo.programId, poolInfo.id, preTick.nextStartIndex);\n allNeededAccounts.push(address);\n }\n } catch (e) {\n /* empty */\n }\n\n allNeededAccounts.push(nextAccountMeta);\n const {\n amountCalculated: inputAmount,\n accounts: reaminAccounts,\n sqrtPriceX64: executionPrice,\n feeAmount,\n } = SwapMath.swapCompute(\n poolInfo.programId,\n poolInfo.id,\n tickArrayCache,\n poolInfo.tickArrayBitmap,\n poolInfo.exBitmapInfo,\n zeroForOne,\n poolInfo.ammConfig.tradeFeeRate,\n poolInfo.liquidity,\n poolInfo.tickCurrent,\n poolInfo.tickSpacing,\n poolInfo.sqrtPriceX64,\n outputAmount.mul(NEGATIVE_ONE),\n firstTickArrayStartIndex,\n sqrtPriceLimitX64,\n );\n allNeededAccounts.push(...reaminAccounts);\n return { expectedAmountIn: inputAmount, remainingAccounts: allNeededAccounts, executionPrice, feeAmount };\n }\n\n public static getFirstInitializedTickArray(\n poolInfo: ComputeClmmPoolInfo,\n zeroForOne: boolean,\n ):\n | { isExist: true; startIndex: number; nextAccountMeta: PublicKey }\n | { isExist: false; startIndex: undefined; nextAccountMeta: undefined } {\n const { isInitialized, startIndex } = PoolUtils.isOverflowDefaultTickarrayBitmap(poolInfo.tickSpacing, [\n poolInfo.tickCurrent,\n ])\n ? TickArrayBitmapExtensionUtils.checkTickArrayIsInit(\n TickQuery.getArrayStartIndex(poolInfo.tickCurrent, poolInfo.tickSpacing),\n poolInfo.tickSpacing,\n poolInfo.exBitmapInfo,\n )\n : TickUtils.checkTickArrayIsInitialized(\n TickUtils.mergeTickArrayBitmap(poolInfo.tickArrayBitmap),\n poolInfo.tickCurrent,\n poolInfo.tickSpacing,\n );\n\n if (isInitialized) {\n const { publicKey: address } = getPdaTickArrayAddress(poolInfo.programId, poolInfo.id, startIndex);\n return {\n isExist: true,\n startIndex,\n nextAccountMeta: address,\n };\n }\n const { isExist, nextStartIndex } = this.nextInitializedTickArrayStartIndex(\n poolInfo,\n TickQuery.getArrayStartIndex(poolInfo.tickCurrent, poolInfo.tickSpacing),\n zeroForOne,\n );\n if (isExist) {\n const { publicKey: address } = getPdaTickArrayAddress(poolInfo.programId, poolInfo.id, nextStartIndex);\n return {\n isExist: true,\n startIndex: nextStartIndex,\n nextAccountMeta: address,\n };\n }\n return { isExist: false, nextAccountMeta: undefined, startIndex: undefined };\n }\n\n public static preInitializedTickArrayStartIndex(\n poolInfo: ComputeClmmPoolInfo,\n zeroForOne: boolean,\n ): { isExist: boolean; nextStartIndex: number } {\n const currentOffset = Math.floor(poolInfo.tickCurrent / TickQuery.tickCount(poolInfo.tickSpacing));\n\n const result: number[] = !zeroForOne\n ? TickUtils.searchLowBitFromStart(\n poolInfo.tickArrayBitmap,\n poolInfo.exBitmapInfo,\n currentOffset - 1,\n 1,\n poolInfo.tickSpacing,\n )\n : TickUtils.searchHightBitFromStart(\n poolInfo.tickArrayBitmap,\n poolInfo.exBitmapInfo,\n currentOffset + 1,\n 1,\n poolInfo.tickSpacing,\n );\n\n return result.length > 0 ? { isExist: true, nextStartIndex: result[0] } : { isExist: false, nextStartIndex: 0 };\n }\n\n public static nextInitializedTickArrayStartIndex(\n poolInfo:\n | {\n tickCurrent: number;\n tickSpacing: number;\n tickArrayBitmap: BN[];\n exBitmapInfo: TickArrayBitmapExtensionType;\n }\n | ClmmPoolInfo,\n lastTickArrayStartIndex: number,\n zeroForOne: boolean,\n ): { isExist: boolean; nextStartIndex: number } {\n lastTickArrayStartIndex = TickQuery.getArrayStartIndex(poolInfo.tickCurrent, poolInfo.tickSpacing);\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const { isInit: startIsInit, tickIndex: startIndex } = TickArrayBitmap.nextInitializedTickArrayStartIndex(\n TickUtils.mergeTickArrayBitmap(poolInfo.tickArrayBitmap),\n lastTickArrayStartIndex,\n poolInfo.tickSpacing,\n zeroForOne,\n );\n if (startIsInit) {\n return { isExist: true, nextStartIndex: startIndex };\n }\n lastTickArrayStartIndex = startIndex;\n\n const { isInit, tickIndex } = TickArrayBitmapExtensionUtils.nextInitializedTickArrayFromOneBitmap(\n lastTickArrayStartIndex,\n poolInfo.tickSpacing,\n zeroForOne,\n poolInfo.exBitmapInfo,\n );\n if (isInit) return { isExist: true, nextStartIndex: tickIndex };\n\n lastTickArrayStartIndex = tickIndex;\n\n if (lastTickArrayStartIndex < MIN_TICK || lastTickArrayStartIndex > MAX_TICK)\n return { isExist: false, nextStartIndex: 0 };\n }\n\n // const tickArrayBitmap = TickUtils.mergeTickArrayBitmap(\n // poolInfo.tickArrayBitmap\n // );\n // const currentOffset = TickUtils.getTickArrayOffsetInBitmapByTick(\n // poolInfo.tickCurrent,\n // poolInfo.tickSpacing\n // );\n // const result: number[] = zeroForOne ? TickUtils.searchLowBitFromStart(\n // tickArrayBitmap,\n // currentOffset - 1,\n // 0,\n // 1,\n // poolInfo.tickSpacing\n // ) : TickUtils.searchHightBitFromStart(\n // tickArrayBitmap,\n // currentOffset,\n // 1024,\n // 1,\n // poolInfo.tickSpacing\n // );\n\n // return result.length > 0 ? { isExist: true, nextStartIndex: result[0] } : { isExist: false, nextStartIndex: 0 }\n }\n\n public static async updatePoolRewardInfos({\n connection,\n apiPoolInfo,\n chainTime,\n poolLiquidity,\n rewardInfos,\n }: {\n connection: Connection;\n apiPoolInfo: ApiV3PoolInfoConcentratedItem;\n chainTime: number;\n poolLiquidity: BN;\n rewardInfos: ClmmPoolRewardLayoutInfo[];\n }): Promise<ClmmPoolRewardInfo[]> {\n const nRewardInfo: ClmmPoolRewardInfo[] = [];\n for (let i = 0; i < rewardInfos.length; i++) {\n const _itemReward = rewardInfos[i];\n const apiRewardProgram =\n apiPoolInfo.rewardDefaultInfos[i]?.mint.programId ??\n (await connection.getAccountInfo(_itemReward.tokenMint))?.owner;\n if (apiRewardProgram === undefined) throw Error(\"get new reward mint info error\");\n\n const itemReward: ClmmPoolRewardInfo = {\n ..._itemReward,\n perSecond: MathUtil.x64ToDecimal(_itemReward.emissionsPerSecondX64),\n remainingRewards: undefined,\n tokenProgramId: new PublicKey(apiRewardProgram),\n };\n\n if (itemReward.tokenMint.equals(PublicKey.default)) continue;\n if (chainTime <= itemReward.openTime.toNumber() || poolLiquidity.eq(ZERO)) {\n nRewardInfo.push(itemReward);\n continue;\n }\n\n const latestUpdateTime = new BN(Math.min(itemReward.endTime.toNumber(), chainTime));\n const timeDelta = latestUpdateTime.sub(itemReward.lastUpdateTime);\n const rewardGrowthDeltaX64 = MathUtil.mulDivFloor(timeDelta, itemReward.emissionsPerSecondX64, poolLiquidity);\n const rewardGrowthGlobalX64 = itemReward.rewardGrowthGlobalX64.add(rewardGrowthDeltaX64);\n const rewardEmissionedDelta = MathUtil.mulDivFloor(timeDelta, itemReward.emissionsPerSecondX64, Q64);\n const rewardTotalEmissioned = itemReward.rewardTotalEmissioned.add(rewardEmissionedDelta);\n nRewardInfo.push({\n ...itemReward,\n rewardGrowthGlobalX64,\n rewardTotalEmissioned,\n lastUpdateTime: latestUpdateTime,\n });\n }\n return nRewardInfo;\n }\n\n public static isOverflowDefaultTickarrayBitmap(tickSpacing: number, tickarrayStartIndexs: number[]): boolean {\n const { maxTickBoundary, minTickBoundary } = this.tickRange(tickSpacing);\n\n for (const tickIndex of tickarrayStartIndexs) {\n const tickarrayStartIndex = TickUtils.getTickArrayStartIndexByTick(tickIndex, tickSpacing);\n\n if (tickarrayStartIndex >= maxTickBoundary || tickarrayStartIndex < minTickBoundary) {\n return true;\n }\n }\n\n return false;\n }\n\n public static tickRange(tickSpacing: number): {\n maxTickBoundary: number;\n minTickBoundary: number;\n } {\n let maxTickBoundary = TickArrayBitmap.maxTickInTickarrayBitmap(tickSpacing);\n let minTickBoundary = -maxTickBoundary;\n\n if (maxTickBoundary > MAX_TICK) {\n maxTickBoundary = TickQuery.getArrayStartIndex(MAX_TICK, tickSpacing) + TickQuery.tickCount(tickSpacing);\n }\n if (minTickBoundary < MIN_TICK) {\n minTickBoundary = TickQuery.getArrayStartIndex(MIN_TICK, tickSpacing);\n }\n return { maxTickBoundary, minTickBoundary };\n }\n\n public static get_tick_array_offset(tickarrayStartIndex: number, tickSpacing: number): number {\n if (!TickQuery.checkIsValidStartIndex(tickarrayStartIndex, tickSpacing)) {\n throw new Error(\"No enough initialized tickArray\");\n }\n\n return (tickarrayStartIndex / TickQuery.tickCount(tickSpacing)) * TICK_ARRAY_BITMAP_SIZE;\n }\n\n static async fetchExBitmaps({\n connection,\n exBitmapAddress,\n batchRequest,\n }: {\n connection: Connection;\n exBitmapAddress: PublicKey[];\n batchRequest: boolean;\n }): Promise<ReturnTypeFetchExBitmaps> {\n const fetchedBitmapAccount = await getMultipleAccountsInfoWithCustomFlags(\n connection,\n exBitmapAddress.map((i) => ({ pubkey: i })),\n { batchRequest },\n );\n\n const returnTypeFetchExBitmaps: ReturnTypeFetchExBitmaps = {};\n for (const item of fetchedBitmapAccount) {\n if (item.accountInfo === null) continue;\n\n returnTypeFetchExBitmaps[item.pubkey.toString()] = TickArrayBitmapExtensionLayout.decode(item.accountInfo.data);\n }\n return returnTypeFetchExBitmaps;\n }\n\n static async fetchMultiplePoolTickArrays({\n connection,\n poolKeys,\n batchRequest,\n }: {\n connection: Connection;\n poolKeys: Omit<ComputeClmmPoolInfo, \"ammConfig\">[];\n batchRequest?: boolean;\n }): Promise<ReturnTypeFetchMultiplePoolTickArrays> {\n const tickArraysToPoolId: { [key: string]: PublicKey } = {};\n const tickArrays: { pubkey: PublicKey }[] = [];\n for (const itemPoolInfo of poolKeys) {\n const currentTickArrayStartIndex = TickUtils.getTickArrayStartIndexByTick(\n itemPoolInfo.tickCurrent,\n itemPoolInfo.tickSpacing,\n );\n const startIndexArray = TickUtils.getInitializedTickArrayInRange(\n itemPoolInfo.tickArrayBitmap,\n itemPoolInfo.exBitmapInfo,\n itemPoolInfo.tickSpacing,\n currentTickArrayStartIndex,\n 7,\n );\n for (const itemIndex of startIndexArray) {\n const { publicKey: tickArrayAddress } = getPdaTickArrayAddress(\n itemPoolInfo.programId,\n itemPoolInfo.id,\n itemIndex,\n );\n tickArrays.push({ pubkey: tickArrayAddress });\n tickArraysToPoolId[tickArrayAddress.toString()] = itemPoolInfo.id;\n }\n }\n\n const fetchedTickArrays = await getMultipleAccountsInfoWithCustomFlags(connection, tickArrays, { batchRequest });\n\n const tickArrayCache: ReturnTypeFetchMultiplePoolTickArrays = {};\n\n for (const itemAccountInfo of fetchedTickArrays) {\n if (!itemAccountInfo.accountInfo) continue;\n const poolId = tickArraysToPoolId[itemAccountInfo.pubkey.toString()];\n if (!poolId) continue;\n if (tickArrayCache[poolId.toString()] === undefined) tickArrayCache[poolId.toString()] = {};\n\n const accountLayoutData = TickArrayLayout.decode(itemAccountInfo.accountInfo.data);\n\n tickArrayCache[poolId.toString()][accountLayoutData.startTickIndex] = {\n ...accountLayoutData,\n address: itemAccountInfo.pubkey,\n };\n }\n return tickArrayCache;\n }\n\n // deprecated, new api doesn't need\n static async fetchPoolsAccountPosition({\n pools,\n connection,\n ownerInfo,\n batchRequest = false,\n updateOwnerRewardAndFee = true,\n }: {\n pools: SDKParsedConcentratedInfo[];\n connection: Connection;\n ownerInfo: { wallet: PublicKey; tokenAccounts: TokenAccountRaw[] };\n batchRequest?: boolean;\n updateOwnerRewardAndFee?: boolean;\n }): Promise<SDKParsedConcentratedInfo[]> {\n const programIds: PublicKey[] = [];\n\n for (let index = 0; index < pools.length; index++) {\n const accountInfo = pools[index];\n\n if (accountInfo === null) continue;\n\n if (!programIds.find((i) => i.equals(accountInfo.state.programId))) programIds.push(accountInfo.state.programId);\n }\n\n if (ownerInfo) {\n const allMint = ownerInfo.tokenAccounts.map((i) => i.accountInfo.mint);\n const allPositionKey: PublicKey[] = [];\n for (const itemMint of allMint) {\n for (const itemProgramId of programIds) {\n allPositionKey.push(getPdaPersonalPositionAddress(itemProgramId, itemMint).publicKey);\n }\n }\n const positionAccountInfos = await getMultipleAccountsInfo(connection, allPositionKey, { batchRequest });\n const keyToTickArrayAddress: { [key: string]: PublicKey } = {};\n for (const itemAccountInfo of positionAccountInfos) {\n if (itemAccountInfo === null) continue;\n // TODO: add check\n\n const position = PositionInfoLayout.decode(itemAccountInfo.data);\n const itemPoolId = position.poolId.toString();\n const poolInfoA = pools.find((pool) => pool.state.id.toBase58() === itemPoolId);\n if (poolInfoA === undefined) continue;\n\n const poolInfo = poolInfoA.state;\n\n const priceLower = TickUtils._getTickPriceLegacy({\n poolInfo,\n tick: position.tickLower,\n baseIn: true,\n });\n const priceUpper = TickUtils._getTickPriceLegacy({\n poolInfo,\n tick: position.tickUpper,\n baseIn: true,\n });\n const { amountA, amountB } = LiquidityMath.getAmountsFromLiquidity(\n poolInfo.sqrtPriceX64,\n priceLower.tickSqrtPriceX64,\n priceUpper.tickSqrtPriceX64,\n position.liquidity,\n false,\n );\n\n const leverage = 1 / (1 - Math.sqrt(Math.sqrt(priceLower.price.div(priceUpper.price).toNumber())));\n\n poolInfoA.positionAccount = [\n ...(poolInfoA.positionAccount ?? []),\n {\n poolId: position.poolId,\n nftMint: position.nftMint,\n\n priceLower: priceLower.price,\n priceUpper: priceUpper.price,\n amountA,\n amountB,\n tickLower: position.tickLower,\n tickUpper: position.tickUpper,\n liquidity: position.liquidity,\n feeGrowthInsideLastX64A: position.feeGrowthInsideLastX64A,\n feeGrowthInsideLastX64B: position.feeGrowthInsideLastX64B,\n tokenFeesOwedA: position.tokenFeesOwedA,\n tokenFeesOwedB: position.tokenFeesOwedB,\n rewardInfos: position.rewardInfos.map((i) => ({\n ...i,\n pendingReward: new BN(0),\n })),\n\n leverage,\n tokenFeeAmountA: new BN(0),\n tokenFeeAmountB: new BN(0),\n },\n ];\n\n const tickArrayLowerAddress = await TickUtils.getTickArrayAddressByTick(\n poolInfoA.state.programId,\n position.poolId,\n position.tickLower,\n poolInfoA.state.tickSpacing,\n );\n const tickArrayUpperAddress = await TickUtils.getTickArrayAddressByTick(\n poolInfoA.state.programId,\n position.poolId,\n position.tickUpper,\n poolInfoA.state.tickSpacing,\n );\n keyToTickArrayAddress[\n `${poolInfoA.state.programId.toString()}-${position.poolId.toString()}-${position.tickLower}`\n ] = tickArrayLowerAddress;\n keyToTickArrayAddress[\n `${poolInfoA.state.programId.toString()}-${position.poolId.toString()}-${position.tickUpper}`\n ] = tickArrayUpperAddress;\n }\n\n if (updateOwnerRewardAndFee) {\n const tickArrayKeys = Object.values(keyToTickArrayAddress);\n const tickArrayDatas = await getMultipleAccountsInfo(connection, tickArrayKeys, { batchRequest });\n const tickArrayLayout = {};\n for (let index = 0; index < tickArrayKeys.length; index++) {\n const tickArrayData = tickArrayDatas[index];\n if (tickArrayData === null) continue;\n const key = tickArrayKeys[index].toString();\n tickArrayLayout[key] = TickArrayLayout.decode(tickArrayData.data);\n }\n\n for (const { state, positionAccount } of pools) {\n if (!positionAccount) continue;\n for (const itemPA of positionAccount) {\n const keyLower = `${state.programId.toString()}-${state.id.toString()}-${itemPA.tickLower}`;\n const keyUpper = `${state.programId.toString()}-${state.id.toString()}-${itemPA.tickUpper}`;\n const tickArrayLower = tickArrayLayout[keyToTickArrayAddress[keyLower].toString()];\n const tickArrayUpper = tickArrayLayout[keyToTickArrayAddress[keyUpper].toString()];\n const tickLowerState: Tick =\n tickArrayLower.ticks[TickUtils.getTickOffsetInArray(itemPA.tickLower, state.tickSpacing)];\n const tickUpperState: Tick =\n tickArrayUpper.ticks[TickUtils.getTickOffsetInArray(itemPA.tickUpper, state.tickSpacing)];\n const { tokenFeeAmountA, tokenFeeAmountB } = await PositionUtils.GetPositionFees(\n state,\n itemPA,\n tickLowerState,\n tickUpperState,\n );\n const rewardInfos = await PositionUtils.GetPositionRewards(state, itemPA, tickLowerState, tickUpperState);\n itemPA.tokenFeeAmountA = tokenFeeAmountA.gte(new BN(0)) ? tokenFeeAmountA : new BN(0);\n itemPA.tokenFeeAmountB = tokenFeeAmountB.gte(new BN(0)) ? tokenFeeAmountB : new BN(0);\n for (let i = 0; i < rewardInfos.length; i++) {\n itemPA.rewardInfos[i].pendingReward = rewardInfos[i].gte(new BN(0)) ? rewardInfos[i] : new BN(0);\n }\n }\n }\n }\n }\n return pools;\n }\n\n static computeAmountOut({\n poolInfo,\n tickArrayCache,\n baseMint,\n epochInfo,\n amountIn,\n slippage,\n priceLimit = new Decimal(0),\n catchLiquidityInsufficient = false,\n }: {\n poolInfo: ComputeClmmPoolInfo;\n tickArrayCache: { [key: string]: TickArray };\n baseMint: PublicKey;\n\n epochInfo: EpochInfo;\n\n amountIn: BN;\n slippage: number;\n priceLimit?: Decimal;\n catchLiquidityInsufficient: boolean;\n }): ReturnTypeComputeAmountOut {\n let sqrtPriceLimitX64: BN;\n const isBaseIn = baseMint.toBase58() === poolInfo.mintA.address;\n const [baseFeeConfig, outFeeConfig] = isBaseIn\n ? [poolInfo.mintA.extensions.feeConfig, poolInfo.mintB.extensions.feeConfig]\n : [poolInfo.mintB.extensions.feeConfig, poolInfo.mintA.extensions.feeConfig];\n\n if (priceLimit.equals(new Decimal(0))) {\n sqrtPriceLimitX64 = isBaseIn ? MIN_SQRT_PRICE_X64.add(new BN(1)) : MAX_SQRT_PRICE_X64.sub(new BN(1));\n } else {\n sqrtPriceLimitX64 = SqrtPriceMath.priceToSqrtPriceX64(\n priceLimit,\n poolInfo.mintA.decimals,\n poolInfo.mintB.decimals,\n );\n }\n\n const realAmountIn = getTransferAmountFeeV2(amountIn, baseFeeConfig, epochInfo, false);\n\n const {\n allTrade,\n expectedAmountOut: _expectedAmountOut,\n remainingAccounts,\n executionPrice: _executionPriceX64,\n feeAmount,\n } = PoolUtils.getOutputAmountAndRemainAccounts(\n poolInfo,\n tickArrayCache,\n baseMint,\n realAmountIn.amount.sub(realAmountIn.fee ?? ZERO),\n sqrtPriceLimitX64,\n catchLiquidityInsufficient,\n );\n\n const amountOut = getTransferAmountFeeV2(_expectedAmountOut, outFeeConfig, epochInfo, false);\n\n const _executionPrice = SqrtPriceMath.sqrtPriceX64ToPrice(\n _executionPriceX64,\n poolInfo.mintA.decimals,\n poolInfo.mintB.decimals,\n );\n const executionPrice = isBaseIn ? _executionPrice : new Decimal(1).div(_executionPrice);\n\n const _minAmountOut = _expectedAmountOut\n .mul(new BN(Math.floor((1 - slippage) * 10000000000)))\n .div(new BN(10000000000));\n const minAmountOut = getTransferAmountFeeV2(_minAmountOut, outFeeConfig, epochInfo, false);\n\n const poolPrice = isBaseIn ? poolInfo.currentPrice : new Decimal(1).div(poolInfo.currentPrice);\n\n const _numerator = new Decimal(executionPrice).sub(poolPrice).abs();\n const _denominator = poolPrice;\n const priceImpact = new Percent(\n new Decimal(_numerator).mul(10 ** 15).toFixed(0),\n new Decimal(_denominator).mul(10 ** 15).toFixed(0),\n );\n\n return {\n allTrade,\n realAmountIn,\n amountOut,\n minAmountOut,\n expirationTime: minExpirationTime(realAmountIn.expirationTime, amountOut.expirationTime),\n currentPrice: poolInfo.currentPrice,\n executionPrice,\n priceImpact,\n fee: feeAmount,\n remainingAccounts,\n executionPriceX64: _executionPriceX64,\n };\n }\n\n static computeAmountOutFormat({\n poolInfo,\n tickArrayCache,\n amountIn,\n tokenOut: _tokenOut,\n slippage,\n epochInfo,\n catchLiquidityInsufficient = false,\n }: {\n poolInfo: ComputeClmmPoolInfo;\n tickArrayCache: { [key: string]: TickArray };\n amountIn: BN;\n tokenOut: ApiV3Token;\n slippage: number;\n epochInfo: EpochInfo;\n catchLiquidityInsufficient?: boolean;\n }): ReturnTypeComputeAmountOutFormat {\n const baseIn = _tokenOut.address === poolInfo.mintB.address;\n const [inputMint, outMint] = baseIn ? [poolInfo.mintA, poolInfo.mintB] : [poolInfo.mintB, poolInfo.mintA];\n const [baseToken, outToken] = [\n new Token({\n ...inputMint,\n mint: inputMint.address,\n isToken2022: inputMint.programId === TOKEN_2022_PROGRAM_ID.toBase58(),\n }),\n new Token({\n ...outMint,\n mint: outMint.address,\n isToken2022: outMint.programId === TOKEN_2022_PROGRAM_ID.toBase58(),\n }),\n ];\n\n const {\n allTrade,\n realAmountIn: _realAmountIn,\n amountOut: _amountOut,\n minAmountOut: _minAmountOut,\n expirationTime,\n currentPrice,\n executionPrice,\n priceImpact,\n fee,\n remainingAccounts,\n executionPriceX64,\n } = PoolUtils.computeAmountOut({\n poolInfo,\n tickArrayCache,\n baseMint: new PublicKey(inputMint.address),\n amountIn,\n slippage,\n epochInfo,\n catchLiquidityInsufficient,\n });\n\n const realAmountIn = {\n ..._realAmountIn,\n amount: new TokenAmount(baseToken, _realAmountIn.amount),\n fee: _realAmountIn.fee === undefined ? undefined : new TokenAmount(baseToken, _realAmountIn.fee),\n };\n\n const amountOut = {\n ..._amountOut,\n amount: new TokenAmount(outToken, _amountOut.amount),\n fee: _amountOut.fee === undefined ? undefined : new TokenAmount(outToken, _amountOut.fee),\n };\n const minAmountOut = {\n ..._minAmountOut,\n amount: new TokenAmount(outToken, _minAmountOut.amount),\n fee: _minAmountOut.fee === undefined ? undefined : new TokenAmount(outToken, _minAmountOut.fee),\n };\n\n const _currentPrice = new Price({\n baseToken,\n denominator: new BN(10).pow(new BN(20 + baseToken.decimals)),\n quoteToken: outToken,\n numerator: currentPrice.mul(new Decimal(10 ** (20 + outToken.decimals))).toFixed(0),\n });\n const _executionPrice = new Price({\n baseToken,\n denominator: new BN(10).pow(new BN(20 + baseToken.decimals)),\n quoteToken: outToken,\n numerator: executionPrice.mul(new Decimal(10 ** (20 + outToken.decimals))).toFixed(0),\n });\n const _fee = new TokenAmount(baseToken, fee);\n\n return {\n allTrade,\n realAmountIn,\n amountOut,\n minAmountOut,\n expirationTime,\n currentPrice: _currentPrice,\n executionPrice: _executionPrice,\n priceImpact,\n fee: _fee,\n remainingAccounts,\n executionPriceX64,\n };\n }\n\n static computeAmountIn({\n poolInfo,\n tickArrayCache,\n baseMint,\n epochInfo,\n amountOut,\n slippage,\n priceLimit = new Decimal(0),\n }: {\n poolInfo: ComputeClmmPoolInfo;\n tickArrayCache: { [key: string]: TickArray };\n baseMint: PublicKey;\n\n epochInfo: EpochInfo;\n\n amountOut: BN;\n slippage: number;\n priceLimit?: Decimal;\n }): ReturnTypeComputeAmountOutBaseOut {\n const isBaseIn = baseMint.toBase58() === poolInfo.mintA.address;\n const feeConfigs = {\n [poolInfo.mintA.address]: poolInfo.mintA.extensions.feeConfig,\n [poolInfo.mintB.address]: poolInfo.mintB.extensions.feeConfig,\n };\n\n let sqrtPriceLimitX64: BN;\n if (priceLimit.equals(new Decimal(0))) {\n sqrtPriceLimitX64 = !isBaseIn ? MIN_SQRT_PRICE_X64.add(new BN(1)) : MAX_SQRT_PRICE_X64.sub(new BN(1));\n } else {\n sqrtPriceLimitX64 = SqrtPriceMath.priceToSqrtPriceX64(\n priceLimit,\n poolInfo.mintA.decimals,\n poolInfo.mintB.decimals,\n );\n }\n\n const realAmountOut = getTransferAmountFeeV2(amountOut, feeConfigs[baseMint.toString()], epochInfo, true);\n\n const {\n expectedAmountIn: _expectedAmountIn,\n remainingAccounts,\n executionPrice: _executionPriceX64,\n feeAmount,\n } = PoolUtils.getInputAmountAndRemainAccounts(\n poolInfo,\n tickArrayCache,\n baseMint,\n realAmountOut.amount.sub(realAmountOut.fee ?? ZERO),\n sqrtPriceLimitX64,\n );\n\n const inMint = isBaseIn ? poolInfo.mintB.address : poolInfo.mintA.address;\n\n const amountIn = getTransferAmountFeeV2(_expectedAmountIn, feeConfigs[inMint], epochInfo, false);\n // const amountIn = getTransferAmountFee(\n // _expectedAmountIn,\n // token2022Infos[inMint.toString()]?.feeConfig,\n // epochInfo,\n // true,\n // );\n\n const _executionPrice = SqrtPriceMath.sqrtPriceX64ToPrice(\n _executionPriceX64,\n poolInfo.mintA.decimals,\n poolInfo.mintB.decimals,\n );\n const executionPrice = isBaseIn ? _executionPrice : new Decimal(1).div(_executionPrice);\n\n const _maxAmountIn = _expectedAmountIn\n .mul(new BN(Math.floor((1 + slippage) * 10000000000)))\n .div(new BN(10000000000));\n // const maxAmountIn = getTransferAmountFee(\n // _maxAmountIn,\n // token2022Infos[inMint.toString()]?.feeConfig,\n // epochInfo,\n // true,\n // );\n const maxAmountIn = getTransferAmountFeeV2(_maxAmountIn, feeConfigs[inMint], epochInfo, true);\n\n const poolPrice = isBaseIn ? poolInfo.currentPrice : new Decimal(1).div(poolInfo.currentPrice);\n\n const _numerator = new Decimal(executionPrice).sub(poolPrice).abs();\n const _denominator = poolPrice;\n const priceImpact = new Percent(\n new Decimal(_numerator).mul(10 ** 15).toFixed(0),\n new Decimal(_denominator).mul(10 ** 15).toFixed(0),\n );\n\n return {\n amountIn,\n maxAmountIn,\n realAmountOut,\n expirationTime: minExpirationTime(amountIn.expirationTime, realAmountOut.expirationTime),\n currentPrice: poolInfo.currentPrice,\n executionPrice,\n priceImpact,\n fee: feeAmount,\n\n remainingAccounts,\n };\n }\n\n static estimateAprsForPriceRangeMultiplier({\n poolInfo,\n aprType,\n positionTickLowerIndex,\n positionTickUpperIndex,\n }: {\n poolInfo: ApiV3PoolInfoConcentratedItem;\n aprType: \"day\" | \"week\" | \"month\";\n\n positionTickLowerIndex: number;\n positionTickUpperIndex: number;\n }): {\n feeApr: number;\n rewardsApr: number[];\n apr: number;\n } {\n const aprInfo = poolInfo[aprType];\n\n const priceLower = TickUtils.getTickPrice({\n poolInfo,\n tick: positionTickLowerIndex,\n baseIn: true,\n }).price.toNumber();\n const priceUpper = TickUtils.getTickPrice({\n poolInfo,\n tick: positionTickUpperIndex,\n baseIn: true,\n }).price.toNumber();\n\n const _minPrice = Math.max(priceLower, aprInfo.priceMin);\n const _maxPrice = Math.min(priceUpper, aprInfo.priceMax);\n\n const sub = _maxPrice - _minPrice;\n\n const userRange = priceUpper - priceLower;\n const tradeRange = aprInfo.priceMax - aprInfo.priceMin;\n\n let p: number;\n\n if (sub <= 0) p = 0;\n else if (userRange === sub) p = tradeRange / sub;\n else if (tradeRange === sub) p = sub / userRange;\n else p = (sub / tradeRange) * (sub / userRange);\n\n return {\n feeApr: aprInfo.feeApr * p,\n rewardsApr: [(aprInfo.rewardApr[0] ?? 0) * p, (aprInfo.rewardApr[1] ?? 0) * p, (aprInfo.rewardApr[2] ?? 0) * p],\n apr: aprInfo.apr * p,\n };\n }\n\n static estimateAprsForPriceRangeDelta({\n poolInfo,\n poolLiquidity,\n aprType,\n mintPrice,\n liquidity,\n positionTickLowerIndex,\n positionTickUpperIndex,\n chainTime,\n }: {\n poolInfo: ApiV3PoolInfoConcentratedItem;\n poolLiquidity: BN;\n aprType: \"day\" | \"week\" | \"month\";\n\n mintPrice: { [mint: string]: { value: number } };\n\n liquidity: BN;\n positionTickLowerIndex: number;\n positionTickUpperIndex: number;\n\n chainTime: number;\n }): {\n feeApr: number;\n rewardsApr: number[];\n apr: number;\n } {\n const aprTypeDay = aprType === \"day\" ? 1 : aprType === \"week\" ? 7 : aprType === \"month\" ? 30 : 0;\n const aprInfo = poolInfo[aprType];\n const mintPriceA = mintPrice[solToWSol(poolInfo.mintA.address).toString()];\n const mintPriceB = mintPrice[solToWSol(poolInfo.mintB.address).toString()];\n const mintDecimalsA = poolInfo.mintA.decimals;\n const mintDecimalsB = poolInfo.mintB.decimals;\n\n if (!aprInfo || !mintPriceA || !mintPriceB) return { feeApr: 0, rewardsApr: [0, 0, 0], apr: 0 };\n\n const sqrtPriceX64 = SqrtPriceMath.priceToSqrtPriceX64(\n new Decimal(poolInfo.price),\n poolInfo.mintA.decimals,\n poolInfo.mintB.decimals,\n );\n\n const sqrtPriceX64A = SqrtPriceMath.getSqrtPriceX64FromTick(positionTickLowerIndex);\n const sqrtPriceX64B = SqrtPriceMath.getSqrtPriceX64FromTick(positionTickUpperIndex);\n\n const { amountSlippageA: poolLiquidityA, amountSlippageB: poolLiquidityB } =\n LiquidityMath.getAmountsFromLiquidityWithSlippage(\n sqrtPriceX64,\n sqrtPriceX64A,\n sqrtPriceX64B,\n poolLiquidity,\n false,\n false,\n 0,\n );\n\n const { amountSlippageA: userLiquidityA, amountSlippageB: userLiquidityB } =\n LiquidityMath.getAmountsFromLiquidityWithSlippage(\n sqrtPriceX64,\n sqrtPriceX64A,\n sqrtPriceX64B,\n liquidity,\n false,\n false,\n 0,\n );\n\n const poolTvl = new Decimal(poolLiquidityA.toString())\n .div(new Decimal(10).pow(mintDecimalsA))\n .mul(mintPriceA.value)\n .add(new Decimal(poolLiquidityB.toString()).div(new Decimal(10).pow(mintDecimalsB)).mul(mintPriceB.value));\n const userTvl = new Decimal(userLiquidityA.toString())\n .div(new Decimal(10).pow(mintDecimalsA))\n .mul(mintPriceA.value)\n .add(new Decimal(userLiquidityB.toString()).div(new Decimal(10).pow(mintDecimalsB)).mul(mintPriceB.value));\n\n const p = new Decimal(1).div(poolTvl.add(userTvl));\n\n const feesPerYear = new Decimal(aprInfo.volumeFee).mul(365).div(aprTypeDay);\n const feeApr = feesPerYear.mul(p).mul(100).toNumber();\n\n const SECONDS_PER_YEAR = 3600 * 24 * 365;\n\n const rewardsApr = poolInfo.rewardDefaultInfos.map((i) => {\n const iDecimal = i.mint.decimals;\n const iPrice = mintPrice[i.mint.address];\n\n if (\n chainTime < ((i as any).startTime ?? 0) ||\n chainTime > ((i as any).endTime ?? 0) ||\n !i.perSecond ||\n !iPrice ||\n iDecimal === undefined\n )\n return 0;\n\n return new Decimal(iPrice.value)\n .mul(new Decimal(i.perSecond).mul(SECONDS_PER_YEAR))\n .div(new Decimal(10).pow(iDecimal))\n .mul(p)\n .mul(100)\n .toNumber();\n });\n\n return {\n feeApr,\n rewardsApr,\n apr: feeApr + rewardsApr.reduce((a, b) => a + b, 0),\n };\n }\n\n static getLiquidityAmountOutFromAmountIn({\n poolInfo,\n inputA,\n tickLower,\n tickUpper,\n amount,\n slippage,\n add,\n epochInfo,\n amountHasFee,\n }: {\n poolInfo: ApiV3PoolInfoConcentratedItem;\n inputA: boolean;\n tickLower: number;\n tickUpper: number;\n amount: BN;\n slippage: number;\n add: boolean;\n epochInfo: EpochInfo;\n amountHasFee: boolean;\n }): Promise<ReturnTypeGetLiquidityAmountOut> {\n const sqrtPriceX64 = SqrtPriceMath.priceToSqrtPriceX64(\n new Decimal(poolInfo.price),\n poolInfo.mintA.decimals,\n poolInfo.mintB.decimals,\n );\n const sqrtPriceX64A = SqrtPriceMath.getSqrtPriceX64FromTick(tickLower);\n const sqrtPriceX64B = SqrtPriceMath.getSqrtPriceX64FromTick(tickUpper);\n\n const coefficient = add ? 1 - slippage : 1 + slippage;\n const addFeeAmount = getTransferAmountFeeV2(\n amount,\n poolInfo[inputA ? \"mintA\" : \"mintB\"].extensions?.feeConfig,\n epochInfo,\n !amountHasFee,\n );\n const _amount = new BN(\n new Decimal(addFeeAmount.amount.sub(addFeeAmount.fee ?? ZERO).toString()).mul(coefficient).toFixed(0),\n );\n\n let liquidity: BN;\n if (sqrtPriceX64.lte(sqrtPriceX64A)) {\n liquidity = inputA\n ? LiquidityMath.getLiquidityFromTokenAmountA(sqrtPriceX64A, sqrtPriceX64B, _amount, !add)\n : new BN(0);\n } else if (sqrtPriceX64.lte(sqrtPriceX64B)) {\n const liquidity0 = LiquidityMath.getLiquidityFromTokenAmountA(sqrtPriceX64, sqrtPriceX64B, _amount, !add);\n const liquidity1 = LiquidityMath.getLiquidityFromTokenAmountB(sqrtPriceX64A, sqrtPriceX64, _amount);\n liquidity = inputA ? liquidity0 : liquidity1;\n } else {\n liquidity = inputA\n ? new BN(0)\n : LiquidityMath.getLiquidityFromTokenAmountB(sqrtPriceX64A, sqrtPriceX64B, _amount);\n }\n\n return PoolUtils.getAmountsFromLiquidity({\n epochInfo,\n poolInfo,\n tickLower,\n tickUpper,\n liquidity,\n slippage,\n add,\n });\n }\n\n static async getAmountsFromLiquidity({\n epochInfo,\n poolInfo,\n tickLower,\n tickUpper,\n liquidity,\n slippage,\n add,\n }: {\n epochInfo: EpochInfo;\n poolInfo: ApiV3PoolInfoConcentratedItem;\n tickLower: number;\n tickUpper: number;\n liquidity: BN;\n slippage: number;\n add: boolean;\n }): Promise<ReturnTypeGetLiquidityAmountOut> {\n const sqrtPriceX64A = SqrtPriceMath.getSqrtPriceX64FromTick(tickLower);\n const sqrtPriceX64B = SqrtPriceMath.getSqrtPriceX64FromTick(tickUpper);\n\n const coefficientRe = add ? 1 + slippage : 1 - slippage;\n\n const amounts = LiquidityMath.getAmountsFromLiquidity(\n SqrtPriceMath.priceToSqrtPriceX64(new Decimal(poolInfo.price), poolInfo.mintA.decimals, poolInfo.mintB.decimals),\n sqrtPriceX64A,\n sqrtPriceX64B,\n liquidity,\n add,\n );\n const [amountA, amountB] = [\n getTransferAmountFeeV2(amounts.amountA, poolInfo.mintA.extensions?.feeConfig, epochInfo, true),\n getTransferAmountFeeV2(amounts.amountB, poolInfo.mintB.extensions?.feeConfig, epochInfo, true),\n ];\n const [amountSlippageA, amountSlippageB] = [\n getTransferAmountFeeV2(\n amounts.amountA.muln(coefficientRe),\n poolInfo.mintA.extensions?.feeConfig,\n epochInfo,\n true,\n ),\n getTransferAmountFeeV2(\n amounts.amountB.muln(coefficientRe),\n poolInfo.mintB.extensions?.feeConfig,\n epochInfo,\n true,\n ),\n ];\n\n return {\n liquidity,\n amountA,\n amountB,\n amountSlippageA,\n amountSlippageB,\n expirationTime: minExpirationTime(amountA.expirationTime, amountB.expirationTime),\n };\n }\n\n static async fetchComputeMultipleClmmInfo({\n connection,\n poolList,\n rpcDataMap = {},\n }: {\n rpcDataMap?: Record<string, ReturnType<typeof PoolInfoLayout.decode>>;\n connection: Connection;\n poolList: Pick<ApiV3PoolInfoConcentratedItem, \"id\" | \"programId\" | \"mintA\" | \"mintB\" | \"config\" | \"price\">[];\n }): Promise<Record<string, ComputeClmmPoolInfo>> {\n const fetchRpcList = poolList.filter((p) => !rpcDataMap[p.id]).map((p) => new PublicKey(p.id));\n const rpcRes = await getMultipleAccountsInfo(connection, fetchRpcList);\n rpcRes.forEach((r, idx) => {\n if (!r) return;\n rpcDataMap[fetchRpcList[idx].toBase58()] = PoolInfoLayout.decode(r.data);\n });\n\n const pdaList = poolList.map(\n (poolInfo) => getPdaExBitmapAccount(new PublicKey(poolInfo.programId), new PublicKey(poolInfo.id)).publicKey,\n );\n\n const exBitData = await PoolUtils.fetchExBitmaps({\n connection,\n exBitmapAddress: pdaList,\n batchRequest: false,\n });\n\n return poolList.reduce(\n (acc, cur) => ({\n ...acc,\n [cur.id]: {\n ...rpcDataMap[cur.id],\n id: new PublicKey(cur.id),\n version: 6,\n programId: new PublicKey(cur.programId),\n mintA: cur.mintA,\n mintB: cur.mintB,\n ammConfig: {\n ...cur.config,\n id: new PublicKey(cur.config.id),\n fundOwner: \"\",\n },\n currentPrice: new Decimal(cur.price),\n exBitmapInfo:\n exBitData[getPdaExBitmapAccount(new PublicKey(cur.programId), new PublicKey(cur.id)).publicKey.toBase58()],\n startTime: rpcDataMap[cur.id].startTime.toNumber(),\n rewardInfos: rpcDataMap[cur.id].rewardInfos,\n },\n }),\n {} as Record<string, ComputeClmmPoolInfo>,\n );\n }\n\n static async fetchComputeClmmInfo({\n connection,\n poolInfo,\n rpcData,\n }: {\n connection: Connection;\n poolInfo: Pick<ApiV3PoolInfoConcentratedItem, \"id\" | \"programId\" | \"mintA\" | \"mintB\" | \"config\" | \"price\">;\n rpcData?: ReturnType<typeof PoolInfoLayout.decode>;\n }): Promise<ComputeClmmPoolInfo> {\n return (\n await this.fetchComputeMultipleClmmInfo({\n connection,\n rpcDataMap: rpcData ? { [poolInfo.id]: rpcData } : undefined,\n poolList: [poolInfo],\n })\n )[poolInfo.id];\n }\n}\n\nexport function getLiquidityFromAmounts({\n poolInfo,\n tickLower,\n tickUpper,\n amountA,\n amountB,\n slippage,\n add,\n epochInfo,\n amountHasFee,\n}: {\n poolInfo: ApiV3PoolInfoConcentratedItem;\n tickLower: number;\n tickUpper: number;\n amountA: BN;\n amountB: BN;\n slippage: number;\n add: boolean;\n epochInfo: EpochInfo;\n amountHasFee: boolean;\n}): ReturnTypeGetLiquidityAmountOut {\n const [_tickLower, _tickUpper, _amountA, _amountB] =\n tickLower < tickUpper ? [tickLower, tickUpper, amountA, amountB] : [tickUpper, tickLower, amountB, amountA];\n const sqrtPriceX64 = SqrtPriceMath.priceToSqrtPriceX64(\n new Decimal(poolInfo.price),\n poolInfo.mintA.decimals,\n poolInfo.mintB.decimals,\n );\n const sqrtPriceX64A = SqrtPriceMath.getSqrtPriceX64FromTick(_tickLower);\n const sqrtPriceX64B = SqrtPriceMath.getSqrtPriceX64FromTick(_tickUpper);\n\n const [amountFeeA, amountFeeB] = [\n getTransferAmountFeeV2(_amountA, poolInfo.mintA.extensions?.feeConfig, epochInfo, !amountHasFee),\n getTransferAmountFeeV2(_amountB, poolInfo.mintB.extensions?.feeConfig, epochInfo, !amountHasFee),\n ];\n\n const liquidity = LiquidityMath.getLiquidityFromTokenAmounts(\n sqrtPriceX64,\n sqrtPriceX64A,\n sqrtPriceX64B,\n amountFeeA.amount.sub(amountFeeA.fee ?? ZERO),\n amountFeeB.amount.sub(amountFeeB.fee ?? ZERO),\n );\n\n return LiquidityMath.getAmountsOutFromLiquidity({\n poolInfo,\n tickLower,\n tickUpper,\n liquidity,\n slippage,\n add,\n epochInfo,\n amountAddFee: !amountHasFee,\n });\n}\n\nconst 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\nexport function clmmComputeInfoToApiInfo(pool: ComputeClmmPoolInfo): ApiV3PoolInfoConcentratedItem {\n return {\n ...pool,\n type: \"Concentrated\",\n programId: pool.programId.toString(),\n id: pool.id.toString(),\n rewardDefaultInfos: [],\n rewardDefaultPoolInfos: \"Clmm\",\n price: pool.currentPrice.toNumber(),\n mintAmountA: 0,\n mintAmountB: 0,\n feeRate: pool.ammConfig.tradeFeeRate,\n openTime: pool.startTime.toString(),\n tvl: 0,\n\n day: mockRewardData,\n week: mockRewardData,\n month: mockRewardData,\n pooltype: [],\n\n farmUpcomingCount: 0,\n farmOngoingCount: 0,\n farmFinishedCount: 0,\n burnPercent: 0,\n config: {\n ...pool.ammConfig,\n id: pool.ammConfig.id.toString(),\n defaultRange: 0,\n defaultRangePoint: [],\n },\n };\n}\n","/*!\r\n * decimal.js v10.4.3\r\n * An arbitrary-precision Decimal type for JavaScript.\r\n * https://github.com/MikeMcl/decimal.js\r\n * Copyright (c) 2022 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` and `toSignificantDigits`.\r\n MAX_DIGITS = 1e9, // 0 to 1e9\r\n\r\n // Base conversion alphabet.\r\n NUMERALS = '0123456789abcdef',\r\n\r\n // The natural logarithm of 10 (1025 digits).\r\n LN10 = '2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983419677840422862486334095254650828067566662873690987816894829072083255546808437998948262331985283935053089653777326288461633662222876982198867465436674744042432743651550489343149393914796194044002221051017141748003688084012647080685567743216228355220114804663715659121373450747856947683463616792101806445070648000277502684916746550586856935673420670581136429224554405758925724208241314695689016758940256776311356919292033376587141660230105703089634572075440370847469940168269282808481184289314848524948644871927809676271275775397027668605952496716674183485704422507197965004714951050492214776567636938662976979522110718264549734772662425709429322582798502585509785265383207606726317164309505995087807523710333101197857547331541421808427543863591778117054309827482385045648019095610299291824318237525357709750539565187697510374970888692180205189339507238539205144634197265287286965110862571492198849978748873771345686209167058',\r\n\r\n // Pi (1025 digits).\r\n PI = '3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724