@raydium-io/raydium-sdk-v2
Version:
An SDK for building applications on top of Raydium.
1 lines • 1.29 MB
Source Map (JSON)
{"version":3,"sources":["../../../../src/raydium/clmm/libraries/swapSimulator.ts","../../../../src/raydium/clmm/libraries/constants.ts","../../../../src/raydium/clmm/libraries/liquidityMath.ts","../../../../src/raydium/clmm/libraries/bigNum.ts","../../../../src/raydium/clmm/libraries/sqrtPriceMath.ts","../../../../src/raydium/clmm/libraries/pool.ts","../../../../src/marshmallow/index.ts","../../../../src/marshmallow/buffer-layout.ts","../../../../src/raydium/clmm/layout.ts","../../../../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/raydium/raydium.ts","../../../../src/api/api.ts","../../../../src/api/url.ts","../../../../src/raydium/account/account.ts","../../../../src/common/txTool/txTool.ts","../../../../src/common/txTool/lookupTable.ts","../../../../src/common/txTool/txType.ts","../../../../src/common/txTool/txUtils.ts","../../../../src/raydium/moduleBase.ts","../../../../src/raydium/account/instruction.ts","../../../../src/raydium/account/util.ts","../../../../src/raydium/account/layout.ts","../../../../src/raydium/farm/farm.ts","../../../../src/common/pda.ts","../../../../src/common/programId.ts","../../../../src/raydium/clmm/clmm.ts","../../../../src/raydium/token/utils.ts","../../../../src/raydium/token/layout.ts","../../../../src/raydium/clmm/instrument.ts","../../../../src/raydium/clmm/libraries/utils.ts","../../../../src/raydium/clmm/libraries/pda.ts","../../../../src/raydium/clmm/libraries/limitOrder.ts","../../../../src/raydium/clmm/libraries/position.ts","../../../../src/raydium/clmm/libraries/swapMath.ts","../../../../src/raydium/farm/config.ts","../../../../src/raydium/farm/layout.ts","../../../../src/raydium/farm/instruction.ts","../../../../src/raydium/farm/util.ts","../../../../src/common/utility.ts","../../../../src/raydium/liquidity/liquidity.ts","../../../../src/common/transfer.ts","../../../../src/raydium/liquidity/constant.ts","../../../../src/raydium/liquidity/instruction.ts","../../../../src/raydium/liquidity/layout.ts","../../../../src/raydium/liquidity/stable.ts","../../../../src/raydium/liquidity/utils.ts","../../../../src/raydium/liquidity/serum.ts","../../../../src/raydium/marketV2/createMarket.ts","../../../../src/raydium/marketV2/instrument.ts","../../../../src/raydium/marketV2/layout.ts","../../../../src/raydium/cpmm/cpmm.ts","../../../../src/raydium/cpmm/curve/calculator.ts","../../../../src/raydium/cpmm/curve/constantProduct.ts","../../../../src/raydium/cpmm/curve/fee.ts","../../../../src/common/fee.ts","../../../../src/raydium/cpmm/instruction.ts","../../../../src/raydium/cpmm/pda.ts","../../../../src/raydium/cpmm/layout.ts","../../../../src/raydium/tradeV2/trade.ts","../../../../src/raydium/launchpad/instrument.ts","../../../../src/raydium/launchpad/layout.ts","../../../../src/raydium/launchpad/pda.ts","../../../../src/raydium/launchpad/curve/constantProductCurve.ts","../../../../src/raydium/launchpad/curve/curve.ts","../../../../src/raydium/launchpad/curve/fixedPriceCurve.ts","../../../../src/raydium/launchpad/curve/linearPriceCurve.ts","../../../../src/raydium/launchpad/curve/func.ts","../../../../src/raydium/launchpad/launchpad.ts","../../../../src/raydium/serum/id.ts","../../../../src/raydium/serum/layout.ts","../../../../src/raydium/serum/serum.ts","../../../../src/raydium/tradeV2/instrument.ts","../../../../src/raydium/utils1216/utils1216.ts","../../../../src/raydium/ido/ido.ts","../../../../src/raydium/ido/instruction.ts","../../../../src/raydium/ido/layout.ts","../../../../src/raydium/token/token.ts","../../../../src/common/lodash.ts","../../../../src/raydium/clmm/libraries/tickArrayUtil.ts"],"sourcesContent":["import { PublicKey } from \"@solana/web3.js\";\nimport BN from \"bn.js\";\nimport { ClmmConfigLayout, PoolInfoLayout, TickArrayBitmapExtensionLayout, TickArrayLayout } from \"../layout\";\nimport { BN_ZERO, MAX_SQRT_PRICE_X64, MIN_SQRT_PRICE_X64 } from \"./constants\";\nimport { LiquidityMathUtil } from \"./liquidityMath\";\nimport { PoolUtil } from \"./pool\";\nimport { SwapMathUtil, SwapState } from \"./swapMath\";\nimport { TickArrayBitmapUtil, TickArrayUtil, TickUtil } from \"./tickArrayUtil\";\n\nexport interface SwapSimulationResult {\n allTrade: boolean;\n amountSpecifiedRemaining: BN;\n amountCalculated: BN;\n feeAmount: BN;\n sqrtPriceX64: BN;\n liquidity: BN;\n tickCurrent: number;\n accounts: PublicKey[];\n}\n\nexport function swapInternal({\n programId,\n poolId,\n poolInfo,\n tickArrays,\n configInfo,\n tickarrayBitmapExtension,\n amountSpecified,\n sqrtPriceLimitX64,\n zeroForOne,\n isBaseInput,\n blockTimestamp,\n includeExtraTickArrays,\n}: {\n programId: PublicKey;\n poolId: PublicKey;\n poolInfo: ReturnType<typeof PoolInfoLayout.decode>;\n tickArrays: { address: PublicKey; value: ReturnType<typeof TickArrayLayout.decode> }[];\n configInfo: ReturnType<typeof ClmmConfigLayout.decode>;\n tickarrayBitmapExtension: ReturnType<typeof TickArrayBitmapExtensionLayout.decode>;\n amountSpecified: BN;\n sqrtPriceLimitX64: BN;\n zeroForOne: boolean;\n isBaseInput: boolean;\n blockTimestamp: number;\n includeExtraTickArrays: boolean;\n}): SwapSimulationResult {\n if (sqrtPriceLimitX64.isZero()) {\n sqrtPriceLimitX64 = zeroForOne ? new BN(MIN_SQRT_PRICE_X64).addn(1) : new BN(MAX_SQRT_PRICE_X64).subn(1);\n }\n\n let tickArrayListIndex = 0;\n\n if (tickArrays.length === 0) {\n return {\n allTrade: false,\n amountSpecifiedRemaining: amountSpecified,\n amountCalculated: BN_ZERO,\n feeAmount: BN_ZERO,\n sqrtPriceX64: poolInfo.sqrtPriceX64,\n liquidity: poolInfo.liquidity,\n tickCurrent: poolInfo.tickCurrent,\n accounts: [],\n };\n }\n\n const addTickArrayAddress = includeExtraTickArrays\n ? TickArrayBitmapUtil.findTickArrayAddress({\n programId,\n poolId,\n tickSpacing: poolInfo.tickSpacing,\n poolBitmap: poolInfo.tickArrayBitmap,\n tickArrayBitmap: tickarrayBitmapExtension,\n findInfo: { type: !zeroForOne ? \"zeroForOne\" : \"oneForZero\", count: 2, tickArrayCurrent: poolInfo.tickCurrent },\n }).filter((i) => i.toString() !== tickArrays[0].address.toString())\n : [];\n\n const _startTickIndex = TickArrayUtil.getTickArrayStartIndex(poolInfo.tickCurrent, poolInfo.tickSpacing);\n const { firstItckArrayContainsPoolTick: _firstItckArrayContainsPoolTick, firstValidTickArrayStartIndex } = {\n firstItckArrayContainsPoolTick: tickArrays[tickArrayListIndex].value.startTickIndex === _startTickIndex,\n firstValidTickArrayStartIndex: tickArrays[tickArrayListIndex].value.startTickIndex,\n };\n let firstItckArrayContainsPoolTick = _firstItckArrayContainsPoolTick;\n\n let currentValidTIckArrayStrartIndex = firstValidTickArrayStartIndex;\n\n let tickArrayCurrent = tickArrays[tickArrayListIndex];\n\n const isFeeOnInput = PoolUtil.isFeeOnInput(poolInfo.feeOn, zeroForOne);\n\n const state = SwapState.newValue({\n poolInfo,\n amountSpecified,\n zeroForOne,\n feeRate: configInfo.tradeFeeRate,\n blockTimestamp,\n });\n\n while (!state.amountSpecifiedRemaining.isZero() && !state.sqrtPriceX64.eq(sqrtPriceLimitX64)) {\n const nextInitializedTick = (() => {\n const tickState = TickArrayUtil.nextInitalizedTick({\n data: tickArrayCurrent.value,\n tickSpacing: state.tickSpacing,\n zeroForOne,\n currentTickIndex: state.tick,\n });\n if (tickState !== undefined) {\n return tickState;\n } else if (!firstItckArrayContainsPoolTick) {\n firstItckArrayContainsPoolTick = true;\n return TickArrayUtil.firstinitializedTick({ data: tickArrayCurrent.value, zeroForOne });\n } else {\n const nextTickArrayIndex = tickArrays[++tickArrayListIndex];\n if (nextTickArrayIndex === undefined) {\n return undefined;\n }\n\n currentValidTIckArrayStrartIndex = nextTickArrayIndex.value.startTickIndex;\n tickArrayCurrent = nextTickArrayIndex;\n return TickArrayUtil.firstinitializedTick({ data: nextTickArrayIndex.value, zeroForOne });\n }\n })();\n\n if (nextInitializedTick === undefined) {\n return {\n allTrade: false,\n amountSpecifiedRemaining: state.amountSpecifiedRemaining,\n amountCalculated: state.amountCalculated,\n feeAmount: state.lpFee.add(state.fundFee).add(state.protocolFee),\n sqrtPriceX64: state.sqrtPriceX64,\n liquidity: state.liquidity,\n tickCurrent: state.tick,\n accounts: tickArrays.slice(0, tickArrayListIndex).map((i) => i.address),\n };\n }\n\n const targetPrice = SwapState.getTargetPriceBasedOnNextTick({\n data: state,\n tickNext: nextInitializedTick.tick,\n zeroForOne,\n sqrtPriceLimitX64,\n });\n\n let liquidityNext = state.liquidity;\n do {\n SwapState.updateVolatilityAccumulator({ state });\n\n const totalFeeRate = SwapState.getTotalFeeRate({ data: state });\n const { isSkipped: isSkippedTickSpacing, boundedPrice } = SwapState.getSpacingBoundedPrice({\n data: state,\n targetPrice,\n zeroForOne,\n });\n\n const isPriceChange = !state.sqrtPriceX64.eq(boundedPrice);\n\n let swapComputedResult;\n if (isPriceChange) {\n swapComputedResult = SwapMathUtil.computeSwap(\n state.sqrtPriceX64,\n boundedPrice,\n state.liquidity,\n state.amountSpecifiedRemaining,\n totalFeeRate,\n isBaseInput,\n zeroForOne,\n isFeeOnInput,\n );\n\n SwapState.applySwapAmounts({\n state,\n amountIn: swapComputedResult.amountIn,\n amountOut: swapComputedResult.amountOut,\n feeAmount: swapComputedResult.feeAmount,\n isBaseInput,\n isFeeOnInput,\n protocolFeeRate: new BN(configInfo.protocolFeeRate),\n fundFeeRate: new BN(configInfo.fundFeeRate),\n });\n } else {\n swapComputedResult = SwapMathUtil.newSwapComputationResult({ sqrtPriceNextX64: boundedPrice });\n }\n\n const limitOrderUnfilledAmountBefore = TickUtil.limitOrderUnfilledAmount({ tick: nextInitializedTick });\n if (state.sqrtPriceNextX64.eq(swapComputedResult.sqrtPriceNextX64)) {\n const limitOrderResult = TickUtil.matchLimitOrder({\n tick: nextInitializedTick,\n swapAmount: state.amountSpecifiedRemaining,\n swapDirectionZeroForOne: zeroForOne,\n isBaseInput,\n feeRate: totalFeeRate,\n isFeeOnInput,\n });\n\n if (limitOrderResult.amountIn.gt(BN_ZERO)) {\n SwapState.applySwapAmounts({\n state,\n amountIn: limitOrderResult.amountIn,\n amountOut: limitOrderResult.amountOut,\n feeAmount: limitOrderResult.ammFeeAmount,\n isBaseInput,\n isFeeOnInput,\n protocolFeeRate: new BN(configInfo.protocolFeeRate),\n fundFeeRate: new BN(configInfo.fundFeeRate),\n });\n }\n\n if (\n TickUtil.hasLiquidity({ data: nextInitializedTick }) &&\n !TickUtil.hasLimitOrders({ data: nextInitializedTick })\n ) {\n const liquidityNet = zeroForOne ? nextInitializedTick.liquidityNet.neg() : nextInitializedTick.liquidityNet;\n\n liquidityNext = LiquidityMathUtil.addDelta(state.liquidity, liquidityNet);\n }\n\n state.tick =\n (zeroForOne && !TickUtil.hasLimitOrders({ data: nextInitializedTick })) ||\n (!zeroForOne && TickUtil.hasLimitOrders({ data: nextInitializedTick }))\n ? state.tickNext - 1\n : state.tickNext;\n } else if (!state.sqrtPriceX64.eq(swapComputedResult.sqrtPriceNextX64)) {\n state.tick = TickUtil.getTickAtSqrtPrice(swapComputedResult.sqrtPriceNextX64);\n }\n\n state.sqrtPriceX64 = swapComputedResult.sqrtPriceNextX64;\n SwapState.updateDynamicFeeIndex({ state, zeroForOne, isSkippedTickSpacing });\n if (state.amountSpecifiedRemaining.isZero() || state.sqrtPriceX64.eq(targetPrice)) {\n const limitOrderUnfilledAmountAfter = TickUtil.limitOrderUnfilledAmount({ tick: nextInitializedTick });\n\n if (\n !state.amountSpecifiedRemaining.isZero() &&\n !limitOrderUnfilledAmountAfter.eq(limitOrderUnfilledAmountBefore)\n ) {\n if (!limitOrderUnfilledAmountAfter.isZero()) throw Error(\"!limitOrderUnfilledAmountAfter.isZero()\");\n }\n break;\n }\n\n // eslint-disable-next-line no-constant-condition\n } while (true);\n state.liquidity = liquidityNext;\n // SwapState.splitFee({ state, protocolFeeRate: new BN(configInfo.protocolFeeRate), fundFeeRate: new BN(configInfo.fundFeeRate) })\n }\n SwapState.updateVolatilityAccumulatorOnPrice({ state });\n\n return {\n allTrade: true,\n amountSpecifiedRemaining: BN_ZERO,\n amountCalculated: state.amountCalculated,\n feeAmount: state.lpFee.add(state.fundFee).add(state.protocolFee),\n sqrtPriceX64: state.sqrtPriceX64,\n liquidity: state.liquidity,\n tickCurrent: state.tick,\n accounts: [\n ...addTickArrayAddress,\n ...tickArrays.slice(0, tickArrayListIndex + 1 + (includeExtraTickArrays ? 1 : 0)).map((i) => i.address),\n ],\n };\n}\n","import BN from \"bn.js\";\n\nexport const Q64 = new BN(1).shln(64);\n\nexport const RESOLUTION = 64;\n\nexport const Q128 = new BN(1).shln(128);\n\nexport const U64_MAX = new BN(1).shln(64).subn(1);\n\nexport const U128_MAX = new BN(1).shln(128).subn(1);\n\nexport const MIN_TICK = -443636;\n\nexport const MAX_TICK = 443636;\n\nexport const MIN_SQRT_PRICE_X64 = new BN(\"4295048016\");\n\nexport const MAX_SQRT_PRICE_X64 = new BN(\"79226673521066979257578248091\");\n\nexport const LOG_B_2_X32 = new BN(\"59543866431248\");\n\nexport const LOG_B_P_ERR_MARGIN_LOWER_X64 = new BN(\"184467440737095516\");\n\nexport const LOG_B_P_ERR_MARGIN_UPPER_X64 = new BN(\"15793534762490258745\");\n\nexport const BIT_PRECISION = 16;\n\nexport const TICK_ARRAY_BITMAP_SIZE = 512;\n\nexport const TICK_ARRAY_SIZE = 60;\n\nexport const MAGIC_SQRT_10001 = new BN(\"18446743708227953217\");\n\nexport const TICK_TO_SQRT_PRICE_FACTORS: { bit: number; factor: BN }[] = [\n { bit: 0, factor: new BN(\"fffcb933bd6fb800\", 16) }, // i=0\n { bit: 1, factor: new BN(\"fff97272373d4000\", 16) }, // i=1\n { bit: 2, factor: new BN(\"fff2e50f5f657000\", 16) }, // i=2\n { bit: 3, factor: new BN(\"ffe5caca7e10f000\", 16) }, // i=3\n { bit: 4, factor: new BN(\"ffcb9843d60f7000\", 16) }, // i=4\n { bit: 5, factor: new BN(\"ff973b41fa98e800\", 16) }, // i=5\n { bit: 6, factor: new BN(\"ff2ea16466c9b000\", 16) }, // i=6\n { bit: 7, factor: new BN(\"fe5dee046a9a3800\", 16) }, // i=7\n { bit: 8, factor: new BN(\"fcbe86c7900bb000\", 16) }, // i=8\n { bit: 9, factor: new BN(\"f987a7253ac65800\", 16) }, // i=9\n { bit: 10, factor: new BN(\"f3392b0822bb6000\", 16) }, // i=10\n { bit: 11, factor: new BN(\"e7159475a2caf000\", 16) }, // i=11\n { bit: 12, factor: new BN(\"d097f3bdfd2f2000\", 16) }, // i=12\n { bit: 13, factor: new BN(\"a9f746462d9f8000\", 16) }, // i=13\n { bit: 14, factor: new BN(\"70d869a156f31c00\", 16) }, // i=14\n { bit: 15, factor: new BN(\"31be135f97ed3200\", 16) }, // i=15\n { bit: 16, factor: new BN(\"9aa508b5b85a500\", 16) }, // i=16\n { bit: 17, factor: new BN(\"5d6af8dedc582c\", 16) }, // i=17\n { bit: 18, factor: new BN(\"2216e584f5fa\", 16) }, // i=18\n];\n\nexport const FEE_RATE_DENOMINATOR = 1_000_000;\n\nexport const MAX_FEE_RATE = 100_000;\n\nexport enum CollectFeeOn {\n FromInput = 0,\n TokenOnlyA = 1,\n TokenOnlyB = 2,\n}\n\n// export const FEE_RATE_DENOMINATOR_VALUE = 1_000_000;\n\nexport const MAX_FEE_RATE_NUMERATOR = 100_000;\nexport const VOLATILITY_ACCUMULATOR_SCALE = 10_000;\nexport const REDUCTION_FACTOR_DENOMINATOR = 10_000;\nexport const DYNAMIC_FEE_CONTROL_DENOMINATOR = 100_000;\n\nexport const TICK_ARRAY_SIZE_USIZE = 60;\n\nexport const REWARD_NUM = 3;\n\nexport const OBSERVATION_NUM = 100;\nexport const OBSERVATION_UPDATE_DURATION_DEFAULT = 15;\n\nexport const OPERATION_SIZE_USIZE = 10;\nexport const WHITE_MINT_SIZE_USIZE = 100;\n\nexport const EXTENSION_TICKARRAY_BITMAP_SIZE = 14;\n\nexport enum PoolStatusBitIndex {\n OpenPositionOrIncreaseLiquidity = 0,\n DecreaseLiquidity = 1,\n CollectFee = 2,\n CollectReward = 3,\n Swap = 4,\n LimitOrder = 5,\n}\n\nexport enum PoolStatusBitFlag {\n Enable = 0,\n Disable = 1,\n}\n\nexport enum RewardState {\n Uninitialized = 0,\n Initialized = 1,\n Opening = 2,\n Ended = 3,\n}\n\nexport enum UpdateAmmConfigParam {\n TradeFeeRate = 0,\n ProtocolFeeRate = 1,\n FundFeeRate = 2,\n NewOwner = 3,\n NewFundOwner = 4,\n}\n\nexport enum UpdateOperationAccountParam {\n UpdateOperationOwner = 0,\n RemoveOperationOwner = 1,\n UpdateWhitelistMint = 2,\n RemoveWhitelistMint = 3,\n}\n\nexport const BN_ZERO = new BN(0);\nexport const BN_ONE = new BN(1);\nexport const BN_NEGATIVE_ONE = new BN(-1);\n\nexport const mockV3CreatePoolInfo = {\n tvl: 0,\n volumeQuote: 0,\n mintAmountA: 0,\n mintAmountB: 0,\n rewardDefaultInfos: [],\n farmUpcomingCount: 0,\n farmOngoingCount: 0,\n farmFinishedCount: 0,\n\n day: {\n volume: 0,\n volumeQuote: 0,\n volumeFee: 0,\n apr: 0,\n feeApr: 0,\n priceMin: 0,\n priceMax: 0,\n rewardApr: [0],\n },\n week: {\n volume: 0,\n volumeQuote: 0,\n volumeFee: 0,\n apr: 0,\n feeApr: 0,\n priceMin: 0,\n priceMax: 0,\n rewardApr: [0],\n },\n month: {\n volume: 0,\n volumeQuote: 0,\n volumeFee: 0,\n apr: 0,\n feeApr: 0,\n priceMin: 0,\n priceMax: 0,\n rewardApr: [0],\n },\n pooltype: [],\n};\n\n/**\n * Get human-readable description for collectFeeOn value\n * CollectFeeOn enum values:\n * 0 = FromInput - fee collected from input token during swap\n * 1 = Token0Only - fee collected from token0\n * 2 = Token1Only - fee collected from token1\n */\nexport function getCollectFeeOnDescription(value: number): string {\n switch (value) {\n case 0:\n return \"0 (FromInput - fee from input token)\";\n case 1:\n return \"1 (Token0Only - fee from token0)\";\n case 2:\n return \"2 (Token1Only - fee from token1)\";\n default:\n return `${value} (unknown)`;\n }\n}\n\nexport const DYNAMIC_CONFIG_INDEX = 2;\nexport const U64_IGNORE_RANGE = new BN(\"18446744073700000000\");\n","import BN from \"bn.js\";\nimport Decimal from \"decimal.js\";\nimport { divRoundingUp, mulDivCeil, mulDivFloor } from \"./bigNum\";\nimport { BN_ZERO, Q64, RESOLUTION, U64_MAX } from \"./constants\";\nimport { SqrtPriceMath } from \"./sqrtPriceMath\";\n\nexport class LiquidityMathUtil {\n static getDeltaAmountAUnsigned(sqrtPriceX64A: BN, sqrtPriceX64B: BN, liquidity: BN, roundUp: boolean): BN {\n if (sqrtPriceX64A.gt(sqrtPriceX64B)) {\n [sqrtPriceX64A, sqrtPriceX64B] = [sqrtPriceX64B, sqrtPriceX64A];\n }\n\n const numerator1 = liquidity.shln(RESOLUTION);\n const numerator2 = sqrtPriceX64B.sub(sqrtPriceX64A);\n\n if (!sqrtPriceX64A.gt(BN_ZERO)) throw Error(\"!sqrtPriceX64A.gt(BN_ZERO)\");\n\n const result = roundUp\n ? divRoundingUp(mulDivCeil(numerator1, numerator2, sqrtPriceX64B), sqrtPriceX64A)\n : mulDivFloor(numerator1, numerator2, sqrtPriceX64B).div(sqrtPriceX64A);\n\n if (result.gt(U64_MAX)) throw Error(\"MaxTokenOverflow\");\n\n return result;\n }\n\n static getDeltaAmountBUnsigned(sqrtPriceX64A: BN, sqrtPriceX64B: BN, liquidity: BN, roundUp: boolean): BN {\n if (sqrtPriceX64A.gt(sqrtPriceX64B)) {\n [sqrtPriceX64A, sqrtPriceX64B] = [sqrtPriceX64B, sqrtPriceX64A];\n }\n\n const result = roundUp\n ? mulDivCeil(liquidity, sqrtPriceX64B.sub(sqrtPriceX64A), Q64)\n : mulDivFloor(liquidity, sqrtPriceX64B.sub(sqrtPriceX64A), Q64);\n\n if (result.gt(U64_MAX)) throw Error(\"MaxTokenOverflow\");\n\n return result;\n }\n\n static addDelta(x: BN, y: BN): BN {\n if (y.isNeg()) {\n const absY = y.neg();\n if (x.lt(absY)) {\n throw new Error(\"Liquidity underflow\");\n }\n return x.sub(absY);\n } else {\n return x.add(y);\n }\n }\n\n static getLiquidityFromAmountA(sqrtPriceLowerX64: BN, sqrtPriceUpperX64: BN, amountA: BN): BN {\n if (sqrtPriceLowerX64.gt(sqrtPriceUpperX64)) {\n [sqrtPriceLowerX64, sqrtPriceUpperX64] = [sqrtPriceUpperX64, sqrtPriceLowerX64];\n }\n\n const intermediate = mulDivFloor(sqrtPriceLowerX64, sqrtPriceUpperX64, Q64);\n\n const priceDelta = sqrtPriceUpperX64.sub(sqrtPriceLowerX64);\n\n return mulDivFloor(amountA, intermediate, priceDelta);\n }\n\n static getLiquidityFromAmountB(sqrtPriceLowerX64: BN, sqrtPriceUpperX64: BN, amountB: BN): BN {\n if (sqrtPriceLowerX64.gt(sqrtPriceUpperX64)) {\n [sqrtPriceLowerX64, sqrtPriceUpperX64] = [sqrtPriceUpperX64, sqrtPriceLowerX64];\n }\n\n const priceDelta = sqrtPriceUpperX64.sub(sqrtPriceLowerX64);\n\n return mulDivFloor(amountB, Q64, priceDelta);\n }\n\n static getLiquidityFromAmounts(\n sqrtPriceCurrentX64: BN,\n sqrtPriceLowerX64: BN,\n sqrtPriceUpperX64: BN,\n amountA: BN,\n amountB: BN,\n ): BN {\n if (sqrtPriceLowerX64.gt(sqrtPriceUpperX64)) {\n [sqrtPriceLowerX64, sqrtPriceUpperX64] = [sqrtPriceUpperX64, sqrtPriceLowerX64];\n }\n\n if (sqrtPriceCurrentX64.lte(sqrtPriceLowerX64)) {\n return this.getLiquidityFromAmountA(sqrtPriceLowerX64, sqrtPriceUpperX64, amountA);\n } else if (sqrtPriceCurrentX64.lt(sqrtPriceUpperX64)) {\n const liquidityA = this.getLiquidityFromAmountA(sqrtPriceCurrentX64, sqrtPriceUpperX64, amountA);\n const liquidityB = this.getLiquidityFromAmountB(sqrtPriceLowerX64, sqrtPriceCurrentX64, amountB);\n return liquidityA.lt(liquidityB) ? liquidityA : liquidityB;\n } else {\n return this.getLiquidityFromAmountB(sqrtPriceLowerX64, sqrtPriceUpperX64, amountB);\n }\n }\n\n static getAmountForLiquidityA(sqrtPriceLowerX64: BN, sqrtPriceUpperX64: BN, liquidity: BN, roundUp: boolean): BN {\n return SqrtPriceMath.getAmountADeltaUnsigned(sqrtPriceLowerX64, sqrtPriceUpperX64, liquidity, roundUp);\n }\n\n static getAmountForLiquidityB(sqrtPriceLowerX64: BN, sqrtPriceUpperX64: BN, liquidity: BN, roundUp: boolean): BN {\n return SqrtPriceMath.getAmountBDeltaUnsigned(sqrtPriceLowerX64, sqrtPriceUpperX64, liquidity, roundUp);\n }\n\n static getAmountsForLiquidity(\n sqrtPriceCurrentX64: BN,\n sqrtPriceLowerX64: BN,\n sqrtPriceUpperX64: BN,\n liquidity: BN,\n roundUp: boolean,\n ) {\n if (sqrtPriceLowerX64.gt(sqrtPriceUpperX64)) {\n [sqrtPriceLowerX64, sqrtPriceUpperX64] = [sqrtPriceUpperX64, sqrtPriceLowerX64];\n }\n\n let amountA = BN_ZERO;\n let amountB = BN_ZERO;\n\n if (sqrtPriceCurrentX64.lte(sqrtPriceLowerX64)) {\n amountA = this.getAmountForLiquidityA(sqrtPriceLowerX64, sqrtPriceUpperX64, liquidity, roundUp);\n } else if (sqrtPriceCurrentX64.lt(sqrtPriceUpperX64)) {\n amountA = this.getAmountForLiquidityA(sqrtPriceCurrentX64, sqrtPriceUpperX64, liquidity, roundUp);\n amountB = this.getAmountForLiquidityB(sqrtPriceLowerX64, sqrtPriceCurrentX64, liquidity, roundUp);\n } else {\n amountB = this.getAmountForLiquidityB(sqrtPriceLowerX64, sqrtPriceUpperX64, liquidity, roundUp);\n }\n\n return { amountA, amountB };\n }\n\n static getAmountsFromLiquidityWithSlippage(\n sqrtPriceCurrentX64: BN,\n sqrtPriceX64A: BN,\n sqrtPriceX64B: BN,\n liquidity: BN,\n amountMax: boolean,\n roundUp: boolean,\n amountSlippage: number,\n ): { amountSlippageA: BN; amountSlippageB: BN } {\n const { amountA, amountB } = this.getAmountsForLiquidity(\n sqrtPriceCurrentX64,\n sqrtPriceX64A,\n sqrtPriceX64B,\n liquidity,\n roundUp,\n );\n const coefficient = amountMax ? 1 + amountSlippage : 1 - amountSlippage;\n\n const amount0Slippage = new BN(new Decimal(amountA.toString()).mul(coefficient).toFixed(0));\n const amount1Slippage = new BN(new Decimal(amountB.toString()).mul(coefficient).toFixed(0));\n return {\n amountSlippageA: amount0Slippage,\n amountSlippageB: amount1Slippage,\n };\n }\n\n static getLiquidityAndAmountsFromAmount({\n sqrtPriceCurrentX64,\n sqrtPriceLowerX64,\n sqrtPriceUpperX64,\n amountInfo,\n }: {\n sqrtPriceCurrentX64: BN;\n sqrtPriceLowerX64: BN;\n sqrtPriceUpperX64: BN;\n amountInfo: { type: \"liquidity\" | \"amountA\" | \"amountB\"; amount: BN };\n }): { liquidity: BN; amountA: BN; amountB: BN } {\n let liquidity;\n if (amountInfo.type === \"liquidity\") {\n liquidity = amountInfo.amount;\n } else if (amountInfo.type === \"amountA\") {\n liquidity = sqrtPriceCurrentX64.gte(sqrtPriceUpperX64)\n ? BN_ZERO\n : this.getLiquidityFromAmountA(\n BN.max(sqrtPriceCurrentX64, sqrtPriceLowerX64),\n sqrtPriceUpperX64,\n amountInfo.amount,\n );\n } else if (amountInfo.type === \"amountB\") {\n liquidity = sqrtPriceCurrentX64.lte(sqrtPriceLowerX64)\n ? BN_ZERO\n : this.getLiquidityFromAmountB(\n sqrtPriceLowerX64,\n BN.min(sqrtPriceCurrentX64, sqrtPriceUpperX64),\n amountInfo.amount,\n );\n } else {\n throw Error(\"amount info type check error\");\n }\n\n return {\n liquidity,\n ...this.getAmountsForLiquidity(\n sqrtPriceCurrentX64,\n sqrtPriceLowerX64,\n sqrtPriceUpperX64,\n amountInfo.amount,\n true,\n ),\n };\n }\n}\n","import BN from \"bn.js\"\nimport Decimal from \"decimal.js\"\nimport { BN_ONE, BN_ZERO, Q128, U128_MAX } from \"./constants\"\n\nexport function mask(bits: number): BN {\n return new BN(1).shln(bits).subn(1)\n}\n\nexport function checkedAdd(a: BN, b: BN, maxBits: number): BN {\n const result = a.add(b)\n const maxValue = mask(maxBits)\n if (result.gt(maxValue)) {\n throw new Error(`Addition overflow: result exceeds ${maxBits} bits`)\n }\n return result\n}\n\nexport function checkedSub(a: BN, b: BN): BN {\n if (a.lt(b)) {\n throw new Error(\"Subtraction underflow\")\n }\n return a.sub(b)\n}\n\nexport function checkedMul(a: BN, b: BN, maxBits: number): BN {\n const result = a.mul(b)\n const maxValue = mask(maxBits)\n if (result.gt(maxValue)) {\n throw new Error(`Multiplication overflow: result exceeds ${maxBits} bits`)\n }\n return result\n}\n\nexport function mulFull(a: BN, b: BN): [BN, BN] {\n const result = a.mul(b)\n const low = result.and(mask(128))\n const high = result.shrn(128)\n return [low, high]\n}\n\nexport function mulDivFloor(a: BN, b: BN, denominator: BN): BN {\n if (denominator.isZero()) {\n throw new Error(\"Division by zero\")\n }\n return a.mul(b).div(denominator)\n}\n\nexport function mulDivCeil(a: BN, b: BN, denominator: BN): BN {\n if (denominator.isZero()) {\n throw new Error(\"Division by zero\")\n }\n const product = a.mul(b)\n const quotient = product.div(denominator)\n const remainder = product.mod(denominator)\n\n if (remainder.isZero()) {\n return quotient\n }\n return quotient.addn(1)\n}\n\nexport function mulDivRound(a: BN, b: BN, denominator: BN, roundUp: boolean): BN {\n return roundUp ? mulDivCeil(a, b, denominator) : mulDivFloor(a, b, denominator)\n}\n\nexport function divRoundingUp(x: BN, y: BN) {\n return x.div(y).add(x.mod(y).isZero() ? BN_ZERO : BN_ONE)\n}\n\nexport function u128SaturatingAdd(a: BN, b: BN): BN {\n const result = a.add(b)\n return result.gt(U128_MAX) ? U128_MAX : result\n}\n\nexport function u128SaturatingSub(a: BN, b: BN): BN {\n return a.gt(b) ? a.sub(b) : new BN(0)\n}\n\nexport function u128CheckedMul(a: BN, b: BN): BN {\n const result = a.mul(b)\n if (result.gt(U128_MAX)) {\n throw new Error(\"U128 multiplication overflow\")\n }\n return result\n}\n\nexport const U256_MAX = new BN(1).shln(256).subn(1)\n\nexport function u256MulDivFloor(a: BN, b: BN, denominator: BN): BN {\n if (denominator.isZero()) {\n throw new Error(\"Division by zero\")\n }\n return a.mul(b).div(denominator)\n}\n\nexport function u256MulDivCeil(a: BN, b: BN, denominator: BN): BN {\n if (denominator.isZero()) {\n throw new Error(\"Division by zero\")\n }\n const product = a.mul(b)\n const quotient = product.div(denominator)\n const remainder = product.mod(denominator)\n\n if (remainder.isZero()) {\n return quotient\n }\n return quotient.addn(1)\n}\n\nexport function mostSignificantBit(n: BN): number {\n if (n.isZero()) {\n return -1\n }\n return n.bitLength() - 1\n}\n\nexport function leastSignificantBit(n: BN): number {\n if (n.isZero()) {\n return -1\n }\n\n let pos = 0\n let temp = n.clone()\n\n while (temp.and(new BN(1)).isZero()) {\n temp = temp.shrn(1)\n pos++\n }\n\n return pos\n}\n\nexport function isBitSet(n: BN, bit: number): boolean {\n return n.testn(bit)\n}\n\nexport function setBit(n: BN, bit: number): BN {\n return n.or(new BN(1).shln(bit))\n}\n\nexport function clearBit(n: BN, bit: number): BN {\n return n.and(new BN(1).shln(bit).notn(256))\n}\n\nexport function toggleBit(n: BN, bit: number): BN {\n return n.xor(new BN(1).shln(bit))\n}\n\nexport function toSignedI128(n: BN): BN {\n const signBit = new BN(1).shln(127)\n if (n.and(signBit).isZero()) {\n return n\n }\n return n.sub(new BN(1).shln(128))\n}\n\nexport function fromSignedI128(n: BN): BN {\n if (n.isNeg()) {\n return n.add(new BN(1).shln(128))\n }\n return n\n}\n\nexport function abs(n: BN): BN {\n return n.isNeg() ? n.neg() : n\n}\n\nexport function x64ToDecimal(num: BN, decimalPlaces?: number): Decimal {\n return new Decimal(num.toString()).div(Decimal.pow(2, 64)).toDecimalPlaces(decimalPlaces)\n}\n\nexport function decimalToX64(num: Decimal): BN {\n return new BN(num.mul(Decimal.pow(2, 64)).floor().toFixed())\n}\n\nexport function wrappingSubU128(n0: BN, n1: BN): BN {\n return n0.add(Q128).sub(n1).mod(Q128)\n}\n","import BN from \"bn.js\"\nimport { divRoundingUp, mulDivCeil, mulDivFloor } from \"./bigNum\"\nimport { BN_ONE, BN_ZERO, Q64, RESOLUTION } from \"./constants\"\n\nexport class SqrtPriceMath {\n static getNextSqrtPriceFromAmountARoundingUp(\n sqrtPriceX64: BN,\n liquidity: BN,\n amount: BN,\n add: boolean\n ): BN {\n if (amount.isZero()) {\n return sqrtPriceX64\n }\n\n const numerator = liquidity.shln(RESOLUTION)\n\n if (add) {\n const product = amount.mul(sqrtPriceX64)\n\n const denominator = numerator.add(product)\n\n if (denominator.gte(numerator)) {\n return mulDivCeil(numerator, sqrtPriceX64, denominator)\n }\n\n const quotient = mulDivFloor(numerator, BN_ONE, sqrtPriceX64)\n return mulDivCeil(numerator, BN_ONE, quotient.add(amount))\n } else {\n const product = amount.mul(sqrtPriceX64)\n\n if (numerator.lte(product)) {\n throw new Error(\"Insufficient liquidity for token0 removal\")\n }\n\n const denominator = numerator.sub(product)\n\n return mulDivCeil(numerator, sqrtPriceX64, denominator)\n }\n }\n\n static getNextSqrtPriceFromAmountBRoundingDown(\n sqrtPriceX64: BN,\n liquidity: BN,\n amount: BN,\n add: boolean\n ): BN {\n if (amount.isZero()) {\n return sqrtPriceX64\n }\n\n if (add) {\n const quotient = amount.shln(RESOLUTION).div(liquidity)\n return sqrtPriceX64.add(quotient)\n } else {\n const quotient = divRoundingUp(amount.shln(RESOLUTION), liquidity)\n return sqrtPriceX64.sub(quotient)\n }\n }\n\n static getNextSqrtPriceFromInput(\n sqrtPriceX64: BN,\n liquidity: BN,\n amountIn: BN,\n zeroForOne: boolean\n ): BN {\n if (!sqrtPriceX64.gt(BN_ZERO)) throw Error('sqrtPriceX64.gt(BN_ZERO)')\n if (!liquidity.gt(BN_ZERO)) throw Error('liquidity.gt(BN_ZERO)')\n\n if (zeroForOne) {\n return this.getNextSqrtPriceFromAmountARoundingUp(sqrtPriceX64, liquidity, amountIn, true)\n } else {\n return this.getNextSqrtPriceFromAmountBRoundingDown(sqrtPriceX64, liquidity, amountIn, true)\n }\n }\n\n static getNextSqrtPriceFromOutput(\n sqrtPriceX64: BN,\n liquidity: BN,\n amountIn: BN,\n zeroForOne: boolean\n ): BN {\n if (!sqrtPriceX64.gt(BN_ZERO)) throw Error('sqrtPriceX64.gt(BN_ZERO)')\n if (!liquidity.gt(BN_ZERO)) throw Error('liquidity.gt(BN_ZERO)')\n\n if (zeroForOne) {\n return this.getNextSqrtPriceFromAmountBRoundingDown(sqrtPriceX64, liquidity, amountIn, false)\n } else {\n return this.getNextSqrtPriceFromAmountARoundingUp(sqrtPriceX64, liquidity, amountIn, false)\n }\n }\n\n static getAmountADeltaUnsigned(\n sqrtPriceLowerX64: BN,\n sqrtPriceUpperX64: BN,\n liquidity: BN,\n roundUp: boolean\n ): BN {\n if (sqrtPriceLowerX64.gt(sqrtPriceUpperX64)) {\n [sqrtPriceLowerX64, sqrtPriceUpperX64] = [sqrtPriceUpperX64, sqrtPriceLowerX64]\n }\n\n const priceDelta = sqrtPriceUpperX64.sub(sqrtPriceLowerX64)\n const numerator = liquidity.mul(priceDelta).shln(64)\n\n const denominator = sqrtPriceLowerX64.mul(sqrtPriceUpperX64)\n\n if (roundUp) {\n return mulDivCeil(numerator, BN_ONE, denominator)\n } else {\n return mulDivFloor(numerator, BN_ONE, denominator)\n }\n }\n\n static getAmountBDeltaUnsigned(\n sqrtPriceLowerX64: BN,\n sqrtPriceUpperX64: BN,\n liquidity: BN,\n roundUp: boolean\n ): BN {\n if (sqrtPriceLowerX64.gt(sqrtPriceUpperX64)) {\n [sqrtPriceLowerX64, sqrtPriceUpperX64] = [sqrtPriceUpperX64, sqrtPriceLowerX64]\n }\n\n const priceDelta = sqrtPriceUpperX64.sub(sqrtPriceLowerX64)\n\n if (roundUp) {\n return mulDivCeil(liquidity, priceDelta, Q64)\n } else {\n return mulDivFloor(liquidity, priceDelta, Q64)\n }\n }\n}\n","import { PublicKey } from \"@solana/web3.js\";\nimport BN from \"bn.js\";\nimport { DynamicFeeInfoLayout, PoolInfoLayout } from \"../layout\";\nimport { mulDivCeil, mulDivFloor } from \"./bigNum\";\nimport {\n BN_ZERO,\n CollectFeeOn,\n MAX_TICK,\n MIN_TICK,\n Q64,\n REDUCTION_FACTOR_DENOMINATOR,\n U64_MAX,\n VOLATILITY_ACCUMULATOR_SCALE,\n} from \"./constants\";\nimport { TickArrayBitmapUtil, TickArrayUtil, TickUtil } from \"./tickArrayUtil\";\n\nexport class PoolFee {\n static tickSpacingIndexFromTick(tickIndex: number, tickSpacing: number): number {\n if (tickIndex % tickSpacing == 0 || tickIndex >= 0) {\n return tickIndex / tickSpacing;\n } else {\n return tickIndex / tickSpacing - 1;\n }\n }\n}\n\nexport class DynamicFeeInfo {\n static getDynamicFeeInfo({ poolInfo }: { poolInfo: ReturnType<typeof PoolInfoLayout.decode> }) {\n if (\n poolInfo.dynamicFeeInfo.filterPeriod === 0 &&\n poolInfo.dynamicFeeInfo.decayPeriod === 0 &&\n poolInfo.dynamicFeeInfo.reductionFactor === 0 &&\n poolInfo.dynamicFeeInfo.dynamicFeeControl === 0 &&\n poolInfo.dynamicFeeInfo.maxVolatilityAccumulator === 0 &&\n poolInfo.dynamicFeeInfo.tickSpacingIndexReference === 0 &&\n poolInfo.dynamicFeeInfo.volatilityReference === 0 &&\n poolInfo.dynamicFeeInfo.volatilityAccumulator === 0 &&\n poolInfo.dynamicFeeInfo.lastUpdateTimestamp.isZero()\n ) {\n return undefined;\n }\n return poolInfo.dynamicFeeInfo;\n }\n\n static updateReference({\n dynamicFeeInfo,\n tickSpacingIndex,\n currentTimestamp,\n }: {\n dynamicFeeInfo: ReturnType<typeof DynamicFeeInfoLayout.decode>;\n tickSpacingIndex: number;\n currentTimestamp: number;\n }) {\n const timeSinceReferenceUpdate = currentTimestamp - dynamicFeeInfo.lastUpdateTimestamp.toNumber();\n\n if (timeSinceReferenceUpdate < dynamicFeeInfo.filterPeriod) {\n //\n } else if (timeSinceReferenceUpdate < dynamicFeeInfo.decayPeriod) {\n dynamicFeeInfo.tickSpacingIndexReference = tickSpacingIndex;\n dynamicFeeInfo.volatilityReference = Math.floor(\n (dynamicFeeInfo.volatilityAccumulator * dynamicFeeInfo.reductionFactor) / REDUCTION_FACTOR_DENOMINATOR,\n );\n dynamicFeeInfo.lastUpdateTimestamp = new BN(currentTimestamp);\n } else {\n dynamicFeeInfo.tickSpacingIndexReference = tickSpacingIndex;\n dynamicFeeInfo.volatilityReference = 0;\n dynamicFeeInfo.lastUpdateTimestamp = new BN(currentTimestamp);\n }\n }\n\n static updateVolatilityAccumulator({\n state,\n tickSpacingIndex,\n }: {\n state: ReturnType<typeof DynamicFeeInfoLayout.decode>;\n tickSpacingIndex: number;\n }) {\n const indexDelta = Math.abs(state.tickSpacingIndexReference - tickSpacingIndex);\n const volatilityAccumulator = state.volatilityReference + indexDelta * VOLATILITY_ACCUMULATOR_SCALE;\n\n state.volatilityAccumulator = Math.min(volatilityAccumulator, state.maxVolatilityAccumulator);\n }\n}\n\nexport class PoolUtil {\n static isFeeOnInput(feeOn: number, zeroForOne: boolean): boolean {\n switch (feeOn) {\n case CollectFeeOn.FromInput:\n return true;\n case CollectFeeOn.TokenOnlyA:\n return zeroForOne;\n case CollectFeeOn.TokenOnlyB:\n return !zeroForOne;\n default:\n return true;\n }\n }\n\n static isFeeOnTokenA(poolInfo: ReturnType<typeof PoolInfoLayout.decode>, zeroForOne: boolean) {\n if (poolInfo.feeOn === CollectFeeOn.FromInput) return zeroForOne;\n if (poolInfo.feeOn === CollectFeeOn.TokenOnlyA) return true;\n return false;\n }\n\n static isOverflowDefaultTickarrayBitmap({ tickSpacing, tickIndexs }: { tickSpacing: number; tickIndexs: number[] }) {\n const { maxTickBoundary, minTickBoundary } = this.tickArrayStartIndexRange({ tickSpacing });\n for (const tickIndex of tickIndexs) {\n const tickarrayStartIndex = TickArrayUtil.getTickArrayStartIndex(tickIndex, tickSpacing);\n\n if (tickarrayStartIndex >= maxTickBoundary || tickarrayStartIndex < minTickBoundary) {\n return true;\n }\n }\n\n return false;\n }\n\n static tickArrayStartIndexRange({ tickSpacing }: { tickSpacing: number }) {\n let maxTickBoundary = TickArrayBitmapUtil.maxTickInTickarrayBitmap(tickSpacing);\n let minTickBoundary = -maxTickBoundary;\n\n if (maxTickBoundary > MAX_TICK) {\n maxTickBoundary =\n TickArrayUtil.getTickArrayStartIndex(MAX_TICK, tickSpacing) + TickArrayUtil.tickCount(tickSpacing);\n }\n if (minTickBoundary < MIN_TICK) {\n minTickBoundary = TickArrayUtil.getTickArrayStartIndex(MIN_TICK, tickSpacing);\n }\n return { maxTickBoundary, minTickBoundary };\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: ReturnType<typeof RewardInfoLayout.decode>[];\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 ?? (await connection.getAccountInfo(_itemReward.mint))?.owner;\n if (apiRewardProgram === undefined) throw Error(\"get new reward mint info error\");\n\n const itemReward: ClmmPoolRewardInfo = {\n ..._itemReward,\n perSecond: x64ToDecimal(_itemReward.emissionsPerSecondX64),\n remainingRewards: undefined,\n tokenProgramId: new PublicKey(apiRewardProgram),\n };\n\n if (itemReward.mint.equals(PublicKey.default) || itemReward.totalEmissioned.eq(U64_MAX)) continue;\n if (chainTime <= itemReward.openTime.toNumber() || poolLiquidity.eq(BN_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 if (timeDelta.isZero()) {\n nRewardInfo.push(itemReward);\n continue;\n }\n const rewardDelta = mulDivCeil(timeDelta, itemReward.emissionsPerSecondX64, Q64);\n let rewardGrowthDeltaX64 = mulDivFloor(timeDelta, itemReward.emissionsPerSecondX64, poolLiquidity);\n\n let totalEmissioned;\n const newTotal = itemReward.totalEmissioned.add(rewardDelta);\n if (newTotal.lte(U64_MAX)) {\n totalEmissioned = newTotal;\n } else {\n const remain = U64_MAX.sub(itemReward.totalEmissioned);\n totalEmissioned = U64_MAX;\n rewardGrowthDeltaX64 = mulDivFloor(remain, Q64, poolLiquidity);\n }\n\n const growthGlobalX64 = itemReward.growthGlobalX64.add(rewardGrowthDeltaX64);\n nRewardInfo.push({\n ...itemReward,\n growthGlobalX64,\n totalEmissioned,\n lastUpdateTime: latestUpdateTime,\n });\n }\n return nRewardInfo;\n }\n}\n\nimport { ApiV3PoolInfoConcentratedItem } from \"@/api\";\nimport { RewardInfoLayout } from \"../layout\";\nimport { ComputeClmmPoolInfo } from \"../type\";\nimport { x64ToDecimal } from \"./bigNum\";\n\nimport { TOKEN_2022_PROGRAM_ID } from \"@solana/spl-token\";\nimport { Connection, EpochInfo } from \"@solana/web3.js\";\n\nimport {\n ClmmPoolRewardInfo,\n ReturnTypeComputeAmountOut,\n ReturnTypeComputeAmountOutBaseOut,\n ReturnTypeComputeAmountOutFormat,\n ReturnTypeFetchExBitmaps,\n ReturnTypeFetchMultiplePoolTickArrays,\n ReturnTypeGetLiquidityAmountOut,\n} from \"../type\";\n\nimport { ApiV3Token } from \"@/api/type\";\n\nimport {\n getMultipleAccountsInfo,\n getMultipleAccountsInfoWithCustomFlags,\n getTransferAmountFeeV2,\n minExpirationTime,\n solToWSol,\n} from \"@/common\";\nimport { Percent, Price, Token, TokenAmount } from \"@/module\";\nimport Decimal from \"decimal.js\";\nimport { TickArrayBitmapExtensionLayout, TickArrayLayout } from \"../layout\";\nimport { MAX_SQRT_PRICE_X64, MIN_SQRT_PRICE_X64 } from \"./constants\";\nimport { LiquidityMathUtil } from \"./liquidityMath\";\nimport { getPdaExBitmapAccount, getPdaTickArrayAddress } from \"./pda\";\nimport { swapInternal } from \"./swapSimulator\";\n\nexport class PoolUtils {\n public static getOutputAmountAndRemainAccounts(\n poolInfo: ComputeClmmPoolInfo,\n tickarrayBitmapExtension: ReturnType<typeof TickArrayBitmapExtensionLayout.decode>,\n tickArrayCache: { [key: string]: ReturnType<typeof TickArrayLayout.decode> & { address: PublicKey } },\n inputTokenMint: PublicKey,\n inputAmount: BN,\n blockTimestamp: number,\n sqrtPriceLimitX64?: BN,\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 currentTickArrayStartIndex = TickArrayUtil.getTickArrayStartIndex(\n poolInfo.accInfo.tickCurrent,\n poolInfo.accInfo.tickSpacing,\n );\n const { allTrade, amountCalculated, feeAmount, sqrtPriceX64, accounts } = swapInternal({\n programId: poolInfo.programId,\n poolId: poolInfo.id,\n poolInfo: poolInfo.accInfo,\n tickArrays: Object.entries(tickArrayCache)\n .map((i) => ({\n address: i[1].address,\n value: i[1],\n }))\n .filter((a) =>\n zeroForOne\n ? a.value.startTickIndex <= currentTickArrayStartIndex\n : a.value.startTickIndex >= currentTickArrayStartIndex,\n )\n .sort((a, b) =>\n zeroForOne\n ? b.value.startTickIndex - a.value.startTickIndex\n : a.value.startTickIndex - b.value.startTickIndex,\n ),\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n configInfo: poolInfo.ammConfig,\n tickarrayBitmapExtension,\n amountSpecified: inputAmount,\n sqrtPriceLimitX64: sqrtPriceLimitX64 ?? BN_ZERO,\n zeroForOne,\n isBaseInput: true,\n blockTimestamp,\n includeExtraTickArrays: true,\n });\n\n return {\n allTrade,\n expectedAmountOut: amountCalculated,\n remainingAccounts: accounts,\n executionPrice: sqrtPriceX64,\n feeAmount,\n };\n }\n\n public static getInputAmountAndRemainAccounts(\n poolInfo: ComputeClmmPoolInfo,\n tickarrayBitmapExtension: ReturnType<typeof TickArrayBitmapExtensionLayout.decode>,\n tickArrayCache: { [key: string]: ReturnType<typeof TickArrayLayout.decode> },\n outputTokenMint: PublicKey,\n outputAmount: BN,\n blockTimestamp: number,\n sqrtPriceLimitX64?: BN,\n ): { allTrade: boolean; expectedAmountIn: BN; remainingAccounts: PublicKey[]; executionPrice: BN; feeAmount: BN } {\n const zeroForOne = outputTokenMint.toBase58() === poolInfo.mintB.address;\n\n const currentTickArrayStartIndex = TickArrayUtil.getTickArrayStartIndex(\n poolInfo.accInfo.tickCurrent,\n poolInfo.accInfo.tickSpacing,\n );\n const { allTrade, amountCalculated, feeAmount, sqrtPriceX64, accounts } = swapInternal({\n programId: poolInfo.programId,\n poolId: poolInfo.id,\n poolInfo: poolInfo.accInfo,\n tickArrays: Object.entries(tickArrayCache)\n .map((i) => ({ address: new PublicKey(i[0]), value: i[1] }))\n .filter((a) =>\n zeroForOne\n ? a.value.startTickIndex <= currentTickArrayStartIndex\n : a.value.startTickIndex >= currentTickArrayStartIndex,\n )\n .sort((a, b) =>\n zeroForOne\n ? b.value.startTickIndex - a.value.startTickIndex\n : a.value.startTickIndex - b.value.startTickIndex,\n ),\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n configInfo: poolInfo.ammConfig,\n tickarrayBitmapExtension,\n amountSpecified: outputAmount,\n sqrtPriceLimitX64: sqrtPriceLimitX64 ?? BN_ZERO,\n zeroForOne,\n isBaseInput: false,\n blockTimestamp,\n includeExtraTickArrays: true,\n });\n\n return {\n allTrade,\n expectedAmountIn: amountCalculated,\n remainingAccounts: accounts,\n executionPrice: sqrtPriceX64,\n feeAmount,\n };\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 startIndexArray = [\n ...TickArrayBitmapUtil.findTickArrayStartIndex({\n tickSpacing: itemPoolInfo.tickSpacing,\n poolBitmap: itemPoolInfo.tickArrayBitmap,\n tickArrayBitmap: itemPoolInfo.exBitmapInfo,\n findInfo: { type: \"zeroForOne\", count: 7, tickArrayCurrent: itemPoolInfo.tickCurrent },\n }),\n ...TickArrayBitmapUtil.findTickArrayStartIndex({\n tickSpacing: itemPoolInfo.tickSpacing,\n poolBitmap: itemPoolInfo.tickArrayBitmap,\n tickArrayBitmap: itemPoolInfo.exBitmapInfo,\n findInfo: { type: \"oneForZero\", count: 7, tickArrayCurrent: itemPoolInfo.tickCurrent },\n }),\n ];\n\n for (const itemIndex of startIndexArray) {\n const { publicKey: tickArrayAddress } = getPdaTickArrayAddress(\n itemPoolInfo.programId,\n itemPoolInfo.id,\n itemIndex,\n );\n if (tickArraysToPoolId[tickArrayAddress.toString()] !== undefined) continue;\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 static computeAmou