1use alloy_primitives::{U160, U256};
17
18use super::full_math::FullMath;
19use crate::{
20 defi::tick_map::tick_math::get_sqrt_ratio_at_tick,
21 types::{PRICE_RAW_MAX, PRICE_RAW_MIN, Price, fixed::FIXED_PRECISION},
22};
23
24#[must_use]
36pub fn encode_sqrt_ratio_x96(amount0: u128, amount1: u128) -> U160 {
37 let amount0_u256 = U256::from(amount0);
38 let amount1_u256 = U256::from(amount1);
39
40 assert!(!amount1_u256.is_zero(), "Division by zero");
41 if amount0_u256.is_zero() {
42 return U160::ZERO;
43 }
44
45 let q192 = U256::from(1u128) << 192;
51
52 if amount0_u256 > U256::MAX / q192 {
54 let sqrt_amount0 = FullMath::sqrt(amount0_u256);
57 let sqrt_amount1 = FullMath::sqrt(amount1_u256);
58
59 assert!(!sqrt_amount1.is_zero(), "Division by zero in sqrt");
60
61 let q96 = U256::from(1u128) << 96;
62
63 let result = FullMath::mul_div(sqrt_amount0, q96, sqrt_amount1).expect("mul_div overflow");
65
66 return if result > U256::from(U160::MAX) {
68 U160::MAX
69 } else {
70 U160::from(result)
71 };
72 }
73
74 let ratio_q192 = FullMath::mul_div(amount0_u256, q192, amount1_u256).expect("mul_div overflow");
76
77 let sqrt_result = FullMath::sqrt(ratio_q192);
79
80 if sqrt_result > U256::from(U160::MAX) {
82 U160::MAX
83 } else {
84 U160::from(sqrt_result)
85 }
86}
87
88fn get_next_sqrt_price_from_amount0_rounding_up(
90 sqrt_price_x96: U160,
91 liquidity: u128,
92 amount: U256,
93 add: bool,
94) -> U160 {
95 if amount.is_zero() {
96 return sqrt_price_x96;
97 }
98 let numerator = U256::from(liquidity) << 96;
99 let sqrt_price_x96 = U256::from(sqrt_price_x96);
100 let product = amount * sqrt_price_x96;
101
102 if add {
103 if product / amount == sqrt_price_x96 {
104 let denominator = numerator + product;
105 if denominator >= numerator {
106 let result = FullMath::mul_div_rounding_up(numerator, sqrt_price_x96, denominator)
108 .expect("mul_div_rounding_up failed");
109 return U160::from(result);
110 }
111 }
112
113 let fallback_denominator = (numerator / sqrt_price_x96) + amount;
115 let result = FullMath::div_rounding_up(numerator, fallback_denominator)
116 .expect("div_rounding_up failed");
117
118 assert!(result <= U256::from(U160::MAX), "Result overflows U160");
120 U160::from(result)
121 } else {
122 assert!(
124 (product / amount) == sqrt_price_x96 && numerator > product,
125 "Invalid conditions for amount0 removal: overflow or underflow detected"
126 );
127
128 let denominator = numerator - product;
129 let result = FullMath::mul_div_rounding_up(numerator, sqrt_price_x96, denominator)
130 .expect("mul_div_rounding_up failed");
131 U160::from(result)
132 }
133}
134
135fn get_next_sqrt_price_from_amount1_rounding_down(
137 sqrt_price_x96: U160,
138 liquidity: u128,
139 amount: U256,
140 add: bool,
141) -> U160 {
142 if add {
145 let quotient = if amount <= U256::from(U160::MAX) {
146 (amount << 96) / U256::from(liquidity)
148 } else {
149 FullMath::mul_div(amount, U256::from(1u128) << 96, U256::from(liquidity))
151 .unwrap_or(U256::ZERO)
152 };
153
154 U160::from(U256::from(sqrt_price_x96) + quotient)
156 } else {
157 let quotient = if amount <= U256::from(U160::MAX) {
158 FullMath::div_rounding_up(amount << 96, U256::from(liquidity)).unwrap_or(U256::ZERO)
160 } else {
161 FullMath::mul_div_rounding_up(amount, U256::from(1u128) << 96, U256::from(liquidity))
163 .unwrap_or(U256::ZERO)
164 };
165
166 assert!(
168 U256::from(sqrt_price_x96) > quotient,
169 "sqrt_price_x96 must be greater than quotient"
170 );
171
172 U160::from(U256::from(sqrt_price_x96) - quotient)
174 }
175}
176
177#[must_use]
182pub fn get_next_sqrt_price_from_input(
183 sqrt_price_x96: U160,
184 liquidity: u128,
185 amount_in: U256,
186 zero_for_one: bool,
187) -> U160 {
188 assert!(
189 sqrt_price_x96 > U160::ZERO,
190 "sqrt_price_x96 must be greater than zero"
191 );
192 assert!(liquidity > 0, "Liquidity must be greater than zero");
193
194 if zero_for_one {
195 get_next_sqrt_price_from_amount0_rounding_up(sqrt_price_x96, liquidity, amount_in, true)
196 } else {
197 get_next_sqrt_price_from_amount1_rounding_down(sqrt_price_x96, liquidity, amount_in, true)
198 }
199}
200
201#[must_use]
206pub fn get_next_sqrt_price_from_output(
207 sqrt_price_x96: U160,
208 liquidity: u128,
209 amount_out: U256,
210 zero_for_one: bool,
211) -> U160 {
212 assert!(
213 sqrt_price_x96 > U160::ZERO,
214 "sqrt_price_x96 must be greater than zero"
215 );
216 assert!(liquidity > 0, "Liquidity must be greater than zero");
217
218 if zero_for_one {
219 get_next_sqrt_price_from_amount1_rounding_down(sqrt_price_x96, liquidity, amount_out, false)
220 } else {
221 get_next_sqrt_price_from_amount0_rounding_up(sqrt_price_x96, liquidity, amount_out, false)
222 }
223}
224
225#[must_use]
227pub fn get_amount0_delta(
228 sqrt_ratio_ax96: U160,
229 sqrt_ratio_bx96: U160,
230 liquidity: u128,
231 round_up: bool,
232) -> U256 {
233 let (sqrt_ratio_a, sqrt_ratio_b) = if sqrt_ratio_ax96 > sqrt_ratio_bx96 {
234 (sqrt_ratio_bx96, sqrt_ratio_ax96)
235 } else {
236 (sqrt_ratio_ax96, sqrt_ratio_bx96)
237 };
238
239 let numerator1 = U256::from(liquidity) << 96;
240 let numerator2 = U256::from(sqrt_ratio_b - sqrt_ratio_a);
241
242 if round_up {
243 let result =
245 FullMath::mul_div_rounding_up(numerator1, numerator2, U256::from(sqrt_ratio_b))
246 .unwrap_or(U256::ZERO);
247
248 FullMath::div_rounding_up(result, U256::from(sqrt_ratio_a)).unwrap_or(U256::ZERO)
250 } else {
251 let result = FullMath::mul_div(numerator1, numerator2, U256::from(sqrt_ratio_b))
252 .unwrap_or(U256::ZERO);
253 result / U256::from(sqrt_ratio_a)
254 }
255}
256#[must_use]
258pub fn get_amount1_delta(
259 sqrt_ratio_ax96: U160,
260 sqrt_ratio_bx96: U160,
261 liquidity: u128,
262 round_up: bool,
263) -> U256 {
264 let (sqrt_ratio_a, sqrt_ratio_b) = if sqrt_ratio_ax96 > sqrt_ratio_bx96 {
265 (sqrt_ratio_bx96, sqrt_ratio_ax96)
266 } else {
267 (sqrt_ratio_ax96, sqrt_ratio_bx96)
268 };
269
270 let liquidity_u256 = U256::from(liquidity);
271 let sqrt_ratio_diff = U256::from(sqrt_ratio_b - sqrt_ratio_a);
272 let q96 = U256::from(1u128) << 96;
273
274 if round_up {
275 FullMath::mul_div_rounding_up(liquidity_u256, sqrt_ratio_diff, q96).unwrap_or(U256::ZERO)
276 } else {
277 FullMath::mul_div(liquidity_u256, sqrt_ratio_diff, q96).unwrap_or(U256::ZERO)
278 }
279}
280
281#[must_use]
283pub fn get_amounts_for_liquidity(
284 sqrt_ratio_x96: U160,
285 tick_lower: i32,
286 tick_upper: i32,
287 liquidity: u128,
288 round_up: bool,
289) -> (U256, U256) {
290 let sqrt_ratio_lower_x96 = get_sqrt_ratio_at_tick(tick_lower);
291 let sqrt_ratio_upper_x96 = get_sqrt_ratio_at_tick(tick_upper);
292
293 let (sqrt_ratio_a, sqrt_ratio_b) = if sqrt_ratio_lower_x96 > sqrt_ratio_upper_x96 {
295 (sqrt_ratio_upper_x96, sqrt_ratio_lower_x96)
296 } else {
297 (sqrt_ratio_lower_x96, sqrt_ratio_upper_x96)
298 };
299
300 let amount0 = if sqrt_ratio_x96 <= sqrt_ratio_a {
301 get_amount0_delta(sqrt_ratio_a, sqrt_ratio_b, liquidity, round_up)
303 } else if sqrt_ratio_x96 < sqrt_ratio_b {
304 get_amount0_delta(sqrt_ratio_x96, sqrt_ratio_b, liquidity, round_up)
306 } else {
307 U256::ZERO
309 };
310
311 let amount1 = if sqrt_ratio_x96 < sqrt_ratio_a {
312 U256::ZERO
314 } else if sqrt_ratio_x96 < sqrt_ratio_b {
315 get_amount1_delta(sqrt_ratio_a, sqrt_ratio_x96, liquidity, round_up)
317 } else {
318 get_amount1_delta(sqrt_ratio_a, sqrt_ratio_b, liquidity, round_up)
320 };
321
322 (amount0, amount1)
323}
324
325#[must_use]
327pub fn expand_to_18_decimals(amount: u64) -> u128 {
328 u128::from(amount) * 10u128.pow(18)
329}
330
331pub fn decode_sqrt_price_x96_to_price(sqrt_price_x96: U160) -> anyhow::Result<Price> {
340 let sqrt_price = U256::from(sqrt_price_x96);
341 let price_x192 = sqrt_price * sqrt_price;
342
343 let fixed_scalar = U256::from(10u128.pow(u32::from(FIXED_PRECISION)));
344 let divisor = U256::from(1u128) << 192;
345 let price_raw_u256 = FullMath::mul_div(price_x192, fixed_scalar, divisor)?;
346
347 let price_raw = price_raw_u256
348 .try_into()
349 .map_err(|_| anyhow::anyhow!("Price overflow: {price_raw_u256} exceeds PriceRaw range"))?;
350
351 Ok(Price::from_raw(price_raw, FIXED_PRECISION))
352}
353
354pub fn decode_sqrt_price_x96_to_price_tokens_adjusted(
369 sqrt_price_x96: U160,
370 token0_decimals: u8,
371 token1_decimals: u8,
372 invert: bool,
373) -> anyhow::Result<Price> {
374 let sqrt_price = U256::from(sqrt_price_x96);
375 let price_x192 = sqrt_price * sqrt_price;
376
377 let decimal_diff = i32::from(token0_decimals) - i32::from(token1_decimals);
378 let fixed_scalar = U256::from(10u128.pow(u32::from(FIXED_PRECISION)));
379 let divisor_base = U256::from(1u128) << 192;
380
381 let numerator = if invert {
382 if decimal_diff >= 0 {
383 let decimal_adjustment = U256::from(10u128.pow(decimal_diff.unsigned_abs()));
384 let denominator = FullMath::mul_div(price_x192, decimal_adjustment, U256::from(1))?;
385 FullMath::mul_div(divisor_base, fixed_scalar, denominator)?
386 } else {
387 let decimal_adjustment = U256::from(10u128.pow(decimal_diff.unsigned_abs()));
388 let numerator_adjusted =
389 FullMath::mul_div(divisor_base, decimal_adjustment, U256::from(1))?;
390 FullMath::mul_div(numerator_adjusted, fixed_scalar, price_x192)?
391 }
392 } else if decimal_diff >= 0 {
393 let decimal_adjustment = U256::from(10u128.pow(decimal_diff.unsigned_abs()));
394 let temp = FullMath::mul_div(price_x192, decimal_adjustment, U256::from(1))?;
395 FullMath::mul_div(temp, fixed_scalar, divisor_base)?
396 } else {
397 let decimal_adjustment = U256::from(10u128.pow(decimal_diff.unsigned_abs()));
398 let divisor_adjusted = divisor_base * decimal_adjustment;
399 FullMath::mul_div(price_x192, fixed_scalar, divisor_adjusted)?
400 };
401
402 let price_raw: i128 = numerator
403 .try_into()
404 .map_err(|_| anyhow::anyhow!("Price overflow: {numerator} exceeds PriceRaw range"))?;
405
406 if price_raw > PRICE_RAW_MAX {
408 anyhow::bail!("Price {price_raw} exceeds maximum valid price {PRICE_RAW_MAX}");
409 }
410
411 if price_raw < PRICE_RAW_MIN {
412 anyhow::bail!("Price {price_raw} is below minimum valid price {PRICE_RAW_MIN}");
413 }
414
415 Ok(Price::from_raw(price_raw, FIXED_PRECISION))
416}
417
418#[cfg(test)]
419mod tests {
420 use rstest::*;
422
423 use super::*;
424 use crate::defi::tick_map::full_math::Q96_U160;
425
426 #[rstest]
427 #[should_panic(expected = "sqrt_price_x96 must be greater than zero")]
428 fn test_if_get_next_sqrt_price_from_input_panic_if_price_zero() {
429 let _ = get_next_sqrt_price_from_input(U160::ZERO, 1, U256::ZERO, true);
430 }
431
432 #[rstest]
433 #[should_panic(expected = "Liquidity must be greater than zero")]
434 fn test_if_get_next_sqrt_price_from_input_panic_if_liquidity_zero() {
435 let _ = get_next_sqrt_price_from_input(U160::from(1), 0, U256::ZERO, true);
436 }
437
438 #[rstest]
439 #[should_panic(expected = "Uint conversion error: Value is too large for Uint<160>")]
440 fn test_if_get_next_sqrt_price_from_input_panics_from_big_price() {
441 let price = U160::MAX - U160::from(1);
442 let _ = get_next_sqrt_price_from_input(price, 1024, U256::from(1024), false);
443 }
444
445 #[rstest]
446 fn test_any_input_amount_cannot_underflow_the_price() {
447 let price = U160::from(1);
450 let liquidity = 1;
451 let amount_in = U256::from(2).pow(U256::from(255));
452 let result = get_next_sqrt_price_from_input(price, liquidity, amount_in, true);
453 assert_eq!(result, U160::from(1));
454 }
455
456 #[rstest]
457 fn test_returns_input_price_if_amount_in_is_zero_and_zero_for_one_true() {
458 let price = encode_sqrt_ratio_x96(1, 1);
459 let liquidity = expand_to_18_decimals(1) / 10;
460 let result = get_next_sqrt_price_from_input(price, liquidity, U256::ZERO, true);
461 assert_eq!(result, price);
462 }
463
464 #[rstest]
465 fn test_returns_input_price_if_amount_in_is_zero_and_zero_for_one_false() {
466 let price = encode_sqrt_ratio_x96(1, 1);
467 let liquidity = expand_to_18_decimals(1) / 10;
468 let result = get_next_sqrt_price_from_input(price, liquidity, U256::ZERO, false);
469 assert_eq!(result, price);
470 }
471
472 #[rstest]
473 fn test_returns_the_minimum_price_for_max_inputs() {
474 let sqrt_p = U160::MAX;
475 let liquidity = u128::MAX;
476 let max_amount_no_overflow = U256::MAX - (U256::from(liquidity) << 96) / U256::from(sqrt_p);
477 let result =
478 get_next_sqrt_price_from_input(sqrt_p, liquidity, max_amount_no_overflow, true);
479 assert_eq!(result, U160::from(1));
480 }
481
482 #[rstest]
483 fn test_input_amount_of_0_1_token1() {
484 let sqrt_q = get_next_sqrt_price_from_input(
485 encode_sqrt_ratio_x96(1, 1),
486 expand_to_18_decimals(1),
487 U256::from(expand_to_18_decimals(1)) / U256::from(10),
488 false,
489 );
490 assert_eq!(
491 sqrt_q,
492 U160::from_str_radix("87150978765690771352898345369", 10).unwrap()
493 );
494 }
495
496 #[rstest]
497 fn test_input_amount_of_0_1_token0() {
498 let sqrt_q = get_next_sqrt_price_from_input(
499 encode_sqrt_ratio_x96(1, 1),
500 expand_to_18_decimals(1),
501 U256::from(expand_to_18_decimals(1)) / U256::from(10),
502 true,
503 );
504 assert_eq!(
505 sqrt_q,
506 U160::from_str_radix("72025602285694852357767227579", 10).unwrap()
507 );
508 }
509
510 #[rstest]
511 fn test_amount_in_greater_than_uint96_max_and_zero_for_one_true() {
512 let result = get_next_sqrt_price_from_input(
513 encode_sqrt_ratio_x96(1, 1),
514 expand_to_18_decimals(10),
515 U256::from(2).pow(U256::from(100)),
516 true,
517 );
518 assert_eq!(
519 result,
520 U160::from_str_radix("624999999995069620", 10).unwrap()
521 );
522 }
523
524 #[rstest]
525 fn test_can_return_1_with_enough_amount_in_and_zero_for_one_true() {
526 let result = get_next_sqrt_price_from_input(
527 encode_sqrt_ratio_x96(1, 1),
528 1,
529 U256::MAX / U256::from(2),
530 true,
531 );
532 assert_eq!(result, U160::from(1));
533 }
534
535 #[rstest]
536 #[should_panic(
537 expected = "Invalid conditions for amount0 removal: overflow or underflow detected"
538 )]
539 fn test_fails_if_output_amount_is_exactly_virtual_reserves_of_token0() {
540 let price = U160::from_str_radix("20282409603651670423947251286016", 10).unwrap();
541 let liquidity = 1024;
542 let amount_out = U256::from(4);
543 let _ = get_next_sqrt_price_from_output(price, liquidity, amount_out, false);
544 }
545
546 #[rstest]
547 #[should_panic(
548 expected = "Invalid conditions for amount0 removal: overflow or underflow detected"
549 )]
550 fn test_fails_if_output_amount_is_greater_than_virtual_reserves_of_token0() {
551 let price = U160::from_str_radix("20282409603651670423947251286016", 10).unwrap();
552 let liquidity = 1024;
553 let amount_out = U256::from(5);
554 let _ = get_next_sqrt_price_from_output(price, liquidity, amount_out, false);
555 }
556
557 #[rstest]
558 #[should_panic(expected = "sqrt_price_x96 must be greater than quotient")]
559 fn test_fails_if_output_amount_is_greater_than_virtual_reserves_of_token1() {
560 let price = U160::from_str_radix("20282409603651670423947251286016", 10).unwrap();
561 let liquidity = 1024;
562 let amount_out = U256::from(262_145);
563 let _ = get_next_sqrt_price_from_output(price, liquidity, amount_out, true);
564 }
565
566 #[rstest]
567 #[should_panic(expected = "sqrt_price_x96 must be greater than quotient")]
568 fn test_fails_if_output_amount_is_exactly_virtual_reserves_of_token1() {
569 let price = U160::from_str_radix("20282409603651670423947251286016", 10).unwrap();
570 let liquidity = 1024;
571 let amount_out = U256::from(262_144);
572 let _ = get_next_sqrt_price_from_output(price, liquidity, amount_out, true);
573 }
574
575 #[rstest]
576 fn test_succeeds_if_output_amount_is_just_less_than_virtual_reserves_of_token1() {
577 let price = U160::from_str_radix("20282409603651670423947251286016", 10).unwrap();
578 let liquidity = 1024;
579 let amount_out = U256::from(262_143);
580 let result = get_next_sqrt_price_from_output(price, liquidity, amount_out, true);
581 assert_eq!(
582 result,
583 U160::from_str_radix("77371252455336267181195264", 10).unwrap()
584 );
585 }
586
587 #[rstest]
588 fn test_returns_input_price_if_amount_out_is_zero_and_zero_for_one_true() {
589 let price = encode_sqrt_ratio_x96(1, 1);
590 let liquidity = expand_to_18_decimals(1) / 10;
591 let result = get_next_sqrt_price_from_output(price, liquidity, U256::ZERO, true);
592 assert_eq!(result, price);
593 }
594
595 #[rstest]
596 fn test_returns_input_price_if_amount_out_is_zero_and_zero_for_one_false() {
597 let price = encode_sqrt_ratio_x96(1, 1);
598 let liquidity = expand_to_18_decimals(1) / 10;
599 let result = get_next_sqrt_price_from_output(price, liquidity, U256::ZERO, false);
600 assert_eq!(result, price);
601 }
602
603 #[rstest]
604 fn test_output_amount_of_0_1_token1_zero_for_one_false() {
605 let sqrt_q = get_next_sqrt_price_from_output(
606 encode_sqrt_ratio_x96(1, 1),
607 expand_to_18_decimals(1),
608 U256::from(expand_to_18_decimals(1)) / U256::from(10),
609 false,
610 );
611 assert_eq!(
612 sqrt_q,
613 U160::from_str_radix("88031291682515930659493278152", 10).unwrap()
614 );
615 }
616
617 #[rstest]
618 fn test_output_amount_of_0_1_token1_zero_for_one_true() {
619 let sqrt_q = get_next_sqrt_price_from_output(
620 encode_sqrt_ratio_x96(1, 1),
621 expand_to_18_decimals(1),
622 U256::from(expand_to_18_decimals(1)) / U256::from(10),
623 true,
624 );
625 assert_eq!(
626 sqrt_q,
627 U160::from_str_radix("71305346262837903834189555302", 10).unwrap()
628 );
629 }
630
631 #[rstest]
632 #[should_panic(expected = "sqrt_price_x96 must be greater than zero")]
633 fn test_if_get_next_sqrt_price_from_output_panic_if_price_zero() {
634 let _ = get_next_sqrt_price_from_output(U160::ZERO, 1, U256::ZERO, true);
635 }
636
637 #[rstest]
638 #[should_panic(expected = "Liquidity must be greater than zero")]
639 fn test_if_get_next_sqrt_price_from_output_panic_if_liquidity_zero() {
640 let _ = get_next_sqrt_price_from_output(U160::from(1), 0, U256::ZERO, true);
641 }
642
643 #[rstest]
644 fn test_encode_sqrt_ratio_x98_some_values() {
645 assert_eq!(encode_sqrt_ratio_x96(1, 1), Q96_U160);
646 assert_eq!(
647 encode_sqrt_ratio_x96(100, 1),
648 U160::from(792_281_625_142_643_375_935_439_503_360_u128)
649 );
650 assert_eq!(
651 encode_sqrt_ratio_x96(1, 100),
652 U160::from(7_922_816_251_426_433_759_354_395_033_u128)
653 );
654 assert_eq!(
655 encode_sqrt_ratio_x96(111, 333),
656 U160::from(45_742_400_955_009_932_534_161_870_629_u128)
657 );
658 assert_eq!(
659 encode_sqrt_ratio_x96(333, 111),
660 U160::from(137_227_202_865_029_797_602_485_611_888_u128)
661 );
662 }
663
664 #[rstest]
665 fn test_get_amount0_delta_returns_0_if_liquidity_is_0() {
666 let amount0 = get_amount0_delta(
667 encode_sqrt_ratio_x96(1, 1),
668 encode_sqrt_ratio_x96(2, 1),
669 0,
670 true,
671 );
672 assert_eq!(amount0, U256::ZERO);
673 }
674
675 #[rstest]
676 fn test_get_amount0_delta_returns_0_if_prices_are_equal() {
677 let amount0 = get_amount0_delta(
678 encode_sqrt_ratio_x96(1, 1),
679 encode_sqrt_ratio_x96(1, 1),
680 0,
681 true,
682 );
683 assert_eq!(amount0, U256::ZERO);
684 }
685
686 #[rstest]
687 fn test_get_amount0_delta_returns_0_1_amount1_for_price_of_1_to_1_21() {
688 let amount0 = get_amount0_delta(
689 encode_sqrt_ratio_x96(1, 1),
690 encode_sqrt_ratio_x96(121, 100),
691 expand_to_18_decimals(1),
692 true,
693 );
694 assert_eq!(
695 amount0,
696 U256::from_str_radix("90909090909090910", 10).unwrap()
697 );
698
699 let amount0_rounded_down = get_amount0_delta(
700 encode_sqrt_ratio_x96(1, 1),
701 encode_sqrt_ratio_x96(121, 100),
702 expand_to_18_decimals(1),
703 false,
704 );
705
706 assert_eq!(amount0_rounded_down, amount0 - U256::from(1));
707 }
708
709 #[rstest]
710 fn test_get_amount0_delta_works_for_prices_that_overflow() {
711 let price_low =
713 encode_sqrt_ratio_x96(U256::from(2).pow(U256::from(90)).try_into().unwrap(), 1);
714 let price_high =
715 encode_sqrt_ratio_x96(U256::from(2).pow(U256::from(96)).try_into().unwrap(), 1);
716
717 let amount0_up = get_amount0_delta(price_low, price_high, expand_to_18_decimals(1), true);
718
719 let amount0_down =
720 get_amount0_delta(price_low, price_high, expand_to_18_decimals(1), false);
721
722 assert_eq!(amount0_up, amount0_down + U256::from(1));
723 }
724
725 #[rstest]
726 fn test_get_amount1_delta_returns_0_if_liquidity_is_0() {
727 let amount1 = get_amount1_delta(
728 encode_sqrt_ratio_x96(1, 1),
729 encode_sqrt_ratio_x96(2, 1),
730 0,
731 true,
732 );
733 assert_eq!(amount1, U256::ZERO);
734 }
735
736 #[rstest]
737 fn test_get_amount1_delta_returns_0_if_prices_are_equal() {
738 let amount1 = get_amount1_delta(
739 encode_sqrt_ratio_x96(1, 1),
740 encode_sqrt_ratio_x96(1, 1),
741 0,
742 true,
743 );
744 assert_eq!(amount1, U256::ZERO);
745 }
746
747 #[rstest]
748 fn test_get_amount1_delta_returns_0_1_amount1_for_price_of_1_to_1_21() {
749 let amount1 = get_amount1_delta(
750 encode_sqrt_ratio_x96(1, 1),
751 encode_sqrt_ratio_x96(121, 100),
752 expand_to_18_decimals(1),
753 true,
754 );
755 assert_eq!(
756 amount1,
757 U256::from_str_radix("100000000000000000", 10).unwrap()
758 );
759
760 let amount1_rounded_down = get_amount1_delta(
761 encode_sqrt_ratio_x96(1, 1),
762 encode_sqrt_ratio_x96(121, 100),
763 expand_to_18_decimals(1),
764 false,
765 );
766
767 assert_eq!(amount1_rounded_down, amount1 - U256::from(1));
768 }
769
770 #[rstest]
771 fn test_decode_sqrt_price_x96_to_price_and_decimal_adjustments() {
772 let sqrt_price_x96 =
774 U160::from_str_radix("2018382873588440326581633304624437", 10).unwrap();
775
776 let raw_price = decode_sqrt_price_x96_to_price(sqrt_price_x96).unwrap();
777 assert_eq!(raw_price.as_f64(), 649_004_842.701_37);
778
779 let adjusted_price =
781 decode_sqrt_price_x96_to_price_tokens_adjusted(sqrt_price_x96, 6, 18, true).unwrap();
782 assert_eq!(adjusted_price.as_f64(), 1_540.820_552_028_045_8);
783 }
784}