1#![allow(clippy::collapsible_else_if)]
2#![allow(clippy::too_many_arguments)]
3
4use crate::{calculate_tuna_protocol_fee, CoreError, COMPUTED_AMOUNT, HUNDRED_PERCENT, INVALID_ARGUMENTS};
5use fusionamm_core::{
6 position_ratio_x64, tick_index_to_sqrt_price, try_apply_swap_fee, try_get_amount_delta_a, try_get_amount_delta_b, try_get_liquidity_from_a,
7 try_get_liquidity_from_b, try_get_token_a_from_liquidity, try_get_token_b_from_liquidity, Q64_RESOLUTION, U128,
8};
9
10#[cfg(feature = "wasm")]
11use fusionamm_macros::wasm_expose;
12
13#[derive(Debug, Copy, Clone, PartialEq)]
14#[cfg_attr(feature = "wasm", wasm_expose)]
15pub struct LiquidationPrices {
16 pub lower: f64,
17 pub upper: f64,
18}
19
20fn compute_liquidation_prices_inside(
52 lower_sqrt_price: u128,
53 upper_sqrt_price: u128,
54 liquidity: u128,
55 leftovers_a: u64,
56 leftovers_b: u64,
57 debt_a: u64,
58 debt_b: u64,
59 liquidation_threshold: u32,
60) -> Result<LiquidationPrices, CoreError> {
61 let liquidation_threshold_f = liquidation_threshold as f64 / HUNDRED_PERCENT as f64;
62 let liquidity_f = liquidity as f64;
63 let lower_sqrt_price_f = lower_sqrt_price as f64 / Q64_RESOLUTION;
64 let upper_sqrt_price_f = upper_sqrt_price as f64 / Q64_RESOLUTION;
65
66 let a = debt_a as f64 + liquidation_threshold_f * (liquidity_f / upper_sqrt_price_f - leftovers_a as f64);
67 let b = -2.0 * liquidation_threshold_f * liquidity_f;
68 let c = debt_b as f64 + liquidation_threshold_f * (liquidity_f * lower_sqrt_price_f - leftovers_b as f64);
69 let d = b * b - 4.0 * a * c;
70
71 let mut lower_liquidation_sqrt_price = 0.0;
72 let mut upper_liquidation_sqrt_price = 0.0;
73
74 if d >= 0.0 {
75 lower_liquidation_sqrt_price = (-b - d.sqrt()) / (2.0 * a);
76 upper_liquidation_sqrt_price = (-b + d.sqrt()) / (2.0 * a);
77 if lower_liquidation_sqrt_price < 0.0 || lower_liquidation_sqrt_price < lower_sqrt_price_f {
78 lower_liquidation_sqrt_price = 0.0;
79 }
80 if upper_liquidation_sqrt_price < 0.0 || upper_liquidation_sqrt_price > upper_sqrt_price_f {
81 upper_liquidation_sqrt_price = 0.0;
82 }
83 }
84
85 Ok(LiquidationPrices {
86 lower: lower_liquidation_sqrt_price * lower_liquidation_sqrt_price,
87 upper: upper_liquidation_sqrt_price * upper_liquidation_sqrt_price,
88 })
89}
90
91fn calculate_liquidation_outside(
122 amount_a: u64,
123 amount_b: u64,
124 leftovers_a: u64,
125 leftovers_b: u64,
126 debt_a: u64,
127 debt_b: u64,
128 liquidation_threshold: u32,
129) -> Result<f64, CoreError> {
130 let liquidation_threshold_f = liquidation_threshold as f64 / HUNDRED_PERCENT as f64;
131
132 if amount_a == 0 && amount_b == 0 {
133 Ok(0.0)
134 } else if amount_a > 0 && amount_b == 0 {
135 let numerator = debt_b as f64 - liquidation_threshold_f * leftovers_b as f64;
137 let denominator = liquidation_threshold_f * (amount_a + leftovers_a) as f64 - debt_a as f64;
138 Ok(numerator / denominator)
139 } else if amount_a == 0 && amount_b > 0 {
140 let numerator = liquidation_threshold_f * (amount_b + leftovers_b) as f64 - debt_b as f64;
142 let denominator = debt_a as f64 - liquidation_threshold_f * leftovers_a as f64;
143 if denominator == 0.0 {
144 return Ok(0.0);
145 }
146 Ok(numerator / denominator)
147 } else {
148 Err(INVALID_ARGUMENTS)
149 }
150}
151
152fn compute_liquidation_prices_outside(
167 lower_sqrt_price: u128,
168 upper_sqrt_price: u128,
169 liquidity: u128,
170 leftovers_a: u64,
171 leftovers_b: u64,
172 debt_a: u64,
173 debt_b: u64,
174 liquidation_threshold: u32,
175) -> Result<LiquidationPrices, CoreError> {
176 let amount_a = try_get_amount_delta_a(lower_sqrt_price.into(), upper_sqrt_price.into(), liquidity.into(), false)?;
177 let amount_b = try_get_amount_delta_b(lower_sqrt_price.into(), upper_sqrt_price.into(), liquidity.into(), false)?;
178
179 let mut liquidation_price_for_a = calculate_liquidation_outside(amount_a, 0, leftovers_a, leftovers_b, debt_a, debt_b, liquidation_threshold)?;
180 let mut liquidation_price_for_b = calculate_liquidation_outside(0, amount_b, leftovers_a, leftovers_b, debt_a, debt_b, liquidation_threshold)?;
181
182 if liquidation_price_for_a < 0.0 || liquidation_price_for_a > (lower_sqrt_price as f64 / Q64_RESOLUTION).powf(2.0) {
183 liquidation_price_for_a = 0.0;
184 }
185 if liquidation_price_for_b < 0.0 || liquidation_price_for_b < (upper_sqrt_price as f64 / Q64_RESOLUTION).powf(2.0) {
186 liquidation_price_for_b = 0.0;
187 }
188
189 Ok(LiquidationPrices {
190 lower: liquidation_price_for_a,
191 upper: liquidation_price_for_b,
192 })
193}
194
195#[cfg_attr(feature = "wasm", wasm_expose)]
210pub fn get_lp_position_liquidation_prices(
211 tick_lower_index: i32,
212 tick_upper_index: i32,
213 liquidity: U128,
214 leftovers_a: u64,
215 leftovers_b: u64,
216 debt_a: u64,
217 debt_b: u64,
218 liquidation_threshold: u32,
219) -> Result<LiquidationPrices, CoreError> {
220 if tick_lower_index >= tick_upper_index {
221 return Err(INVALID_ARGUMENTS);
222 }
223
224 if liquidation_threshold >= HUNDRED_PERCENT {
225 return Err(INVALID_ARGUMENTS);
226 }
227
228 let lower_sqrt_price: u128 = tick_index_to_sqrt_price(tick_lower_index).into();
229 let upper_sqrt_price: u128 = tick_index_to_sqrt_price(tick_upper_index).into();
230 let liquidity: u128 = liquidity.into();
231
232 let liquidation_price_inside = compute_liquidation_prices_inside(
233 lower_sqrt_price,
234 upper_sqrt_price,
235 liquidity,
236 leftovers_a,
237 leftovers_b,
238 debt_a,
239 debt_b,
240 liquidation_threshold,
241 )?;
242
243 let liquidation_price_outside = compute_liquidation_prices_outside(
244 lower_sqrt_price,
245 upper_sqrt_price,
246 liquidity,
247 leftovers_a,
248 leftovers_b,
249 debt_a,
250 debt_b,
251 liquidation_threshold,
252 )?;
253
254 let lower_liquidation_price = if liquidation_price_inside.lower > 0.0 {
255 liquidation_price_inside.lower
256 } else {
257 liquidation_price_outside.lower
258 };
259
260 let upper_liquidation_price = if liquidation_price_inside.upper > 0.0 {
261 liquidation_price_inside.upper
262 } else {
263 liquidation_price_outside.upper
264 };
265
266 Ok(LiquidationPrices {
267 lower: lower_liquidation_price,
268 upper: upper_liquidation_price,
269 })
270}
271
272#[derive(Debug, Copy, Clone, PartialEq)]
273#[cfg_attr(feature = "wasm", wasm_expose)]
274pub struct IncreaseLpPositionQuoteArgs {
275 pub collateral_a: u64,
277 pub collateral_b: u64,
279 pub borrow_a: u64,
281 pub borrow_b: u64,
283 pub protocol_fee_rate: u16,
285 pub protocol_fee_rate_on_collateral: u16,
287 pub swap_fee_rate: u16,
289 pub sqrt_price: u128,
291 pub tick_lower_index: i32,
293 pub tick_upper_index: i32,
295 pub max_amount_slippage: u32,
297}
298
299#[derive(Debug, Copy, Clone, PartialEq)]
300#[cfg_attr(feature = "wasm", wasm_expose)]
301pub struct IncreaseLpPositionQuoteResult {
302 pub collateral_a: u64,
303 pub collateral_b: u64,
304 pub max_collateral_a: u64,
305 pub max_collateral_b: u64,
306 pub borrow_a: u64,
307 pub borrow_b: u64,
308 pub total_a: u64,
309 pub total_b: u64,
310 pub min_total_a: u64,
311 pub min_total_b: u64,
312 pub swap_input: u64,
313 pub swap_output: u64,
314 pub swap_a_to_b: bool,
315 pub protocol_fee_a: u64,
316 pub protocol_fee_b: u64,
317}
318
319#[cfg_attr(feature = "wasm", wasm_expose)]
320pub fn get_increase_lp_position_quote(args: IncreaseLpPositionQuoteArgs) -> Result<IncreaseLpPositionQuoteResult, CoreError> {
321 let mut collateral_a = args.collateral_a;
322 let mut collateral_b = args.collateral_b;
323 let mut borrow_a = args.borrow_a;
324 let mut borrow_b = args.borrow_b;
325 let sqrt_price = args.sqrt_price;
326
327 if args.tick_lower_index > args.tick_upper_index {
328 return Err("Incorrect position tick index order: the lower tick must be less or equal the upper tick.");
329 }
330
331 if args.max_amount_slippage > HUNDRED_PERCENT {
332 return Err("max_amount_slippage must be in range [0; HUNDRED_PERCENT]");
333 }
334
335 if collateral_a == COMPUTED_AMOUNT && collateral_b == COMPUTED_AMOUNT {
336 return Err("Both collateral amounts can't be set to COMPUTED_AMOUNT");
337 }
338
339 let max_amount_slippage = args.max_amount_slippage;
340
341 let mut max_collateral_a = collateral_a;
342 let mut max_collateral_b = collateral_b;
343
344 let lower_sqrt_price: u128 = tick_index_to_sqrt_price(args.tick_lower_index).into();
345 let upper_sqrt_price: u128 = tick_index_to_sqrt_price(args.tick_upper_index).into();
346
347 if collateral_a == COMPUTED_AMOUNT {
348 if sqrt_price <= lower_sqrt_price {
349 return Err("sqrtPrice must be greater than lower_sqrt_price if collateral A is computed.");
350 } else if sqrt_price < upper_sqrt_price {
351 let liquidity = try_get_liquidity_from_b(collateral_b + borrow_b, lower_sqrt_price, sqrt_price)?;
352 let amount_a = try_get_token_a_from_liquidity(liquidity, sqrt_price, upper_sqrt_price, false)?;
353 collateral_a = (amount_a * collateral_b) / (collateral_b + borrow_b);
354 borrow_a = amount_a - collateral_a;
355 max_collateral_a = collateral_a + ((collateral_a as u128 * max_amount_slippage as u128) / HUNDRED_PERCENT as u128) as u64;
356 } else {
357 collateral_a = 0;
358 max_collateral_a = 0;
359 borrow_a = 0;
360 }
361 } else if collateral_b == COMPUTED_AMOUNT {
362 if sqrt_price <= lower_sqrt_price {
363 collateral_b = 0;
364 max_collateral_b = 0;
365 borrow_b = 0;
366 } else if sqrt_price < upper_sqrt_price {
367 let liquidity = try_get_liquidity_from_a(collateral_a + borrow_a, sqrt_price, upper_sqrt_price)?;
368 let amount_b = try_get_token_b_from_liquidity(liquidity, lower_sqrt_price, sqrt_price, false)?;
369 collateral_b = (amount_b * collateral_a) / (collateral_a + borrow_a);
370 borrow_b = amount_b - collateral_b;
371 max_collateral_b = collateral_b + ((collateral_b as u128 * max_amount_slippage as u128) / HUNDRED_PERCENT as u128) as u64;
372 } else {
373 return Err("sqrtPrice must be less than upper_sqrt_price if collateral B is computed.");
374 }
375 }
376
377 let protocol_fee_a = calculate_tuna_protocol_fee(collateral_a, borrow_a, args.protocol_fee_rate_on_collateral, args.protocol_fee_rate);
378 let provided_a = collateral_a + borrow_a - protocol_fee_a;
379
380 let protocol_fee_b = calculate_tuna_protocol_fee(collateral_b, borrow_b, args.protocol_fee_rate_on_collateral, args.protocol_fee_rate);
381 let provided_b = collateral_b + borrow_b - protocol_fee_b;
382
383 let mut swap_input = 0;
384 let mut swap_output = 0;
385 let mut swap_a_to_b = false;
386 let mut total_a = provided_a;
387 let mut total_b = provided_b;
388
389 if args.collateral_a != COMPUTED_AMOUNT && args.collateral_b != COMPUTED_AMOUNT {
390 let position_ratio = position_ratio_x64(sqrt_price.into(), args.tick_lower_index, args.tick_upper_index);
391 let ratio_a = position_ratio.ratio_a as f64 / Q64_RESOLUTION;
392 let ratio_b = position_ratio.ratio_b as f64 / Q64_RESOLUTION;
393
394 let price = (sqrt_price as f64 / Q64_RESOLUTION).powf(2.0);
395
396 let mut total = (provided_a as f64 * price + provided_b as f64) as u64;
398 total_a = (total as f64 * ratio_a / price) as u64;
399 total_b = (total as f64 * ratio_b) as u64;
400
401 let mut fee_a = 0;
402 let mut fee_b = 0;
403
404 if total_a < provided_a {
405 swap_input = provided_a - total_a;
406 fee_a = swap_input - try_apply_swap_fee(swap_input, args.swap_fee_rate)?;
407 swap_output = ((swap_input - fee_a) as f64 * price) as u64;
408 swap_a_to_b = true;
409 } else if total_b < provided_b {
410 swap_input = provided_b - total_b;
411 fee_b = swap_input - try_apply_swap_fee(swap_input, args.swap_fee_rate)?;
412 swap_output = ((swap_input - fee_b) as f64 / price) as u64;
413 swap_a_to_b = false;
414 }
415
416 total = ((provided_a - fee_a) as f64 * price) as u64 + provided_b - fee_b;
418 total_a = ((total as f64 * ratio_a) / price) as u64;
419 total_b = (total as f64 * ratio_b) as u64;
420 }
421
422 let min_total_a = total_a - ((total_a as u128 * max_amount_slippage as u128) / HUNDRED_PERCENT as u128) as u64;
423 let min_total_b = total_b - ((total_b as u128 * max_amount_slippage as u128) / HUNDRED_PERCENT as u128) as u64;
424
425 Ok(IncreaseLpPositionQuoteResult {
426 collateral_a,
427 collateral_b,
428 max_collateral_a,
429 max_collateral_b,
430 borrow_a,
431 borrow_b,
432 total_a,
433 total_b,
434 min_total_a,
435 min_total_b,
436 swap_input,
437 swap_output,
438 swap_a_to_b,
439 protocol_fee_a,
440 protocol_fee_b,
441 })
442}
443
444#[cfg(all(test, not(feature = "wasm")))]
445mod tests {
446 use crate::{
447 get_increase_lp_position_quote, get_lp_position_liquidation_prices, IncreaseLpPositionQuoteArgs, IncreaseLpPositionQuoteResult,
448 LiquidationPrices, COMPUTED_AMOUNT, HUNDRED_PERCENT,
449 };
450 use fusionamm_core::{price_to_sqrt_price, price_to_tick_index, tick_index_to_sqrt_price, try_get_liquidity_from_b};
451 use once_cell::sync::Lazy;
452
453 pub static TICK_LOWER_INDEX: Lazy<i32> = Lazy::new(|| price_to_tick_index(180.736, 6, 6));
454 pub static TICK_UPPER_INDEX: Lazy<i32> = Lazy::new(|| price_to_tick_index(225.66, 6, 6));
455 pub static SQRT_PRICE: Lazy<u128> = Lazy::new(|| price_to_sqrt_price(213.41, 6, 6));
456 pub static LIQUIDITY: Lazy<u128> =
457 Lazy::new(|| try_get_liquidity_from_b(10000_000_000, tick_index_to_sqrt_price(*TICK_LOWER_INDEX), *SQRT_PRICE).unwrap());
458
459 #[test]
460 fn test_liquidation_price_outside_range_lower() {
461 assert_eq!(
462 get_lp_position_liquidation_prices(
463 *TICK_LOWER_INDEX,
464 *TICK_UPPER_INDEX,
465 *LIQUIDITY,
466 0, 0, 0, 9807_000_000, HUNDRED_PERCENT * 83 / 100 ),
472 Ok(LiquidationPrices {
473 lower: 176.12815046153585,
474 upper: 0.0
475 })
476 );
477 }
478
479 #[test]
480 fn test_liquidation_price_outside_range_upper() {
481 assert_eq!(
482 get_lp_position_liquidation_prices(
483 *TICK_LOWER_INDEX,
484 *TICK_UPPER_INDEX,
485 *LIQUIDITY,
486 0, 0, 20_000_000, 0, HUNDRED_PERCENT * 83 / 100 ),
492 Ok(LiquidationPrices {
493 lower: 0.0,
494 upper: 562.219410388
495 })
496 );
497 }
498
499 #[test]
500 fn test_liquidation_price_outside_range_lower_and_upper() {
501 assert_eq!(
502 get_lp_position_liquidation_prices(
503 *TICK_LOWER_INDEX,
504 *TICK_UPPER_INDEX,
505 *LIQUIDITY,
506 0, 0, 10_000_000, 5000_000_000, HUNDRED_PERCENT * 83 / 100 ),
512 Ok(LiquidationPrices {
513 lower: 109.45458168998225,
514 upper: 624.4388207760001
515 })
516 );
517 }
518
519 #[test]
520 fn test_liquidation_price_inside_range_lower() {
521 assert_eq!(
522 get_lp_position_liquidation_prices(
523 *TICK_LOWER_INDEX,
524 *TICK_UPPER_INDEX,
525 *LIQUIDITY,
526 0, 0, 0, 11000_000_000, HUNDRED_PERCENT * 83 / 100 ),
532 Ok(LiquidationPrices {
533 lower: 204.60489065334323,
534 upper: 0.0
535 })
536 );
537 }
538
539 #[test]
540 fn test_liquidation_price_inside_range_upper() {
541 assert_eq!(
542 get_lp_position_liquidation_prices(
543 *TICK_LOWER_INDEX,
544 *TICK_UPPER_INDEX,
545 *LIQUIDITY,
546 0, 0, 51_000_000, 0, HUNDRED_PERCENT * 83 / 100 ),
552 Ok(LiquidationPrices {
553 lower: 0.0,
554 upper: 220.16318077637644
555 })
556 );
557 }
558
559 #[test]
560 fn test_liquidation_price_inside_range_lower_and_upper() {
561 assert_eq!(
562 get_lp_position_liquidation_prices(
563 *TICK_LOWER_INDEX,
564 *TICK_UPPER_INDEX,
565 *LIQUIDITY,
566 0, 0, 11_500_000, 8700_000_000, HUNDRED_PERCENT * 83 / 100 ),
572 Ok(LiquidationPrices {
573 lower: 210.75514596082337,
574 upper: 219.48595430071575
575 })
576 );
577 }
578
579 #[test]
580 fn test_lp_increase_quote_collateral_a_and_b_provided() {
581 assert_eq!(
582 get_increase_lp_position_quote(IncreaseLpPositionQuoteArgs {
583 collateral_a: 1000000,
584 collateral_b: 1000000,
585 borrow_a: 2000000,
586 borrow_b: 2000000,
587 tick_lower_index: price_to_tick_index(1.0, 1, 1),
588 sqrt_price: price_to_sqrt_price(2.0, 1, 1),
589 tick_upper_index: price_to_tick_index(4.0, 1, 1),
590 protocol_fee_rate: (HUNDRED_PERCENT / 100) as u16,
591 protocol_fee_rate_on_collateral: (HUNDRED_PERCENT / 100) as u16,
592 swap_fee_rate: 10000, max_amount_slippage: HUNDRED_PERCENT / 10,
594 }),
595 Ok(IncreaseLpPositionQuoteResult {
596 collateral_a: 1000000,
597 collateral_b: 1000000,
598 max_collateral_a: 1000000,
599 max_collateral_b: 1000000,
600 borrow_a: 2000000,
601 borrow_b: 2000000,
602 total_a: 2223701,
603 total_b: 4447744,
604 min_total_a: 2001331,
605 min_total_b: 4002970,
606 swap_input: 742586,
607 swap_output: 1470320,
608 swap_a_to_b: true,
609 protocol_fee_a: 30000,
610 protocol_fee_b: 30000
611 })
612 );
613 }
614
615 #[test]
616 fn test_lp_increase_quote_collateral_a_provided() {
617 assert_eq!(
618 get_increase_lp_position_quote(IncreaseLpPositionQuoteArgs {
619 collateral_a: 10000000,
620 collateral_b: 0,
621 borrow_a: 0,
622 borrow_b: 0,
623 tick_lower_index: price_to_tick_index(0.25, 6, 9),
624 sqrt_price: price_to_sqrt_price(0.5, 6, 9),
625 tick_upper_index: price_to_tick_index(1.0, 6, 9),
626 protocol_fee_rate: (HUNDRED_PERCENT / 100) as u16,
627 protocol_fee_rate_on_collateral: (HUNDRED_PERCENT / 100) as u16,
628 swap_fee_rate: 10000, max_amount_slippage: HUNDRED_PERCENT / 10,
630 }),
631 Ok(IncreaseLpPositionQuoteResult {
632 collateral_a: 10000000,
633 collateral_b: 0,
634 max_collateral_a: 10000000,
635 max_collateral_b: 0,
636 borrow_a: 0,
637 borrow_b: 0,
638 total_a: 4925137,
639 total_b: 2462680451,
640 min_total_a: 4432624,
641 min_total_b: 2216412406,
642 swap_input: 4950113,
643 swap_output: 2450305500,
644 swap_a_to_b: true,
645 protocol_fee_a: 100000,
646 protocol_fee_b: 0
647 })
648 );
649 }
650
651 #[test]
652 fn test_lp_increase_quote_collateral_a_provided_b_computed() {
653 assert_eq!(
654 get_increase_lp_position_quote(IncreaseLpPositionQuoteArgs {
655 collateral_a: 10000000,
656 collateral_b: COMPUTED_AMOUNT,
657 borrow_a: 2000000,
658 borrow_b: COMPUTED_AMOUNT,
659 tick_lower_index: price_to_tick_index(1.0, 1, 1),
660 sqrt_price: price_to_sqrt_price(3.0, 1, 1),
661 tick_upper_index: price_to_tick_index(4.0, 1, 1),
662 protocol_fee_rate: 0,
663 protocol_fee_rate_on_collateral: 0,
664 swap_fee_rate: 0,
665 max_amount_slippage: HUNDRED_PERCENT / 10,
666 }),
667 Ok(IncreaseLpPositionQuoteResult {
668 collateral_a: 10000000,
669 collateral_b: 94660495,
670 max_collateral_a: 10000000,
671 max_collateral_b: 104126544,
672 borrow_a: 2000000,
673 borrow_b: 18932100,
674 total_a: 12000000,
675 total_b: 113592595,
676 min_total_a: 10800000,
677 min_total_b: 102233336,
678 swap_input: 0,
679 swap_output: 0,
680 swap_a_to_b: false,
681 protocol_fee_a: 0,
682 protocol_fee_b: 0
683 })
684 );
685 }
686
687 #[test]
688 fn test_lp_increase_quote_collateral_a_computed_b_provided() {
689 assert_eq!(
690 get_increase_lp_position_quote(IncreaseLpPositionQuoteArgs {
691 collateral_a: COMPUTED_AMOUNT,
692 collateral_b: 1000000,
693 borrow_a: COMPUTED_AMOUNT,
694 borrow_b: 2000000,
695 tick_lower_index: price_to_tick_index(1.0, 1, 1),
696 sqrt_price: price_to_sqrt_price(3.0, 1, 1),
697 tick_upper_index: price_to_tick_index(4.0, 1, 1),
698 protocol_fee_rate: 0,
699 protocol_fee_rate_on_collateral: 0,
700 swap_fee_rate: 0,
701 max_amount_slippage: HUNDRED_PERCENT / 10,
702 }),
703 Ok(IncreaseLpPositionQuoteResult {
704 collateral_a: 105640,
705 collateral_b: 1000000,
706 max_collateral_a: 116204,
707 max_collateral_b: 1000000,
708 borrow_a: 211282,
709 borrow_b: 2000000,
710 total_a: 316922,
711 total_b: 3000000,
712 min_total_a: 285230,
713 min_total_b: 2700000,
714 swap_input: 0,
715 swap_output: 0,
716 swap_a_to_b: false,
717 protocol_fee_a: 0,
718 protocol_fee_b: 0
719 })
720 );
721 }
722
723 #[test]
724 fn test_lp_increase_quote_one_sided_collateral_a_provided_b_computed() {
725 assert_eq!(
726 get_increase_lp_position_quote(IncreaseLpPositionQuoteArgs {
727 collateral_a: 10000000,
728 collateral_b: COMPUTED_AMOUNT,
729 borrow_a: 2000000,
730 borrow_b: COMPUTED_AMOUNT,
731 tick_lower_index: price_to_tick_index(1.0, 1, 1),
732 sqrt_price: price_to_sqrt_price(0.5, 1, 1),
733 tick_upper_index: price_to_tick_index(4.0, 1, 1),
734 protocol_fee_rate: 0,
735 protocol_fee_rate_on_collateral: 0,
736 swap_fee_rate: 0,
737 max_amount_slippage: HUNDRED_PERCENT / 10,
738 }),
739 Ok(IncreaseLpPositionQuoteResult {
740 collateral_a: 10000000,
741 collateral_b: 0,
742 max_collateral_a: 10000000,
743 max_collateral_b: 0,
744 borrow_a: 2000000,
745 borrow_b: 0,
746 total_a: 12000000,
747 total_b: 0,
748 min_total_a: 10800000,
749 min_total_b: 0,
750 swap_input: 0,
751 swap_output: 0,
752 swap_a_to_b: false,
753 protocol_fee_a: 0,
754 protocol_fee_b: 0
755 })
756 );
757 }
758
759 #[test]
760 fn test_lp_increase_quote_one_sided_collateral_a_computed_b_provided() {
761 assert_eq!(
762 get_increase_lp_position_quote(IncreaseLpPositionQuoteArgs {
763 collateral_a: COMPUTED_AMOUNT,
764 collateral_b: 1000000,
765 borrow_a: COMPUTED_AMOUNT,
766 borrow_b: 2000000,
767 tick_lower_index: price_to_tick_index(1.0, 1, 1),
768 sqrt_price: price_to_sqrt_price(5.0, 1, 1),
769 tick_upper_index: price_to_tick_index(4.0, 1, 1),
770 protocol_fee_rate: 0,
771 protocol_fee_rate_on_collateral: 0,
772 swap_fee_rate: 0,
773 max_amount_slippage: HUNDRED_PERCENT / 10,
774 }),
775 Ok(IncreaseLpPositionQuoteResult {
776 collateral_a: 0,
777 collateral_b: 1000000,
778 max_collateral_a: 0,
779 max_collateral_b: 1000000,
780 borrow_a: 0,
781 borrow_b: 2000000,
782 total_a: 0,
783 total_b: 3000000,
784 min_total_a: 0,
785 min_total_b: 2700000,
786 swap_input: 0,
787 swap_output: 0,
788 swap_a_to_b: false,
789 protocol_fee_a: 0,
790 protocol_fee_b: 0
791 })
792 );
793 }
794}