Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

optimize internal swap #1704

Merged
merged 12 commits into from
Dec 18, 2021
144 changes: 51 additions & 93 deletions modules/auction-manager/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ use sp_runtime::{
DispatchError, DispatchResult, FixedPointNumber, RuntimeDebug,
};
use sp_std::prelude::*;
use support::{AuctionManager, CDPTreasury, CDPTreasuryExtended, DEXManager, EmergencyShutdown, PriceProvider, Rate};
use support::{AuctionManager, CDPTreasury, CDPTreasuryExtended, EmergencyShutdown, PriceProvider, Rate, SwapLimit};

mod mock;
mod tests;
Expand Down Expand Up @@ -158,9 +158,6 @@ pub mod module {
/// CDP treasury to escrow assets related to auction
type CDPTreasury: CDPTreasuryExtended<Self::AccountId, Balance = Balance, CurrencyId = CurrencyId>;

/// DEX to get exchange info
type DEX: DEXManager<Self::AccountId, CurrencyId, Balance>;

/// The price source of currencies
type PriceSource: PriceProvider<CurrencyId>;

Expand All @@ -174,12 +171,6 @@ pub mod module {
/// Emergency shutdown.
type EmergencyShutdown: EmergencyShutdown;

/// The default parital path list for DEX to directly take auction,
/// Note: the path is parital, the whole swap path is collateral currency id concat
/// the partial path. And the list is sorted, DEX try to take auction by order.
#[pallet::constant]
type DefaultSwapParitalPathList: Get<Vec<Vec<CurrencyId>>>;

/// Weight information for the extrinsics in this module.
type WeightInfo: WeightInfo;
}
Expand Down Expand Up @@ -263,12 +254,6 @@ pub mod module {
}
}
}

fn integrity_test() {
assert!(T::DefaultSwapParitalPathList::get()
.iter()
.all(|path| !path.is_empty() && path[path.len() - 1] == T::GetStableCurrencyId::get()));
}
}

#[pallet::call]
Expand Down Expand Up @@ -597,85 +582,58 @@ impl<T: Config> Pallet<T> {

// if bid_price doesn't reach target, DEX will try trading with DEX to get better result.
if !collateral_auction.in_reverse_stage(bid_price) {
let default_swap_parital_path_list: Vec<Vec<CurrencyId>> = T::DefaultSwapParitalPathList::get();

// iterator default_swap_parital_path_list to try swap until swap succeed.
for partial_path in default_swap_parital_path_list {
let partial_path_len = partial_path.len();

// check collateral currency_id and partial_path can form a valid swap path.
if partial_path_len > 0 && collateral_auction.currency_id != partial_path[0] {
let mut swap_path = vec![collateral_auction.currency_id];
swap_path.extend(partial_path);

// DEX must take a higher bid.
if bid_price
< T::DEX::get_swap_target_amount(&swap_path, collateral_auction.amount).unwrap_or_default()
{
// try swap collateral in auction with DEX to get stable.
if let Ok(stable_amount) = T::CDPTreasury::swap_exact_collateral_to_stable(
collateral_auction.currency_id,
collateral_auction.amount,
Zero::zero(),
&swap_path,
true,
) {
// swap successfully, will not deal.
should_deal = false;

// refund stable currency to the last bidder, it shouldn't fail and affect the
// process. but even it failed, just the winner did not get the bid price. it
// can be fixed by treasury council.
if let Some(bidder) = maybe_bidder.as_ref() {
let res = T::CDPTreasury::issue_debit(bidder, bid_price, false);
if let Err(e) = res {
log::warn!(
target: "auction-manager",
"issue_debit: failed to issue stable {:?} to {:?}: {:?}. \
This is unexpected but should be safe",
bid_price, bidder, e
);
debug_assert!(false);
}
}

// DEX bid is higher than the target amount of auction,
// need refund extra stable currency to recipient.
if collateral_auction.in_reverse_stage(stable_amount) {
let refund_amount = stable_amount
.checked_sub(collateral_auction.target)
.expect("ensured stable_amount > target; qed");
// it shouldn't fail and affect the process.
// but even it failed, just the winner did not get the refund amount. it can be
// fixed by treasury council.
let res = T::CDPTreasury::issue_debit(
&collateral_auction.refund_recipient,
refund_amount,
false,
);
if let Err(e) = res {
log::warn!(
target: "auction-manager",
"issue_debit: failed to issue stable {:?} to {:?}: {:?}. \
This is unexpected but should be safe",
refund_amount, collateral_auction.refund_recipient, e
);
debug_assert!(false);
}
}

Self::deposit_event(Event::DEXTakeCollateralAuction(
auction_id,
collateral_auction.currency_id,
collateral_auction.amount,
stable_amount,
));

// break loop.
break;
}
// try swap collateral in auction with DEX to get stable at least bid_price.
if let Ok((_, stable_amount)) = T::CDPTreasury::swap_collateral_to_stable(
collateral_auction.currency_id,
SwapLimit::ExactSupply(collateral_auction.amount, bid_price),
true,
) {
// swap successfully, will not deal.
should_deal = false;

// refund stable currency to the last bidder, it shouldn't fail and affect the
// process. but even it failed, just the winner did not get the bid price. it
// can be fixed by treasury council.
if let Some(bidder) = maybe_bidder.as_ref() {
let res = T::CDPTreasury::issue_debit(bidder, bid_price, false);
if let Err(e) = res {
log::warn!(
target: "auction-manager",
"issue_debit: failed to issue stable {:?} to {:?}: {:?}. \
This is unexpected but should be safe",
bid_price, bidder, e
);
debug_assert!(false);
}
}

// DEX bid is higher than the target amount of auction,
// need refund extra stable currency to recipient.
if collateral_auction.in_reverse_stage(stable_amount) {
let refund_amount = stable_amount
.checked_sub(collateral_auction.target)
.expect("ensured stable_amount > target; qed");
// it shouldn't fail and affect the process.
// but even it failed, just the winner did not get the refund amount. it can be
// fixed by treasury council.
let res = T::CDPTreasury::issue_debit(&collateral_auction.refund_recipient, refund_amount, false);
if let Err(e) = res {
log::warn!(
target: "auction-manager",
"issue_debit: failed to issue stable {:?} to {:?}: {:?}. \
This is unexpected but should be safe",
refund_amount, collateral_auction.refund_recipient, e
);
debug_assert!(false);
}
}

Self::deposit_event(Event::DEXTakeCollateralAuction(
auction_id,
collateral_auction.currency_id,
collateral_auction.amount,
stable_amount,
));
}
}

Expand Down
10 changes: 4 additions & 6 deletions modules/auction-manager/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ parameter_types! {
pub const MaxAuctionsCount: u32 = 10_000;
pub const CDPTreasuryPalletId: PalletId = PalletId(*b"aca/cdpt");
pub TreasuryAccount: AccountId = PalletId(*b"aca/hztr").into_account();
pub AlternativeSwapPathJointList: Vec<Vec<CurrencyId>> = vec![
vec![DOT],
];
}

impl cdp_treasury::Config for Runtime {
Expand All @@ -130,6 +133,7 @@ impl cdp_treasury::Config for Runtime {
type MaxAuctionsCount = MaxAuctionsCount;
type PalletId = CDPTreasuryPalletId;
type TreasuryAccount = TreasuryAccount;
type AlternativeSwapPathJointList = AlternativeSwapPathJointList;
type WeightInfo = ();
}

Expand Down Expand Up @@ -196,10 +200,6 @@ parameter_types! {
pub const AuctionTimeToClose: u64 = 100;
pub const AuctionDurationSoftCap: u64 = 2000;
pub const UnsignedPriority: u64 = 1 << 20;
pub DefaultSwapParitalPathList: Vec<Vec<CurrencyId>> = vec![
vec![AUSD],
vec![DOT, AUSD],
];
}

impl Config for Runtime {
Expand All @@ -211,11 +211,9 @@ impl Config for Runtime {
type AuctionDurationSoftCap = AuctionDurationSoftCap;
type GetStableCurrencyId = GetStableCurrencyId;
type CDPTreasury = CDPTreasuryModule;
type DEX = DEXModule;
type PriceSource = MockPriceSource;
type UnsignedPriority = UnsignedPriority;
type EmergencyShutdown = MockEmergencyShutdown;
type DefaultSwapParitalPathList = DefaultSwapParitalPathList;
type WeightInfo = ();
}

Expand Down
21 changes: 17 additions & 4 deletions modules/auction-manager/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use mock::{Call as MockCall, Event, *};
use sp_core::offchain::{testing, DbExternalities, OffchainDbExt, OffchainWorkerExt, StorageKind, TransactionPoolExt};
use sp_io::offchain;
use sp_runtime::traits::One;
use support::DEXManager;

fn run_to_block_offchain(n: u64) {
while System::block_number() < n {
Expand Down Expand Up @@ -187,7 +188,10 @@ fn collateral_auction_end_handler_without_bid() {
false
));
assert_eq!(DEXModule::get_liquidity_pool(BTC, AUSD), (100, 1000));
assert_eq!(DEXModule::get_swap_target_amount(&[BTC, AUSD], 100).unwrap(), 500);
assert_eq!(
DEXModule::get_swap_amount(&vec![BTC, AUSD], SwapLimit::ExactSupply(100, 0)),
Some((100, 500))
);

assert_ok!(AuctionManagerModule::new_collateral_auction(&ALICE, BTC, 100, 200));
assert_eq!(CDPTreasuryModule::total_collaterals(BTC), 100);
Expand Down Expand Up @@ -244,8 +248,14 @@ fn collateral_auction_end_handler_without_bid_and_swap_by_alternative_path() {
));
assert_eq!(DEXModule::get_liquidity_pool(BTC, DOT), (100, 1000));
assert_eq!(DEXModule::get_liquidity_pool(DOT, AUSD), (1000, 1000));
assert_eq!(DEXModule::get_swap_target_amount(&[BTC, AUSD], 100), None);
assert_eq!(DEXModule::get_swap_target_amount(&[BTC, DOT, AUSD], 100), Some(333));
assert_eq!(
DEXModule::get_swap_amount(&vec![BTC, AUSD], SwapLimit::ExactSupply(100, 0)),
None
);
assert_eq!(
DEXModule::get_swap_amount(&vec![BTC, DOT, AUSD], SwapLimit::ExactSupply(100, 0)),
Some((100, 333))
);

assert_ok!(AuctionManagerModule::new_collateral_auction(&ALICE, BTC, 100, 200));
assert_eq!(Tokens::free_balance(BTC, &ALICE), 1000);
Expand Down Expand Up @@ -354,7 +364,10 @@ fn collateral_auction_end_handler_by_dex_which_target_not_zero() {
0,
false
));
assert_eq!(DEXModule::get_swap_target_amount(&[BTC, AUSD], 100).unwrap(), 500);
assert_eq!(
DEXModule::get_swap_amount(&vec![BTC, AUSD], SwapLimit::ExactSupply(100, 0)),
Some((100, 500))
);

assert_eq!(CDPTreasuryModule::total_collaterals(BTC), 100);
assert_eq!(AuctionManagerModule::total_target_in_auction(), 200);
Expand Down
Loading