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