use alloy::primitives::{aliases::U160, uint, U256};
use anyhow::Result;
use uniswap_sdk_core::{
entities::FractionBase,
prelude::{BigInt, BigUint, Currency, Fraction, Percent, Price, ToBig},
utils::FromBig,
};
use waterpump_evm_amm_math::{
encode_sqrt_ratio::encode_sqrt_ratio_x96 as encode_sqrt_ratio_x96_u256,
tick_math::{MAX_SQRT_RATIO, MIN_SQRT_RATIO},
};
const ONE: U160 = uint!(1_U160);
const Q192_BIG_INT: BigInt = BigInt::from_bits(BigUint::from_digits([0, 0, 0, 1, 0, 0, 0, 0]));
fn encode_sqrt_ratio_x96(numerator: BigInt, denominator: BigInt) -> U160 {
let num_u256 = U256::from_big_int(numerator);
let den_u256 = U256::from_big_int(denominator);
let result =
encode_sqrt_ratio_x96_u256(num_u256, den_u256).expect("encode_sqrt_ratio_x96 failed");
U160::from(result)
}
pub fn ratios_after_slippage(
token0_price: &Price<Currency, Currency>,
slippage_tolerance: &Percent,
) -> Result<(U160, U160)> {
let one = Percent::new(1, 1);
let token0_price_fraction = token0_price.as_fraction();
let price_lower = (one.clone() - slippage_tolerance).as_fraction() * &token0_price_fraction;
let price_upper = token0_price_fraction * ((one + slippage_tolerance).as_fraction());
let min_sqrt_ratio_u160 = U160::from(MIN_SQRT_RATIO);
let max_sqrt_ratio_u160 = U160::from(MAX_SQRT_RATIO);
let mut sqrt_ratio_x96_lower =
encode_sqrt_ratio_x96(price_lower.numerator, price_lower.denominator);
if sqrt_ratio_x96_lower <= min_sqrt_ratio_u160 {
sqrt_ratio_x96_lower = min_sqrt_ratio_u160 + ONE;
}
let sqrt_ratio_x96_upper = {
let max_sqrt_ratio_big = max_sqrt_ratio_u160.to_big_int();
if price_upper >= Fraction::new(max_sqrt_ratio_big.pow(2), Q192_BIG_INT) {
max_sqrt_ratio_u160 - ONE
} else {
encode_sqrt_ratio_x96(price_upper.numerator, price_upper.denominator)
}
};
Ok((sqrt_ratio_x96_lower, sqrt_ratio_x96_upper))
}