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 {
13 Err(UniswapV3MathError::LiquiditySub)
14 } else {
15 Ok(z.0)
16 }
17 } else {
18 let z = x.overflowing_add(y as u128);
19 if z.0 < x {
20 Err(UniswapV3MathError::LiquidityAdd)
21 } else {
22 Ok(z.0)
23 }
24 }
25}
26
27pub fn get_liquidity_for_amount0(sqrt_ratio_a_x_96: U256, sqrt_ratio_b_x_96: U256, amount0: U256) -> eyre::Result<u128> {
28 let (sqrt_ratio_a_x_96, sqrt_ratio_b_x_96) =
29 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) };
30
31 let intermediate = mul_div(sqrt_ratio_a_x_96, sqrt_ratio_b_x_96, Q96)?;
33 let ret = mul_div(amount0, intermediate, sqrt_ratio_b_x_96 - sqrt_ratio_a_x_96)?;
34 if ret > U256::from(U128::MAX) {
35 Err(eyre!("LIQUIDITY_OVERFLOWN"))
36 } else {
37 Ok(ret.to())
38 }
39}
40
41pub fn get_liquidity_for_amount1(sqrt_ratio_a_x_96: U256, sqrt_ratio_b_x_96: U256, amount1: U256) -> eyre::Result<u128> {
42 let (sqrt_ratio_a_x_96, sqrt_ratio_b_x_96) =
43 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) };
44 let ret = mul_div(amount1, Q96, sqrt_ratio_b_x_96 - sqrt_ratio_a_x_96)?;
45 if ret > U256::from(U128::MAX) {
46 Err(eyre!("LIQUIDITY_OVERFLOWN"))
47 } else {
48 Ok(ret.to())
49 }
50}
51
52pub fn get_liquidity_for_amounts(
53 sqrt_ratio_x_96: U256,
54 sqrt_ratio_a_x_96: U256,
55 sqrt_ratio_b_x_96: U256,
56 amount0: U256,
57 amount1: U256,
58) -> eyre::Result<u128> {
59 let (sqrt_ratio_a_x_96, sqrt_ratio_b_x_96) =
60 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) };
61 let liquidity = if sqrt_ratio_x_96 <= sqrt_ratio_a_x_96 {
62 get_liquidity_for_amount0(sqrt_ratio_a_x_96, sqrt_ratio_b_x_96, amount0)?
63 } else if sqrt_ratio_x_96 < sqrt_ratio_b_x_96 {
64 let liquidity0 = get_liquidity_for_amount0(sqrt_ratio_x_96, sqrt_ratio_b_x_96, amount0)?;
65 let liquidity1 = get_liquidity_for_amount1(sqrt_ratio_a_x_96, sqrt_ratio_x_96, amount1)?;
66 if liquidity0 < liquidity1 {
67 liquidity0
68 } else {
69 liquidity1
70 }
71 } else {
72 get_liquidity_for_amount1(sqrt_ratio_a_x_96, sqrt_ratio_b_x_96, amount1)?
73 };
74 Ok(liquidity)
75}
76
77#[cfg(test)]
78mod test {
79
80 use crate::liquidity_math::add_delta;
81
82 #[test]
83 fn test_add_delta() {
84 let result = add_delta(1, 0);
86 assert_eq!(result.unwrap(), 1);
87
88 let result = add_delta(1, -1);
90 assert_eq!(result.unwrap(), 0);
91
92 let result = add_delta(1, 1);
94 assert_eq!(result.unwrap(), 2);
95
96 let result = add_delta(340282366920938463463374607431768211441, 15);
98 assert_eq!(result.err().unwrap().to_string(), "Liquidity Add");
99
100 let result = add_delta(0, -1);
102 assert_eq!(result.err().unwrap().to_string(), "Liquidity Sub");
103
104 let result = add_delta(3, -4);
106 assert_eq!(result.err().unwrap().to_string(), "Liquidity Sub");
107 }
108}