package uniswap import ( "math/big" "github.com/holiman/uint256" ) const ( // Q96 represents 2^96 used in Uniswap V3 sqrtPriceX96 calculations Q96 = 79228162514264337593543950336 // 2^96 // Tick spacing for different fee tiers LowTickSpacing = 10 MediumTickSpacing = 60 HighTickSpacing = 200 ) // SqrtPriceX96ToPrice converts sqrtPriceX96 to a price // Price is represented as token1/token0 func SqrtPriceX96ToPrice(sqrtPriceX96 *big.Int) *big.Float { // price = (sqrtPriceX96 / 2^96)^2 // price = sqrtPriceX96^2 / 2^192 // Convert to big.Float for precision sqrtPrice := new(big.Float).SetInt(sqrtPriceX96) // Calculate sqrtPrice^2 price := new(big.Float).Mul(sqrtPrice, sqrtPrice) // Divide by 2^192 (which is (2^96)^2) q192 := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(2), big.NewInt(192), nil)) price.Quo(price, q192) return price } // PriceToSqrtPriceX96 converts a price to sqrtPriceX96 func PriceToSqrtPriceX96(price *big.Float) *big.Int { // sqrtPriceX96 = sqrt(price) * 2^96 // Calculate sqrt(price) sqrtPrice := new(big.Float).Sqrt(price) // Multiply by 2^96 q96 := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(2), big.NewInt(96), nil)) sqrtPrice.Mul(sqrtPrice, q96) // Convert to big.Int sqrtPriceX96 := new(big.Int) sqrtPrice.Int(sqrtPriceX96) return sqrtPriceX96 } // TickToSqrtPriceX96 converts a tick to sqrtPriceX96 func TickToSqrtPriceX96(tick int) *big.Int { // sqrtPriceX96 = 1.0001^(tick/2) * 2^96 // Calculate 1.0001^(tick/2) base := new(big.Float).SetFloat64(1.0001) tickF := new(big.Float).SetFloat64(float64(tick) / 2.0) power := new(big.Float).Pow(base, tickF) // Multiply by 2^96 q96 := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(2), big.NewInt(96), nil)) sqrtPrice := new(big.Float).Mul(power, q96) // Convert to big.Int sqrtPriceX96 := new(big.Int) sqrtPrice.Int(sqrtPriceX96) return sqrtPriceX96 } // SqrtPriceX96ToTick converts sqrtPriceX96 to a tick func SqrtPriceX96ToTick(sqrtPriceX96 *big.Int) int { // tick = log_1.0001(sqrtPriceX96 / 2^96)^2 // tick = log_1.0001(price) // tick = 2 * log_1.0001(sqrtPriceX96 / 2^96) if sqrtPriceX96.Cmp(big.NewInt(0)) <= 0 { return 0 // Invalid input } // Convert to big.Float sqrtPrice := new(big.Float).SetInt(sqrtPriceX96) q96 := new(big.Float).SetInt(new(big.Int).SetInt64(Q96)) // Calculate sqrtPriceX96 / 2^96 ratio := new(big.Float).Quo(sqrtPrice, q96) // Calculate (sqrtPriceX96 / 2^96)^2 to get price price := new(big.Float).Mul(ratio, ratio) // Calculate log_1.0001(price) // log_1.0001(x) = ln(x) / ln(1.0001) lnPrice := new(big.Float).Log(price) lnBase := new(big.Float).Log(new(big.Float).SetFloat64(1.0001)) logRatio := new(big.Float).Quo(lnPrice, lnBase) // Convert to int tick, _ := logRatio.Int64() return int(tick) } // GetTickAtSqrtPrice calculates the tick for a given sqrtPriceX96 using uint256 func GetTickAtSqrtPrice(sqrtPriceX96 *uint256.Int) int { // This is a simplified implementation // In practice, you would use a more precise logarithmic calculation // Convert to big.Int for calculation sqrtPriceBig := sqrtPriceX96.ToBig() return SqrtPriceX96ToTick(sqrtPriceBig) } // GetNextTick calculates the next initialized tick func GetNextTick(currentTick int, tickSpacing int) int { // Round down to nearest tick spacing tick := ((currentTick / tickSpacing) + 1) * tickSpacing return tick } // GetPreviousTick calculates the previous initialized tick func GetPreviousTick(currentTick int, tickSpacing int) int { // Round down to nearest tick spacing tick := (currentTick / tickSpacing) * tickSpacing return tick }