// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.19; import { ABDKMath64x64 } from "@abdk/ABDKMath64x64.sol"; import "@aperture/uni-v3-lib/TickMath.sol"; import { Math } from "@openzeppelin/utils/math/Math.sol"; /** * @title UniswapMath * @notice Abstract contract providing mathematical utilities for Uniswap V3 price and tick calculations * @dev Contains pure mathematical functions for price/tick conversions and validations */ abstract contract UniswapMath { using Math for uint256; /// @notice Calculates the Uniswap V3 tick corresponding to a given price ratio between Kraiken and ETH /// @param t0isWeth Boolean flag indicating if token0 is WETH /// @param tokenAmount Amount of the Kraiken token /// @param ethAmount Amount of Ethereum /// @return tick_ The calculated tick for the given price ratio function _tickAtPrice(bool t0isWeth, uint256 tokenAmount, uint256 ethAmount) internal pure returns (int24 tick_) { require(ethAmount > 0, "ETH amount cannot be zero"); if (tokenAmount == 0) { // KRAIKEN/ETH tick_ = TickMath.MAX_TICK; } else { // Use ABDKMath64x64 for precise division and square root calculation int128 priceRatioX64 = ABDKMath64x64.div(int128(int256(tokenAmount)), int128(int256(ethAmount))); // KRAIKEN/ETH tick_ = _tickAtPriceRatio(priceRatioX64); } // convert to tick in a pool tick_ = t0isWeth ? tick_ : -tick_; } /// @notice Converts a price ratio to a Uniswap V3 tick /// @param priceRatioX64 The price ratio in ABDKMath64x64 format /// @return tick_ The corresponding tick function _tickAtPriceRatio(int128 priceRatioX64) internal pure returns (int24 tick_) { // Convert the price ratio into a sqrt price in the format expected by Uniswap's TickMath uint160 sqrtPriceX96 = uint160(int160(ABDKMath64x64.sqrt(priceRatioX64) << 32)); tick_ = TickMath.getTickAtSqrtRatio(sqrtPriceX96); } /// @notice Calculates the price ratio from a given Uniswap V3 tick /// @dev Returns price (token1/token0) in Q96 format: price * 2^96 /// Computed as sqrtRatioX96² / 2^96 = (sqrt(price) * 2^96)² / 2^96 = price * 2^96 /// @param tick The tick for which to calculate the price ratio /// @return priceRatioX96 The price ratio in Q96 format function _priceAtTick(int24 tick) internal pure returns (uint256 priceRatioX96) { uint256 sqrtRatioX96 = TickMath.getSqrtRatioAtTick(tick); priceRatioX96 = sqrtRatioX96.mulDiv(sqrtRatioX96, (1 << 96)); } /// @notice Clamps tick to valid range and aligns to tick spacing /// @param tick The tick to clamp /// @param tickSpacing The tick spacing to align to /// @return clampedTick The clamped and aligned tick function _clampToTickSpacing(int24 tick, int24 tickSpacing) internal pure returns (int24 clampedTick) { // Align to tick spacing first clampedTick = tick / tickSpacing * tickSpacing; // Ensure tick is within valid bounds if (clampedTick < TickMath.MIN_TICK) clampedTick = TickMath.MIN_TICK; if (clampedTick > TickMath.MAX_TICK) clampedTick = TickMath.MAX_TICK; } }