Skip to content

Commit 9cfe4ff

Browse files
authored
use the slippage for the price from oracle to limit internal swap (AcalaNetwork#1285)
* dex remove slippage check * remove slippage limit when internal swap * use the slippage for price of oracle to limit the internal swap
1 parent 407e5a7 commit 9cfe4ff

File tree

22 files changed

+315
-248
lines changed

22 files changed

+315
-248
lines changed

modules/auction-manager/src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,6 @@ impl<T: Config> Pallet<T> {
572572
< T::DEX::get_swap_target_amount(
573573
&[collateral_auction.currency_id, T::GetStableCurrencyId::get()],
574574
collateral_auction.amount,
575-
None,
576575
)
577576
.unwrap_or_default())
578577
{
@@ -582,7 +581,6 @@ impl<T: Config> Pallet<T> {
582581
collateral_auction.amount,
583582
Zero::zero(),
584583
None,
585-
None,
586584
true,
587585
) {
588586
// swap successfully, will not deal

modules/auction-manager/src/tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ fn collateral_auction_end_handler_without_bid() {
187187
0,
188188
false
189189
));
190-
assert_eq!(DEXModule::get_swap_target_amount(&[BTC, AUSD], 100, None).unwrap(), 500);
190+
assert_eq!(DEXModule::get_swap_target_amount(&[BTC, AUSD], 100).unwrap(), 500);
191191

192192
assert_ok!(AuctionManagerModule::new_collateral_auction(&ALICE, BTC, 100, 200));
193193
assert_eq!(CDPTreasuryModule::total_collaterals(BTC), 100);
@@ -318,7 +318,7 @@ fn collateral_auction_end_handler_by_dex_which_target_not_zero() {
318318
0,
319319
false
320320
));
321-
assert_eq!(DEXModule::get_swap_target_amount(&[BTC, AUSD], 100, None).unwrap(), 500);
321+
assert_eq!(DEXModule::get_swap_target_amount(&[BTC, AUSD], 100).unwrap(), 500);
322322

323323
assert_eq!(CDPTreasuryModule::total_collaterals(BTC), 100);
324324
assert_eq!(AuctionManagerModule::total_target_in_auction(), 200);

modules/cdp-engine/src/lib.rs

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,9 @@ pub mod module {
153153
#[pallet::constant]
154154
type GetStableCurrencyId: Get<CurrencyId>;
155155

156-
/// The max slippage allowed when liquidate an unsafe CDP by swap with
157-
/// DEX
156+
/// When swap with DEX, the acceptable max slippage for the price from oracle.
158157
#[pallet::constant]
159-
type MaxSlippageSwapWithDEX: Get<Ratio>;
158+
type MaxSwapSlippageCompareToOracle: Get<Ratio>;
160159

161160
/// The CDP treasury to maintain bad debts and surplus generated by CDPs
162161
type CDPTreasury: CDPTreasuryExtended<Self::AccountId, Balance = Balance, CurrencyId = CurrencyId>;
@@ -806,7 +805,6 @@ impl<T: Config> Pallet<T> {
806805
currency_id,
807806
collateral,
808807
debit_value,
809-
None,
810808
maybe_path,
811809
false,
812810
)?;
@@ -842,16 +840,23 @@ impl<T: Config> Pallet<T> {
842840

843841
let bad_debt_value = Self::get_debit_value(currency_id, debit);
844842
let target_stable_amount = Self::get_liquidation_penalty(currency_id).saturating_mul_acc_int(bad_debt_value);
845-
846-
// try use collateral to swap enough stable token in DEX when the price impact
847-
// is below the limit, otherwise create collateral auctions.
848843
let liquidation_strategy = (|| -> Result<LiquidationStrategy, DispatchError> {
849-
// swap exact stable with DEX in limit of price impact
844+
// calculate the supply limit by slippage limit for the price of oracle,
845+
let max_supply_limit = Ratio::one()
846+
.saturating_sub(T::MaxSwapSlippageCompareToOracle::get())
847+
.reciprocal()
848+
.unwrap_or_else(Ratio::max_value)
849+
.saturating_mul_int(
850+
T::PriceSource::get_relative_price(T::GetStableCurrencyId::get(), currency_id)
851+
.expect("the oracle price should be avalible because liquidation are triggered by it.")
852+
.saturating_mul_int(target_stable_amount),
853+
);
854+
855+
// try use collateral to swap enough stable token in DEX.
850856
if let Ok(actual_supply_collateral) = <T as Config>::CDPTreasury::swap_collateral_to_exact_stable(
851857
currency_id,
852-
collateral,
858+
collateral.min(max_supply_limit),
853859
target_stable_amount,
854-
Some(T::MaxSlippageSwapWithDEX::get()),
855860
None,
856861
false,
857862
) {
@@ -862,19 +867,19 @@ impl<T: Config> Pallet<T> {
862867

863868
<T as Config>::CDPTreasury::withdraw_collateral(&who, currency_id, refund_collateral_amount)?;
864869

865-
return Ok(LiquidationStrategy::Exchange);
866-
}
867-
868-
// create collateral auctions by cdp treasury
869-
<T as Config>::CDPTreasury::create_collateral_auctions(
870-
currency_id,
871-
collateral,
872-
target_stable_amount,
873-
who.clone(),
874-
true,
875-
)?;
870+
Ok(LiquidationStrategy::Exchange)
871+
} else {
872+
// if swap failed, create collateral auctions by cdp treasury
873+
<T as Config>::CDPTreasury::create_collateral_auctions(
874+
currency_id,
875+
collateral,
876+
target_stable_amount,
877+
who.clone(),
878+
true,
879+
)?;
876880

877-
Ok(LiquidationStrategy::Auction)
881+
Ok(LiquidationStrategy::Auction)
882+
}
878883
})()?;
879884

880885
Self::deposit_event(Event::LiquidateUnsafeCDP(

modules/cdp-engine/src/mock.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ parameter_types! {
268268
pub DefaultDebitExchangeRate: ExchangeRate = ExchangeRate::one();
269269
pub DefaultLiquidationPenalty: Rate = Rate::saturating_from_rational(10, 100);
270270
pub const MinimumDebitValue: Balance = 2;
271-
pub MaxSlippageSwapWithDEX: Ratio = Ratio::saturating_from_rational(50, 100);
271+
pub MaxSwapSlippageCompareToOracle: Ratio = Ratio::saturating_from_rational(50, 100);
272272
pub const UnsignedPriority: u64 = 1 << 20;
273273
pub CollateralCurrencyIds: Vec<CurrencyId> = vec![BTC, DOT];
274274
}
@@ -284,7 +284,7 @@ impl Config for Runtime {
284284
type GetStableCurrencyId = GetStableCurrencyId;
285285
type CDPTreasury = CDPTreasuryModule;
286286
type UpdateOrigin = EnsureSignedBy<One, AccountId>;
287-
type MaxSlippageSwapWithDEX = MaxSlippageSwapWithDEX;
287+
type MaxSwapSlippageCompareToOracle = MaxSwapSlippageCompareToOracle;
288288
type UnsignedPriority = UnsignedPriority;
289289
type EmergencyShutdown = MockEmergencyShutdown;
290290
type UnixTime = Timestamp;

modules/cdp-engine/src/tests.rs

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use frame_support::{assert_noop, assert_ok};
2525
use mock::{Event, *};
2626
use orml_traits::MultiCurrency;
2727
use sp_runtime::traits::BadOrigin;
28+
use support::DEXManager;
2829

2930
#[test]
3031
fn is_cdp_unsafe_work() {
@@ -452,6 +453,126 @@ fn liquidate_unsafe_cdp_by_collateral_auction() {
452453
});
453454
}
454455

456+
#[test]
457+
fn liquidate_unsafe_cdp_by_collateral_auction_when_limited_by_slippage() {
458+
ExtBuilder::default().build().execute_with(|| {
459+
System::set_block_number(1);
460+
assert_ok!(CDPEngineModule::set_collateral_params(
461+
Origin::signed(1),
462+
BTC,
463+
Change::NewValue(Some(Rate::saturating_from_rational(1, 100000))),
464+
Change::NewValue(Some(Ratio::saturating_from_rational(3, 2))),
465+
Change::NewValue(Some(Rate::saturating_from_rational(2, 10))),
466+
Change::NewValue(Some(Ratio::saturating_from_rational(9, 5))),
467+
Change::NewValue(10000),
468+
));
469+
assert_ok!(DEXModule::add_liquidity(
470+
Origin::signed(CAROL),
471+
BTC,
472+
AUSD,
473+
100,
474+
121,
475+
0,
476+
false
477+
));
478+
assert_eq!(DEXModule::get_liquidity_pool(BTC, AUSD), (100, 121));
479+
480+
assert_ok!(CDPEngineModule::adjust_position(&ALICE, BTC, 100, 50));
481+
assert_eq!(Currencies::free_balance(BTC, &ALICE), 900);
482+
assert_eq!(Currencies::free_balance(AUSD, &ALICE), 50);
483+
assert_eq!(LoansModule::positions(BTC, ALICE).debit, 50);
484+
assert_eq!(LoansModule::positions(BTC, ALICE).collateral, 100);
485+
486+
assert_ok!(CDPEngineModule::set_collateral_params(
487+
Origin::signed(1),
488+
BTC,
489+
Change::NoChange,
490+
Change::NewValue(Some(Ratio::max_value())),
491+
Change::NoChange,
492+
Change::NoChange,
493+
Change::NoChange,
494+
));
495+
496+
// pool is enough, but slippage limit the swap
497+
MockPriceSource::set_relative_price(Some(Price::saturating_from_rational(1, 2)));
498+
assert_eq!(DEXModule::get_swap_supply_amount(&[BTC, AUSD], 60), Some(99));
499+
assert_eq!(DEXModule::get_swap_target_amount(&[BTC, AUSD], 100), Some(60));
500+
assert_ok!(CDPEngineModule::liquidate_unsafe_cdp(ALICE, BTC));
501+
System::assert_last_event(Event::CDPEngineModule(crate::Event::LiquidateUnsafeCDP(
502+
BTC,
503+
ALICE,
504+
100,
505+
50,
506+
LiquidationStrategy::Auction,
507+
)));
508+
509+
assert_eq!(DEXModule::get_liquidity_pool(BTC, AUSD), (100, 121));
510+
assert_eq!(CDPTreasuryModule::debit_pool(), 50);
511+
assert_eq!(Currencies::free_balance(BTC, &ALICE), 900);
512+
assert_eq!(Currencies::free_balance(AUSD, &ALICE), 50);
513+
assert_eq!(LoansModule::positions(BTC, ALICE).debit, 0);
514+
assert_eq!(LoansModule::positions(BTC, ALICE).collateral, 0);
515+
});
516+
}
517+
518+
#[test]
519+
fn liquidate_unsafe_cdp_by_swap() {
520+
ExtBuilder::default().build().execute_with(|| {
521+
System::set_block_number(1);
522+
assert_ok!(CDPEngineModule::set_collateral_params(
523+
Origin::signed(1),
524+
BTC,
525+
Change::NewValue(Some(Rate::saturating_from_rational(1, 100000))),
526+
Change::NewValue(Some(Ratio::saturating_from_rational(3, 2))),
527+
Change::NewValue(Some(Rate::saturating_from_rational(2, 10))),
528+
Change::NewValue(Some(Ratio::saturating_from_rational(9, 5))),
529+
Change::NewValue(10000),
530+
));
531+
assert_ok!(DEXModule::add_liquidity(
532+
Origin::signed(CAROL),
533+
BTC,
534+
AUSD,
535+
100,
536+
121,
537+
0,
538+
false
539+
));
540+
assert_eq!(DEXModule::get_liquidity_pool(BTC, AUSD), (100, 121));
541+
542+
assert_ok!(CDPEngineModule::adjust_position(&ALICE, BTC, 100, 50));
543+
assert_eq!(Currencies::free_balance(BTC, &ALICE), 900);
544+
assert_eq!(Currencies::free_balance(AUSD, &ALICE), 50);
545+
assert_eq!(LoansModule::positions(BTC, ALICE).debit, 50);
546+
assert_eq!(LoansModule::positions(BTC, ALICE).collateral, 100);
547+
548+
assert_ok!(CDPEngineModule::set_collateral_params(
549+
Origin::signed(1),
550+
BTC,
551+
Change::NoChange,
552+
Change::NewValue(Some(Ratio::max_value())),
553+
Change::NoChange,
554+
Change::NoChange,
555+
Change::NoChange,
556+
));
557+
558+
assert_ok!(CDPEngineModule::liquidate_unsafe_cdp(ALICE, BTC));
559+
System::assert_last_event(Event::CDPEngineModule(crate::Event::LiquidateUnsafeCDP(
560+
BTC,
561+
ALICE,
562+
100,
563+
50,
564+
LiquidationStrategy::Exchange,
565+
)));
566+
567+
assert_eq!(DEXModule::get_liquidity_pool(BTC, AUSD), (199, 61));
568+
assert_eq!(CDPTreasuryModule::debit_pool(), 50);
569+
assert_eq!(Currencies::free_balance(BTC, &ALICE), 901);
570+
assert_eq!(Currencies::free_balance(AUSD, &ALICE), 50);
571+
assert_eq!(LoansModule::positions(BTC, ALICE).debit, 0);
572+
assert_eq!(LoansModule::positions(BTC, ALICE).collateral, 0);
573+
});
574+
}
575+
455576
#[test]
456577
fn get_interest_rate_per_sec_work() {
457578
ExtBuilder::default().build().execute_with(|| {

modules/cdp-treasury/src/lib.rs

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,6 @@ impl<T: Config> CDPTreasuryExtended<T::AccountId> for Pallet<T> {
333333
currency_id: CurrencyId,
334334
supply_amount: Balance,
335335
min_target_amount: Balance,
336-
price_impact_limit: Option<Ratio>,
337336
maybe_path: Option<&[CurrencyId]>,
338337
collateral_in_auction: bool,
339338
) -> sp_std::result::Result<Balance, DispatchError> {
@@ -364,13 +363,7 @@ impl<T: Config> CDPTreasuryExtended<T::AccountId> for Pallet<T> {
364363
}
365364
};
366365

367-
T::DEX::swap_with_exact_supply(
368-
&Self::account_id(),
369-
swap_path,
370-
supply_amount,
371-
min_target_amount,
372-
price_impact_limit,
373-
)
366+
T::DEX::swap_with_exact_supply(&Self::account_id(), swap_path, supply_amount, min_target_amount)
374367
}
375368

376369
/// swap collateral which not in auction to get exact stable,
@@ -379,7 +372,6 @@ impl<T: Config> CDPTreasuryExtended<T::AccountId> for Pallet<T> {
379372
currency_id: CurrencyId,
380373
max_supply_amount: Balance,
381374
target_amount: Balance,
382-
price_impact_limit: Option<Ratio>,
383375
maybe_path: Option<&[CurrencyId]>,
384376
collateral_in_auction: bool,
385377
) -> sp_std::result::Result<Balance, DispatchError> {
@@ -410,13 +402,7 @@ impl<T: Config> CDPTreasuryExtended<T::AccountId> for Pallet<T> {
410402
}
411403
};
412404

413-
T::DEX::swap_with_exact_target(
414-
&Self::account_id(),
415-
swap_path,
416-
target_amount,
417-
max_supply_amount,
418-
price_impact_limit,
419-
)
405+
T::DEX::swap_with_exact_target(&Self::account_id(), swap_path, target_amount, max_supply_amount)
420406
}
421407

422408
fn create_collateral_auctions(

modules/cdp-treasury/src/tests.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -221,33 +221,32 @@ fn swap_collateral_to_exact_stable_work() {
221221
assert_eq!(CDPTreasuryModule::total_collaterals_not_in_auction(BTC), 200);
222222

223223
assert_noop!(
224-
CDPTreasuryModule::swap_collateral_to_exact_stable(BTC, 201, 499, None, None, false),
224+
CDPTreasuryModule::swap_collateral_to_exact_stable(BTC, 201, 499, None, false),
225225
Error::<Runtime>::CollateralNotEnough,
226226
);
227227

228228
assert_ok!(CDPTreasuryModule::swap_collateral_to_exact_stable(
229-
BTC, 100, 499, None, None, false
229+
BTC, 100, 499, None, false
230230
));
231231
assert_eq!(CDPTreasuryModule::surplus_pool(), 499);
232232
assert_eq!(CDPTreasuryModule::total_collaterals_not_in_auction(BTC), 100);
233233

234234
assert_noop!(
235-
CDPTreasuryModule::swap_collateral_to_exact_stable(BTC, 100, 199, None, Some(&vec![BTC]), false),
235+
CDPTreasuryModule::swap_collateral_to_exact_stable(BTC, 100, 199, Some(&vec![BTC]), false),
236236
Error::<Runtime>::InvalidSwapPath
237237
);
238238
assert_noop!(
239-
CDPTreasuryModule::swap_collateral_to_exact_stable(BTC, 100, 199, None, Some(&vec![BTC, DOT]), false),
239+
CDPTreasuryModule::swap_collateral_to_exact_stable(BTC, 100, 199, Some(&vec![BTC, DOT]), false),
240240
Error::<Runtime>::InvalidSwapPath
241241
);
242242
assert_noop!(
243-
CDPTreasuryModule::swap_collateral_to_exact_stable(BTC, 100, 199, None, Some(&vec![DOT, AUSD]), false),
243+
CDPTreasuryModule::swap_collateral_to_exact_stable(BTC, 100, 199, Some(&vec![DOT, AUSD]), false),
244244
Error::<Runtime>::InvalidSwapPath
245245
);
246246
assert_ok!(CDPTreasuryModule::swap_collateral_to_exact_stable(
247247
BTC,
248248
100,
249249
10,
250-
None,
251250
Some(&vec![BTC, DOT, AUSD]),
252251
false
253252
));
@@ -291,7 +290,7 @@ fn swap_exact_collateral_to_stable_work() {
291290
assert_eq!(CDPTreasuryModule::total_collaterals(BTC), 200);
292291

293292
assert_noop!(
294-
CDPTreasuryModule::swap_exact_collateral_to_stable(BTC, 200, 100, None, None, true),
293+
CDPTreasuryModule::swap_exact_collateral_to_stable(BTC, 200, 100, None, true),
295294
Error::<Runtime>::CollateralNotEnough,
296295
);
297296

@@ -304,29 +303,28 @@ fn swap_exact_collateral_to_stable_work() {
304303
assert_eq!(MockAuctionManager::get_total_collateral_in_auction(BTC), 200);
305304

306305
assert_ok!(CDPTreasuryModule::swap_exact_collateral_to_stable(
307-
BTC, 100, 400, None, None, true
306+
BTC, 100, 400, None, true
308307
));
309308
assert_eq!(CDPTreasuryModule::surplus_pool(), 500);
310309
assert_eq!(CDPTreasuryModule::total_collaterals(BTC), 100);
311310

312311
assert_noop!(
313-
CDPTreasuryModule::swap_exact_collateral_to_stable(BTC, 100, 199, None, Some(&vec![BTC]), true),
312+
CDPTreasuryModule::swap_exact_collateral_to_stable(BTC, 100, 199, Some(&vec![BTC]), true),
314313
Error::<Runtime>::InvalidSwapPath
315314
);
316315
assert_noop!(
317-
CDPTreasuryModule::swap_exact_collateral_to_stable(BTC, 100, 199, None, Some(&vec![BTC, DOT]), true),
316+
CDPTreasuryModule::swap_exact_collateral_to_stable(BTC, 100, 199, Some(&vec![BTC, DOT]), true),
318317
Error::<Runtime>::InvalidSwapPath
319318
);
320319
assert_noop!(
321-
CDPTreasuryModule::swap_exact_collateral_to_stable(BTC, 100, 199, None, Some(&vec![DOT, AUSD]), true),
320+
CDPTreasuryModule::swap_exact_collateral_to_stable(BTC, 100, 199, Some(&vec![DOT, AUSD]), true),
322321
Error::<Runtime>::InvalidSwapPath
323322
);
324323

325324
assert_ok!(CDPTreasuryModule::swap_exact_collateral_to_stable(
326325
BTC,
327326
100,
328327
10,
329-
None,
330328
Some(&vec![BTC, DOT, AUSD]),
331329
true
332330
));

0 commit comments

Comments
 (0)