kabu_defi_uniswap_v3_math/
liquidity_math.rs1use crate::error::UniswapV3MathError;
2use crate::full_math::mul_div;
3use crate::sqrt_price_math::Q96;
4use alloy::primitives::{U128, U256};
5use eyre::eyre;
6
7pub fn add_delta(x: u128, y: i128) -> Result<u128, UniswapV3MathError> {
9 if y < 0 {
10 let z = x.overflowing_sub(-y as u128);
11
12 if z.1 { Err(UniswapV3MathError::LiquiditySub) } else { Ok(z.0) }
13 } else {
14 let z = x.overflowing_add(y as u128);
15 if z.0 < x { Err(UniswapV3MathError::LiquidityAdd) } else { Ok(z.0) }
16 }
17}
18
19pub fn get_liquidity_for_amount0(sqrt_ratio_a_x_96: U256, sqrt_ratio_b_x_96: U256, amount0: U256) -> eyre::Result<u128> {
20 let (sqrt_ratio_a_x_96, sqrt_ratio_b_x_96) =
21 if sqrt_ratio_a_x_96 > sqrt_ratio_b_x_96 { (sqrt_ratio_b_x_96, sqrt_ratio_a_x_96) } else { (sqrt_ratio_a_x_96, sqrt_ratio_b_x_96) };
22
23 let intermediate = mul_div(sqrt_ratio_a_x_96, sqrt_ratio_b_x_96, Q96)?;
25 let ret = mul_div(amount0, intermediate, sqrt_ratio_b_x_96 - sqrt_ratio_a_x_96)?;
26 if ret > U256::from(U128::MAX) { Err(eyre!("LIQUIDITY_OVERFLOWN")) } else { Ok(ret.to()) }
27}
28
29pub fn get_liquidity_for_amount1(sqrt_ratio_a_x_96: U256, sqrt_ratio_b_x_96: U256, amount1: U256) -> eyre::Result<u128> {
30 let (sqrt_ratio_a_x_96, sqrt_ratio_b_x_96) =
31 if sqrt_ratio_a_x_96 > sqrt_ratio_b_x_96 { (sqrt_ratio_b_x_96, sqrt_ratio_a_x_96) } else { (sqrt_ratio_a_x_96, sqrt_ratio_b_x_96) };
32 let ret = mul_div(amount1, Q96, sqrt_ratio_b_x_96 - sqrt_ratio_a_x_96)?;
33 if ret > U256::from(U128::MAX) { Err(eyre!("LIQUIDITY_OVERFLOWN")) } else { Ok(ret.to()) }
34}
35
36pub fn get_liquidity_for_amounts(
37 sqrt_ratio_x_96: U256,
38 sqrt_ratio_a_x_96: U256,
39 sqrt_ratio_b_x_96: U256,
40 amount0: U256,
41 amount1: U256,
42) -> eyre::Result<u128> {
43 let (sqrt_ratio_a_x_96, sqrt_ratio_b_x_96) =
44 if sqrt_ratio_a_x_96 > sqrt_ratio_b_x_96 { (sqrt_ratio_b_x_96, sqrt_ratio_a_x_96) } else { (sqrt_ratio_a_x_96, sqrt_ratio_b_x_96) };
45 let liquidity = if sqrt_ratio_x_96 <= sqrt_ratio_a_x_96 {
46 get_liquidity_for_amount0(sqrt_ratio_a_x_96, sqrt_ratio_b_x_96, amount0)?
47 } else if sqrt_ratio_x_96 < sqrt_ratio_b_x_96 {
48 let liquidity0 = get_liquidity_for_amount0(sqrt_ratio_x_96, sqrt_ratio_b_x_96, amount0)?;
49 let liquidity1 = get_liquidity_for_amount1(sqrt_ratio_a_x_96, sqrt_ratio_x_96, amount1)?;
50 if liquidity0 < liquidity1 { liquidity0 } else { liquidity1 }
51 } else {
52 get_liquidity_for_amount1(sqrt_ratio_a_x_96, sqrt_ratio_b_x_96, amount1)?
53 };
54 Ok(liquidity)
55}
56
57#[cfg(test)]
58mod test {
59
60 use crate::liquidity_math::add_delta;
61
62 #[test]
63 fn test_add_delta() {
64 let result = add_delta(1, 0);
66 assert_eq!(result.unwrap(), 1);
67
68 let result = add_delta(1, -1);
70 assert_eq!(result.unwrap(), 0);
71
72 let result = add_delta(1, 1);
74 assert_eq!(result.unwrap(), 2);
75
76 let result = add_delta(340282366920938463463374607431768211441, 15);
78 assert_eq!(result.err().unwrap().to_string(), "Liquidity Add");
79
80 let result = add_delta(0, -1);
82 assert_eq!(result.err().unwrap().to_string(), "Liquidity Sub");
83
84 let result = add_delta(3, -4);
86 assert_eq!(result.err().unwrap().to_string(), "Liquidity Sub");
87 }
88}