1use alloy::primitives::{I256, U256};
2
3use crate::{
4 error::UniswapV3MathError,
5 full_math::{mul_div, mul_div_rounding_up},
6 unsafe_math::div_rounding_up,
7};
8
9pub const MAX_U160: U256 = U256::from_limbs([18446744073709551615, 18446744073709551615, 4294967295, 0]);
10pub const Q96: U256 = U256::from_limbs([0, 4294967296, 0, 0]);
11pub const FIXED_POINT_96_RESOLUTION: U256 = U256::from_limbs([96, 0, 0, 0]);
12
13pub fn get_next_sqrt_price_from_input(
15 sqrt_price: U256,
16 liquidity: u128,
17 amount_in: U256,
18 zero_for_one: bool,
19) -> Result<U256, UniswapV3MathError> {
20 if sqrt_price.is_zero() {
21 return Err(UniswapV3MathError::SqrtPriceIsZero);
22 } else if liquidity == 0 {
23 return Err(UniswapV3MathError::LiquidityIsZero);
24 }
25
26 if zero_for_one {
27 get_next_sqrt_price_from_amount_0_rounding_up(sqrt_price, liquidity, amount_in, true)
28 } else {
29 get_next_sqrt_price_from_amount_1_rounding_down(sqrt_price, liquidity, amount_in, true)
30 }
31}
32
33pub fn get_next_sqrt_price_from_output(
35 sqrt_price: U256,
36 liquidity: u128,
37 amount_out: U256,
38 zero_for_one: bool,
39) -> Result<U256, UniswapV3MathError> {
40 if sqrt_price.is_zero() {
41 return Err(UniswapV3MathError::SqrtPriceIsZero);
42 } else if liquidity == 0 {
43 return Err(UniswapV3MathError::LiquidityIsZero);
44 }
45
46 if zero_for_one {
47 get_next_sqrt_price_from_amount_1_rounding_down(sqrt_price, liquidity, amount_out, false)
48 } else {
49 get_next_sqrt_price_from_amount_0_rounding_up(sqrt_price, liquidity, amount_out, false)
50 }
51}
52
53pub fn get_next_sqrt_price_from_amount_0_rounding_up(
55 sqrt_price_x_96: U256,
56 liquidity: u128,
57 amount: U256,
58 add: bool,
59) -> Result<U256, UniswapV3MathError> {
60 if amount.is_zero() {
61 return Ok(sqrt_price_x_96);
62 }
63
64 let numerator_1: U256 = U256::from(liquidity) << 96;
65
66 if add {
67 let product = amount.wrapping_mul(sqrt_price_x_96);
68
69 if product.wrapping_div(amount) == sqrt_price_x_96 {
70 let denominator = numerator_1.wrapping_add(product);
71
72 if denominator >= numerator_1 {
73 return mul_div_rounding_up(numerator_1, sqrt_price_x_96, denominator);
74 }
75 }
76
77 Ok(div_rounding_up(numerator_1, (numerator_1.wrapping_div(sqrt_price_x_96)).wrapping_add(amount)))
78 } else {
79 let product = amount.wrapping_mul(sqrt_price_x_96);
80 if product.wrapping_div(amount) == sqrt_price_x_96 && numerator_1 > product {
81 let denominator = numerator_1.wrapping_sub(product);
82
83 mul_div_rounding_up(numerator_1, sqrt_price_x_96, denominator)
84 } else {
85 Err(UniswapV3MathError::ProductDivAmount)
86 }
87 }
88}
89
90pub fn get_next_sqrt_price_from_amount_1_rounding_down(
92 sqrt_price_x_96: U256,
93 liquidity: u128,
94 amount: U256,
95 add: bool,
96) -> Result<U256, UniswapV3MathError> {
97 let liquidity = U256::from(liquidity);
98
99 if add {
100 let quotient =
101 if amount <= MAX_U160 { (amount << FIXED_POINT_96_RESOLUTION) / liquidity } else { mul_div(amount, Q96, liquidity)? };
102
103 let next_sqrt_price = sqrt_price_x_96 + quotient;
104
105 if next_sqrt_price > MAX_U160 { Err(UniswapV3MathError::SafeCastToU160Overflow) } else { Ok(next_sqrt_price) }
106 } else {
107 let quotient = if amount <= MAX_U160 {
108 div_rounding_up(amount << FIXED_POINT_96_RESOLUTION, liquidity)
109 } else {
110 mul_div_rounding_up(amount, Q96, liquidity)?
111 };
112
113 if sqrt_price_x_96 <= quotient {
115 return Err(UniswapV3MathError::SqrtPriceIsLteQuotient);
116 }
117
118 Ok(sqrt_price_x_96.overflowing_sub(quotient).0)
119 }
120}
121
122pub fn _get_amount_0_delta(
124 mut sqrt_ratio_a_x_96: U256,
125 mut sqrt_ratio_b_x_96: U256,
126 liquidity: u128,
127 round_up: bool,
128) -> Result<U256, UniswapV3MathError> {
129 if sqrt_ratio_a_x_96 > sqrt_ratio_b_x_96 {
130 (sqrt_ratio_a_x_96, sqrt_ratio_b_x_96) = (sqrt_ratio_b_x_96, sqrt_ratio_a_x_96)
131 };
132
133 let numerator_1 = U256::from(liquidity) << 96;
134 let numerator_2 = sqrt_ratio_b_x_96 - sqrt_ratio_a_x_96;
135
136 if sqrt_ratio_a_x_96.is_zero() {
137 return Err(UniswapV3MathError::SqrtPriceIsZero);
138 }
139
140 if round_up {
141 let numerator_partial = mul_div_rounding_up(numerator_1, numerator_2, sqrt_ratio_b_x_96)?;
142 Ok(div_rounding_up(numerator_partial, sqrt_ratio_a_x_96))
143 } else {
144 Ok(mul_div(numerator_1, numerator_2, sqrt_ratio_b_x_96)? / sqrt_ratio_a_x_96)
145 }
146}
147
148pub fn _get_amount_1_delta(
150 mut sqrt_ratio_a_x_96: U256,
151 mut sqrt_ratio_b_x_96: U256,
152 liquidity: u128,
153 round_up: bool,
154) -> Result<U256, UniswapV3MathError> {
155 if sqrt_ratio_a_x_96 > sqrt_ratio_b_x_96 {
156 (sqrt_ratio_a_x_96, sqrt_ratio_b_x_96) = (sqrt_ratio_b_x_96, sqrt_ratio_a_x_96)
157 };
158
159 let denominator = U256::from_limbs([0, 4294967296, 0, 0]);
160
161 if round_up {
162 mul_div_rounding_up(U256::from(liquidity), sqrt_ratio_b_x_96 - sqrt_ratio_a_x_96, denominator)
163 } else {
164 mul_div(U256::from(liquidity), sqrt_ratio_b_x_96 - sqrt_ratio_a_x_96, denominator)
165 }
166}
167
168pub fn get_amount_0_delta(sqrt_ratio_a_x_96: U256, sqrt_ratio_b_x_96: U256, liquidity: i128) -> Result<I256, UniswapV3MathError> {
169 if liquidity < 0 {
170 Ok(-I256::from_raw(_get_amount_0_delta(sqrt_ratio_a_x_96, sqrt_ratio_b_x_96, -liquidity as u128, false)?))
171 } else {
172 Ok(I256::from_raw(_get_amount_0_delta(sqrt_ratio_a_x_96, sqrt_ratio_b_x_96, liquidity as u128, true)?))
173 }
174}
175
176pub fn get_amount_1_delta(sqrt_ratio_a_x_96: U256, sqrt_ratio_b_x_96: U256, liquidity: i128) -> Result<I256, UniswapV3MathError> {
177 if liquidity < 0 {
178 Ok(-I256::from_raw(_get_amount_1_delta(sqrt_ratio_a_x_96, sqrt_ratio_b_x_96, -liquidity as u128, false)?))
179 } else {
180 Ok(I256::from_raw(_get_amount_1_delta(sqrt_ratio_a_x_96, sqrt_ratio_b_x_96, liquidity as u128, true)?))
181 }
182}
183
184#[cfg(test)]
185mod test {
186 use std::{
187 ops::{Add, Sub},
188 str::FromStr,
189 };
190
191 use alloy::primitives::U256;
192
193 use crate::{
194 U256_1, U256_2,
195 sqrt_price_math::{_get_amount_1_delta, MAX_U160, get_next_sqrt_price_from_output},
196 };
197
198 use super::{_get_amount_0_delta, get_next_sqrt_price_from_input};
199
200 #[test]
201 fn test_get_next_sqrt_price_from_input() {
202 let result = get_next_sqrt_price_from_input(U256::ZERO, 0, U256::from(100000000000000000_u128), false);
204 assert_eq!(result.unwrap_err().to_string(), "Sqrt price is 0");
205
206 let result = get_next_sqrt_price_from_input(U256_1, 0, U256::from(100000000000000000_u128), true);
208 assert_eq!(result.unwrap_err().to_string(), "Liquidity is 0");
209
210 let result = get_next_sqrt_price_from_input(MAX_U160, 1024, U256::from(1024), false);
212 assert_eq!(result.unwrap_err().to_string(), "Overflow when casting to U160");
213
214 let result = get_next_sqrt_price_from_input(
216 U256_1,
217 1,
218 U256::from_str("57896044618658097711785492504343953926634992332820282019728792003956564819968").unwrap(),
219 true,
220 );
221
222 assert_eq!(result.unwrap(), U256_1);
223
224 let result =
226 get_next_sqrt_price_from_input(U256::from_str("79228162514264337593543950336").unwrap(), 1e17 as u128, U256::ZERO, true);
227
228 assert_eq!(result.unwrap(), U256::from_str("79228162514264337593543950336").unwrap());
229
230 let result =
232 get_next_sqrt_price_from_input(U256::from_str("79228162514264337593543950336").unwrap(), 1e17 as u128, U256::ZERO, true);
233
234 assert_eq!(result.unwrap(), U256::from_str("79228162514264337593543950336").unwrap());
235
236 let sqrt_price = MAX_U160;
239 let liquidity = u128::MAX;
240 let max_amount_no_overflow = U256::MAX - ((U256::from(liquidity) << 96) / sqrt_price);
241 let result = get_next_sqrt_price_from_input(sqrt_price, liquidity, max_amount_no_overflow, true);
242 assert_eq!(result.unwrap(), U256_1);
243
244 let result = get_next_sqrt_price_from_input(
246 U256::from_str("79228162514264337593543950336").unwrap(),
247 1e18 as u128,
248 U256::from_str("100000000000000000").unwrap(),
249 false,
250 );
251
252 assert_eq!(result.unwrap(), U256::from_str("87150978765690771352898345369").unwrap());
253
254 let result = get_next_sqrt_price_from_input(
256 U256::from_str("79228162514264337593543950336").unwrap(),
257 1e18 as u128,
258 U256::from_str("100000000000000000").unwrap(),
259 true,
260 );
261
262 assert_eq!(result.unwrap(), U256::from_str("72025602285694852357767227579").unwrap());
263
264 let result = get_next_sqrt_price_from_input(
266 U256::from_str("79228162514264337593543950336").unwrap(),
267 1e19 as u128,
268 U256::from_str("1267650600228229401496703205376").unwrap(),
269 true,
270 );
271 assert_eq!(result.unwrap(), U256::from_str("624999999995069620").unwrap());
274
275 let result = get_next_sqrt_price_from_input(U256::from_str("79228162514264337593543950336").unwrap(), 1, U256::MAX / U256_2, true);
277
278 assert_eq!(result.unwrap(), U256_1);
279 }
280
281 #[test]
282 fn test_get_next_sqrt_price_from_output() {
283 let result = get_next_sqrt_price_from_output(U256::ZERO, 0, U256::from(1000000000), false);
285 assert_eq!(result.unwrap_err().to_string(), "Sqrt price is 0");
286
287 let result = get_next_sqrt_price_from_output(U256_1, 0, U256::from(1000000000), false);
289 assert_eq!(result.unwrap_err().to_string(), "Liquidity is 0");
290
291 let result =
293 get_next_sqrt_price_from_output(U256::from_str("20282409603651670423947251286016").unwrap(), 1024, U256::from(4), false);
294 assert_eq!(result.unwrap_err().to_string(), "require((product = amount * sqrtPX96) / amount == sqrtPX96 && numerator1 > product);");
295
296 let result =
298 get_next_sqrt_price_from_output(U256::from_str("20282409603651670423947251286016").unwrap(), 1024, U256::from(5), false);
299 assert_eq!(result.unwrap_err().to_string(), "require((product = amount * sqrtPX96) / amount == sqrtPX96 && numerator1 > product);");
300
301 let result =
303 get_next_sqrt_price_from_output(U256::from_str("20282409603651670423947251286016").unwrap(), 1024, U256::from(262145), true);
304 assert_eq!(result.unwrap_err().to_string(), "Sqrt price is less than or equal to quotient");
305
306 let result =
308 get_next_sqrt_price_from_output(U256::from_str("20282409603651670423947251286016").unwrap(), 1024, U256::from(262144), true);
309 assert_eq!(result.unwrap_err().to_string(), "Sqrt price is less than or equal to quotient");
310
311 let result =
313 get_next_sqrt_price_from_output(U256::from_str("20282409603651670423947251286016").unwrap(), 1024, U256::from(262143), true);
314 assert_eq!(result.unwrap(), U256::from_str("77371252455336267181195264").unwrap());
315
316 let result =
318 get_next_sqrt_price_from_output(U256::from_str("20282409603651670423947251286016").unwrap(), 1024, U256::from(4), false);
319 assert_eq!(result.unwrap_err().to_string(), "require((product = amount * sqrtPX96) / amount == sqrtPX96 && numerator1 > product);");
320
321 let result =
323 get_next_sqrt_price_from_output(U256::from_str("79228162514264337593543950336").unwrap(), 1e17 as u128, U256::ZERO, true);
324 assert_eq!(result.unwrap(), U256::from_str("79228162514264337593543950336").unwrap());
325
326 let result =
328 get_next_sqrt_price_from_output(U256::from_str("79228162514264337593543950336").unwrap(), 1e17 as u128, U256::ZERO, false);
329 assert_eq!(result.unwrap(), U256::from_str("79228162514264337593543950336").unwrap());
330
331 let result = get_next_sqrt_price_from_output(
333 U256::from_str("79228162514264337593543950336").unwrap(),
334 1e18 as u128,
335 U256::from(1e17 as u128),
336 false,
337 );
338 assert_eq!(result.unwrap(), U256::from_str("88031291682515930659493278152").unwrap());
339
340 let result = get_next_sqrt_price_from_output(
342 U256::from_str("79228162514264337593543950336").unwrap(),
343 1e18 as u128,
344 U256::from(1e17 as u128),
345 true,
346 );
347 assert_eq!(result.unwrap(), U256::from_str("71305346262837903834189555302").unwrap());
348
349 let result = get_next_sqrt_price_from_output(U256::from_str("79228162514264337593543950336").unwrap(), 1, U256::MAX, true);
351 assert_eq!(result.unwrap_err().to_string(), "Denominator is less than or equal to prod_1");
352
353 let result = get_next_sqrt_price_from_output(U256::from_str("79228162514264337593543950336").unwrap(), 1, U256::MAX, false);
355 assert_eq!(result.unwrap_err().to_string(), "require((product = amount * sqrtPX96) / amount == sqrtPX96 && numerator1 > product);");
356 }
357
358 #[test]
359 fn test_get_amount_0_delta() {
360 let amount_0 = _get_amount_0_delta(
362 U256::from_str("79228162514264337593543950336").unwrap(),
363 U256::from_str("79228162514264337593543950336").unwrap(),
364 0,
365 true,
366 );
367
368 assert_eq!(amount_0.unwrap(), U256::ZERO);
369
370 let amount_0 = _get_amount_0_delta(
372 U256::from_str("79228162514264337593543950336").unwrap(),
373 U256::from_str("87150978765690771352898345369").unwrap(),
374 0,
375 true,
376 );
377
378 assert_eq!(amount_0.unwrap(), U256::ZERO);
379
380 let amount_0 = _get_amount_0_delta(
382 U256::from_str("79228162514264337593543950336").unwrap(),
383 U256::from_str("87150978765690771352898345369").unwrap(),
384 1e18 as u128,
385 true,
386 )
387 .unwrap();
388
389 assert_eq!(amount_0.clone(), U256::from_str("90909090909090910").unwrap());
390
391 let amount_0_rounded_down = _get_amount_0_delta(
392 U256::from_str("79228162514264337593543950336").unwrap(),
393 U256::from_str("87150978765690771352898345369").unwrap(),
394 1e18 as u128,
395 false,
396 );
397
398 assert_eq!(amount_0_rounded_down.unwrap(), amount_0.sub(U256_1));
399
400 let amount_0_up = _get_amount_0_delta(
402 U256::from_str("2787593149816327892691964784081045188247552").unwrap(),
403 U256::from_str("22300745198530623141535718272648361505980416").unwrap(),
404 1e18 as u128,
405 true,
406 )
407 .unwrap();
408
409 let amount_0_down = _get_amount_0_delta(
410 U256::from_str("2787593149816327892691964784081045188247552").unwrap(),
411 U256::from_str("22300745198530623141535718272648361505980416").unwrap(),
412 1e18 as u128,
413 false,
414 )
415 .unwrap();
416
417 assert_eq!(amount_0_up, amount_0_down.add(U256_1));
418 }
419
420 #[test]
421 fn test_get_amount_1_delta() {
422 let amount_1 = _get_amount_1_delta(
424 U256::from_str("79228162514264337593543950336").unwrap(),
425 U256::from_str("79228162514264337593543950336").unwrap(),
426 0,
427 true,
428 );
429
430 assert_eq!(amount_1.unwrap(), U256::ZERO);
431
432 let amount_1 = _get_amount_1_delta(
434 U256::from_str("79228162514264337593543950336").unwrap(),
435 U256::from_str("87150978765690771352898345369").unwrap(),
436 0,
437 true,
438 );
439
440 assert_eq!(amount_1.unwrap(), U256::ZERO);
441
442 let amount_1 = _get_amount_1_delta(
444 U256::from_str("79228162514264337593543950336").unwrap(),
445 U256::from_str("87150978765690771352898345369").unwrap(),
446 1e18 as u128,
447 true,
448 )
449 .unwrap();
450
451 assert_eq!(amount_1.clone(), U256::from_str("100000000000000000").unwrap());
452
453 let amount_1_rounded_down = _get_amount_1_delta(
454 U256::from_str("79228162514264337593543950336").unwrap(),
455 U256::from_str("87150978765690771352898345369").unwrap(),
456 1e18 as u128,
457 false,
458 );
459
460 assert_eq!(amount_1_rounded_down.unwrap(), amount_1.sub(U256_1));
461 }
462
463 #[test]
464 fn test_swap_computation() {
465 let sqrt_price = U256::from_str("1025574284609383690408304870162715216695788925244").unwrap();
466 let liquidity = 50015962439936049619261659728067971248;
467 let zero_for_one = true;
468 let amount_in = U256::from(406);
469
470 let sqrt_q = get_next_sqrt_price_from_input(sqrt_price, liquidity, amount_in, zero_for_one).unwrap();
471
472 assert_eq!(sqrt_q, U256::from_str("1025574284609383582644711336373707553698163132913").unwrap());
473
474 let amount_0_delta = _get_amount_0_delta(sqrt_q, sqrt_price, liquidity, true).unwrap();
475
476 assert_eq!(amount_0_delta, U256::from(406));
477 }
478}