use crate::defi::{pool_analysis::error::LiquidityMathError, tick_map::tick::PoolTick};
pub fn try_liquidity_math_add(x: u128, y: i128) -> Result<u128, LiquidityMathError> {
if y < 0 {
let delta = y.unsigned_abs();
let z = x.wrapping_sub(delta);
if z >= x {
return Err(LiquidityMathError::Underflow { current: x, delta });
}
Ok(z)
} else {
let delta = y as u128;
let z = x.wrapping_add(delta);
if z < x {
return Err(LiquidityMathError::Overflow { current: x, delta });
}
Ok(z)
}
}
#[must_use]
pub fn liquidity_math_add(x: u128, y: i128) -> u128 {
match try_liquidity_math_add(x, y) {
Ok(value) => value,
Err(LiquidityMathError::Overflow { current, delta }) => {
panic!("Liquidity addition overflow: x={current}, y={y}, delta={delta}")
}
Err(LiquidityMathError::Underflow { current, delta }) => {
panic!("Liquidity subtraction underflow: x={current}, y={y}, delta={delta}")
}
}
}
#[must_use]
pub fn tick_spacing_to_max_liquidity_per_tick(tick_spacing: i32) -> u128 {
assert!(tick_spacing != 0, "Tick spacing must be non-zero");
let min_tick = (PoolTick::MIN_TICK / tick_spacing) * tick_spacing;
let max_tick = (PoolTick::MAX_TICK / tick_spacing) * tick_spacing;
let num_ticks = ((i64::from(max_tick) - i64::from(min_tick)) / i64::from(tick_spacing)) + 1;
u128::MAX / num_ticks as u128
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::*;
#[rstest]
fn test_add() {
assert_eq!(liquidity_math_add(1, 0), 1);
assert_eq!(liquidity_math_add(1, 1), 2);
}
#[rstest]
fn test_subtract_one() {
assert_eq!(liquidity_math_add(1, -1), 0);
assert_eq!(liquidity_math_add(3, -2), 1);
}
#[rstest]
#[should_panic(expected = "Liquidity addition overflow")]
fn test_addition_overflow() {
let x = u128::MAX - 14; let _ = liquidity_math_add(x, 15);
}
#[rstest]
#[should_panic(expected = "Liquidity subtraction underflow")]
fn test_subtraction_underflow_zero() {
let _ = liquidity_math_add(0, -1);
}
#[rstest]
#[should_panic(expected = "Liquidity subtraction underflow")]
fn test_subtraction_underflow() {
let _ = liquidity_math_add(3, -4);
}
#[rstest]
fn test_try_add_returns_overflow_error() {
let x = u128::MAX - 14;
let err = try_liquidity_math_add(x, 15).unwrap_err();
assert_eq!(
err,
LiquidityMathError::Overflow {
current: x,
delta: 15
}
);
}
#[rstest]
fn test_try_add_returns_underflow_error() {
let err = try_liquidity_math_add(3, -4).unwrap_err();
assert_eq!(
err,
LiquidityMathError::Underflow {
current: 3,
delta: 4
}
);
}
#[rstest]
fn test_tick_spacing_to_max_liquidity() {
assert_eq!(
tick_spacing_to_max_liquidity_per_tick(1),
191_757_530_477_355_301_479_181_766_273_477
);
assert_eq!(
tick_spacing_to_max_liquidity_per_tick(10),
1_917_569_901_783_203_986_719_870_431_555_990
);
assert_eq!(
tick_spacing_to_max_liquidity_per_tick(60),
11_505_743_598_341_114_571_880_798_222_544_994
);
assert_eq!(
tick_spacing_to_max_liquidity_per_tick(200),
38_350_317_471_085_141_830_651_933_667_504_588
);
}
}