@@ -53,6 +53,11 @@ fun test_liquidation_quote_debt_partial_ok() {
5353 test_liquidation_quote_debt_partial ();
5454}
5555
56+ #[test]
57+ fun test_liquidation_base_debt_default_ok () {
58+ test_liquidation_base_debt_default ();
59+ }
60+
5661#[test]
5762fun test_liquidation_base_debt_ok () {
5863 test_liquidation_base_debt ();
@@ -427,7 +432,7 @@ fun test_liquidation_quote_debt_partial() {
427432 cleanup_margin_test (registry, admin_cap, maintainer_cap, clock, scenario);
428433}
429434
430- fun test_liquidation_base_debt () {
435+ fun test_liquidation_base_debt_default () {
431436 let (
432437 mut scenario,
433438 clock,
@@ -509,7 +514,7 @@ fun test_liquidation_base_debt() {
509514 // Remaining_repay_coin = 1 - 0.3597 = 0.6403 BTC
510515 // The liquidator should receive 0.3492 * 1.05 = 0.36666 BTC = 1100 USD. The net profit is 0.36666 - 0.3597 = 0.00696 BTC
511516 // 0.00696 BTC / 0.3492 BTC = 2% reward
512- // The 0.2 BTC will be used first. 1100 - 0.2 * 3000 = 500 USD. Then the remaining 500 USD will be taken as USDC..
517+ // The 0.2 BTC will be used first. 1100 - 0.2 * 3000 = 500 USD. Then the remaining 500 USD will be taken as USDC.
513518 let (base_coin, quote_coin, remaining_repay_coin) = mm.liquidate <BTC , USDC , BTC >(
514519 ®istry,
515520 &btc_price_3000,
@@ -536,6 +541,115 @@ fun test_liquidation_base_debt() {
536541 cleanup_margin_test (registry, admin_cap, maintainer_cap, clock, scenario);
537542}
538543
544+ fun test_liquidation_base_debt () {
545+ let (
546+ mut scenario,
547+ clock,
548+ admin_cap,
549+ maintainer_cap,
550+ btc_pool_id,
551+ usdc_pool_id,
552+ _pool_id,
553+ ) = setup_btc_usd_margin_trading ();
554+
555+ let btc_price = build_btc_price_info_object (&mut scenario, 500 , &clock);
556+ let usdc_price = build_demo_usdc_price_info_object (&mut scenario, &clock);
557+
558+ scenario.next_tx (test_constants::user1 ());
559+ let mut pool = scenario.take_shared <Pool <BTC , USDC >>();
560+ let registry = scenario.take_shared <MarginRegistry >();
561+ margin_manager::new <BTC , USDC >(&pool, ®istry, &clock, scenario.ctx ());
562+
563+ scenario.next_tx (test_constants::user1 ());
564+ let mut mm = scenario.take_shared <MarginManager <BTC , USDC >>();
565+ let usdc_pool = scenario.take_shared_by_id <MarginPool <USDC >>(usdc_pool_id);
566+ let mut btc_pool = scenario.take_shared_by_id <MarginPool <BTC >>(btc_pool_id);
567+
568+ // Deposit 500 USDC
569+ mm.deposit <BTC , USDC , USDC >(
570+ ®istry,
571+ mint_coin <USDC >(500 * usdc_multiplier (), scenario.ctx ()),
572+ scenario.ctx (),
573+ );
574+
575+ // Borrow $200 BTC (0.4 BTC). Risk ratio = (500 + 200) / 200 = 3.5
576+ mm.borrow_base <BTC , USDC >(
577+ ®istry,
578+ &mut btc_pool,
579+ &btc_price,
580+ &usdc_price,
581+ &pool,
582+ 40000000 ,
583+ &clock,
584+ scenario.ctx (),
585+ );
586+
587+ assert ! (
588+ mm.risk_ratio (®istry, &btc_price, &usdc_price, &pool, &btc_pool, &clock) == 3_500_000_000 ,
589+ 0 ,
590+ );
591+
592+ // Now we withdraw 0.2 BTC. This should be allowed since risk ratio >= 2;
593+ let withdraw_btc = mm.withdraw <BTC , USDC , BTC >(
594+ ®istry,
595+ &btc_pool,
596+ &usdc_pool,
597+ &btc_price,
598+ &usdc_price,
599+ &pool,
600+ 20000000 ,
601+ &clock,
602+ scenario.ctx (),
603+ );
604+ withdraw_btc.burn_for_testing ();
605+
606+ // Risk ratio is now (500 + 100) / 200 = 3.0
607+ assert ! (
608+ mm.risk_ratio (®istry, &btc_price, &usdc_price, &pool, &btc_pool, &clock) == 3_000_000_000 ,
609+ 0 ,
610+ );
611+
612+ // Perform liquidation and check rewards
613+ scenario.next_tx (test_constants::liquidator ());
614+
615+ // We now have 0.2 BTC ($440) and 500 USDC ($500), with a debt of 0.4 BTC ($880)
616+ // At BTC price 2200, Risk ratio = (440 + 500) / 880 = 1.0681818 < 1.1, can liquidate
617+ let repay_coin = mint_coin <BTC >(1 * btc_multiplier (), scenario.ctx ());
618+ let btc_price_2200 = build_btc_price_info_object (&mut scenario, 2200 , &clock);
619+
620+ assert ! (
621+ mm.risk_ratio (®istry, &btc_price_2200, &usdc_price, &pool, &btc_pool, &clock) == 1_068_181_825 ,
622+ 0 ,
623+ );
624+
625+ // 0.37454 BTC will be used to liquidate. 0.3636 BTC for repayment of loan, 0.01094 BTC for pool liquidation fee.
626+ // Since 0.3636 BTC is used for repayment, the liquidator should receive 0.3636 * 0.02 = 0.007272 as a reward.
627+ // Risk ratio after liquidation = (940 - 824 - 16) / (880 - 800) = 1.25
628+ // Remaining_repay_coin = 1 - 0.37454 = 0.62546 BTC
629+ // The liquidator should receive 0.3636 * 1.05 = 0.38178 BTC = 840 USD.
630+ // The 0.2 BTC will be used first (0.2 BTC = 440 USD). Then the remaining 400 USD will be taken as USDC.
631+ let (base_coin, quote_coin, remaining_repay_coin) = mm.liquidate <BTC , USDC , BTC >(
632+ ®istry,
633+ &btc_price_2200,
634+ &usdc_price,
635+ &mut btc_pool,
636+ &mut pool,
637+ repay_coin,
638+ &clock,
639+ scenario.ctx (),
640+ );
641+
642+ assert ! (base_coin.value () == 20000000 , 0 ); // 0.2 BTC
643+ assert ! (quote_coin.value () == 399999930 , 0 ); // ~400 USDC
644+ assert ! (remaining_repay_coin.value () == 62545457 , 0 ); // 0.62545457 BTC
645+
646+ destroy_3 ! (remaining_repay_coin, base_coin, quote_coin);
647+ return_shared_3 ! (mm, usdc_pool, pool);
648+ destroy_3 ! (btc_price, usdc_price, btc_price_2200);
649+ destroy (btc_pool);
650+ cleanup_margin_test (registry, admin_cap, maintainer_cap, clock, scenario);
651+ }
652+
539653/// Test liquidation with BTC/SUI pair where both assets are volatile
540654/// BTC: 8 decimals, SUI: 9 decimals
541655fun test_btc_sui_liquidation (error_code: u64 ) {
0 commit comments