// Package uniswap provides mathematical functions for Uniswap V3 calculations. package uniswap import ( "math" "math/big" ) // SqrtPriceX96ToPriceAdvanced converts sqrtPriceX96 to a price using advanced caching. func SqrtPriceX96ToPriceAdvanced(sqrtPriceX96 *big.Int) *big.Float { // Initialize global cached constants initConstants() // price = (sqrtPriceX96 / 2^96)^2 // price = sqrtPriceX96^2 / 2^192 // Validate input if sqrtPriceX96 == nil || sqrtPriceX96.Sign() <= 0 { return new(big.Float).SetFloat64(0.0) } // 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 using cached constant price.Quo(price, GetQ192Float()) // Validate result is reasonable (not extremely high or low) priceFloat, _ := price.Float64() if math.IsNaN(priceFloat) || math.IsInf(priceFloat, 0) || priceFloat > 1e20 || priceFloat < 1e-20 { // Extremely high/low prices are likely errors return new(big.Float).SetFloat64(1.0) // Default to 1.0 as safe fallback } return price } // PriceToSqrtPriceX96Advanced converts a price to sqrtPriceX96 using advanced caching. func PriceToSqrtPriceX96Advanced(price *big.Float) *big.Int { // Initialize global cached constants initConstants() // sqrtPriceX96 = sqrt(price) * 2^96 // Calculate sqrt(price) sqrtPrice := new(big.Float).Sqrt(price) // Multiply by 2^96 using cached constant sqrtPrice.Mul(sqrtPrice, GetQ96Float()) // Validate result resultFloat, _ := sqrtPrice.Float64() if math.IsNaN(resultFloat) || math.IsInf(resultFloat, 0) { return new(big.Int).SetUint64(0) // Return 0 for invalid results } // Convert to big.Int sqrtPriceX96 := new(big.Int) sqrtPrice.Int(sqrtPriceX96) return sqrtPriceX96 } // TickToSqrtPriceX96Advanced converts a tick to sqrtPriceX96 using advanced caching. func TickToSqrtPriceX96Advanced(tick int) *big.Int { // Initialize global cached constants initConstants() // sqrtPriceX96 = 1.0001^(tick/2) * 2^96 // Using logarithms: 1.0001^(tick/2) = e^(ln(1.0001) * tick/2) logResult := GetLnBase() * float64(tick) / 2.0 result := math.Exp(logResult) // Convert to big.Float price := new(big.Float).SetFloat64(result) // Multiply by 2^96 using cached constant price.Mul(price, GetQ96Float()) // Validate result resultFloat, _ := price.Float64() if math.IsNaN(resultFloat) || math.IsInf(resultFloat, 0) { return new(big.Int).SetUint64(0) // Return 0 for invalid results } // Convert to big.Int sqrtPriceX96 := new(big.Int) price.Int(sqrtPriceX96) return sqrtPriceX96 } // SqrtPriceX96ToTickAdvanced converts sqrtPriceX96 to a tick using advanced caching. func SqrtPriceX96ToTickAdvanced(sqrtPriceX96 *big.Int) int { // Initialize global cached constants initConstants() // tick = log_1.0001(sqrtPriceX96 / 2^96)^2 // tick = 2 * ln(sqrtPriceX96 / 2^96) / ln(1.0001) if sqrtPriceX96.Cmp(big.NewInt(0)) <= 0 { return 0 // Invalid input } // Convert to big.Float sqrtPrice := new(big.Float).SetInt(sqrtPriceX96) q96Float := GetQ96Float() // Calculate ln(sqrtPriceX96 / 2^96) to avoid potential overflow ratio := new(big.Float).Quo(sqrtPrice, q96Float) lnRatio, _ := ratio.Float64() if lnRatio <= 0 { return 0 // Invalid ratio } lnValue := math.Log(lnRatio) // Calculate tick: tick = 2 * lnValue / ln(1.0001) tick := int(2.0 * lnValue * GetInvLnBase()) return tick }