diff --git a/modules/homa-lite/src/lib.rs b/modules/homa-lite/src/lib.rs index e80bdba46..23c88683a 100644 --- a/modules/homa-lite/src/lib.rs +++ b/modules/homa-lite/src/lib.rs @@ -419,17 +419,26 @@ pub mod module { Self::deposit_event(Event::::RedeemRequestCancelled(who, request_amount)); } - } else { - // Redeem amount must be above a certain limit. - ensure!( - Self::liquid_amount_is_above_minimum_threshold(liquid_amount), - Error::::AmountBelowMinimumThreshold - ); + return Ok(()); + } - // Withdraw fee is burned. - let base_withdraw_fee = T::BaseWithdrawFee::get().mul(liquid_amount); - let slash_amount = T::Currency::slash(T::LiquidCurrencyId::get(), &who, base_withdraw_fee); - ensure!(slash_amount.is_zero(), Error::::InsufficientLiquidBalance); + // Redeem amount must be above a certain limit. + ensure!( + Self::liquid_amount_is_above_minimum_threshold(liquid_amount), + Error::::AmountBelowMinimumThreshold + ); + + RedeemRequests::::try_mutate(&who, |request| -> DispatchResult { + let old_amount = request.take().map(|(amount, _)| amount).unwrap_or_default(); + + let diff_amount = liquid_amount.saturating_sub(old_amount); + + let base_withdraw_fee = T::BaseWithdrawFee::get().mul(diff_amount); + if !base_withdraw_fee.is_zero() { + // Burn withdraw fee for increased amount + let slash_amount = T::Currency::slash(T::LiquidCurrencyId::get(), &who, base_withdraw_fee); + ensure!(slash_amount.is_zero(), Error::::InsufficientLiquidBalance); + } // Deduct BaseWithdrawFee from the liquid amount. let liquid_amount = liquid_amount.saturating_sub(base_withdraw_fee); @@ -491,12 +500,17 @@ pub mod module { }?; // Insert/replace the new redeem request into storage. - RedeemRequests::::insert(&who, (liquid_remaining, additional_fee)); + *request = Some((liquid_remaining, additional_fee)); - Self::deposit_event(Event::::RedeemRequested(who, liquid_remaining, additional_fee)); + Self::deposit_event(Event::::RedeemRequested( + who.clone(), + liquid_remaining, + additional_fee, + )); } - } - Ok(()) + + Ok(()) + }) } /// Request staking currencies to be unbonded from the RelayChain. @@ -556,19 +570,6 @@ pub mod module { } impl Pallet { - /// Calculate the exchange rate between the Staking and Liquid currency. - /// returns Ratio(staking : liquid) = total_staking_amount / liquid_total_issuance - /// If the exchange rate cannot be calculated, T::DefaultExchangeRate is used - pub fn get_exchange_rate() -> Ratio { - let staking_total = Self::total_staking_currency(); - let liquid_total = T::Currency::total_issuance(T::LiquidCurrencyId::get()); - if staking_total.is_zero() { - T::DefaultExchangeRate::get() - } else { - Ratio::checked_from_rational(staking_total, liquid_total).unwrap_or_else(T::DefaultExchangeRate::get) - } - } - /// Calculate the amount of Staking currency converted from Liquid currency. /// staking_amount = (total_staking_amount / liquid_total_issuance) * liquid_amount /// If the exchange rate cannot be calculated, T::DefaultExchangeRate is used @@ -799,6 +800,8 @@ pub mod module { ); let actual_staking_amount = Self::convert_liquid_to_staking(actual_liquid_amount)?; + TotalStakingCurrency::::mutate(|x| *x = x.saturating_sub(actual_staking_amount)); + // Redeem from the available_staking_balances costs only the xcm unbond fee. T::Currency::deposit( T::StakingCurrencyId::get(), @@ -866,10 +869,19 @@ pub mod module { ) } } - pub struct LiquidExchangeProvider(sp_std::marker::PhantomData); - impl ExchangeRateProvider for LiquidExchangeProvider { - fn get_exchange_rate() -> ExchangeRate { - Pallet::::get_exchange_rate().reciprocal().unwrap_or_default() + + impl ExchangeRateProvider for Pallet { + /// Calculate the exchange rate between the Staking and Liquid currency. + /// returns Ratio(staking : liquid) = total_staking_amount / liquid_total_issuance + /// If the exchange rate cannot be calculated, T::DefaultExchangeRate is used + fn get_exchange_rate() -> Ratio { + let staking_total = Self::total_staking_currency(); + let liquid_total = T::Currency::total_issuance(T::LiquidCurrencyId::get()); + if staking_total.is_zero() { + T::DefaultExchangeRate::get() + } else { + Ratio::checked_from_rational(staking_total, liquid_total).unwrap_or_else(T::DefaultExchangeRate::get) + } } } } diff --git a/modules/homa-lite/src/mock.rs b/modules/homa-lite/src/mock.rs index 51c77a26c..cb047ce9a 100644 --- a/modules/homa-lite/src/mock.rs +++ b/modules/homa-lite/src/mock.rs @@ -331,6 +331,15 @@ pub struct ExtBuilder { native_balances: Vec<(AccountId, Balance)>, } +impl ExtBuilder { + pub fn empty() -> Self { + Self { + tokens_balances: vec![], + native_balances: vec![], + } + } +} + impl Default for ExtBuilder { fn default() -> Self { let initial = dollar(INITIAL_BALANCE); diff --git a/modules/homa-lite/src/tests.rs b/modules/homa-lite/src/tests.rs index 568ef91b0..a3c8a3b44 100644 --- a/modules/homa-lite/src/tests.rs +++ b/modules/homa-lite/src/tests.rs @@ -74,10 +74,6 @@ fn mint_works() { HomaLite::get_exchange_rate(), ExchangeRate::saturating_from_rational(lksm_issuance / 5, lksm_issuance) ); - assert_eq!( - LiquidExchangeProvider::::get_exchange_rate(), - ExchangeRate::saturating_from_rational(lksm_issuance, lksm_issuance / 5) - ); // The exchange rate is now 1:5 ratio // liquid = (1000 - 0.01) * 1_009_899_901_000_000_000 / 201_979_980_200_000_000 * 0.99 @@ -517,11 +513,11 @@ fn request_redeem_works() { assert_eq!(AvailableStakingBalance::::get(), 0); assert_eq!(Currencies::free_balance(KSM, &ROOT), dollar(49_998)); assert_eq!(Currencies::free_balance(LKSM, &ROOT), dollar(349_400)); - assert_eq!(Currencies::reserved_balance(LKSM, &ROOT), 149_850_000_000_000_000); + assert_eq!(Currencies::reserved_balance(LKSM, &ROOT), 149949400000000000); // request_redeem replaces existing item in the queue, not add to it. assert_eq!( RedeemRequests::::get(&ROOT), - Some((149_850_000_000_000_000, Permill::zero())) + Some((149949400000000000, Permill::zero())) ); }); } @@ -641,10 +637,10 @@ fn can_replace_requested_redeem() { dollar(50_000), Permill::from_percent(50) )); - assert_eq!(Currencies::reserved_balance(LKSM, &ROOT), dollar(49_950)); + assert_eq!(Currencies::reserved_balance(LKSM, &ROOT), dollar(50_000)); assert_eq!( RedeemRequests::::get(&ROOT), - Some((dollar(49_950), Permill::from_percent(50))) + Some((dollar(50_000), Permill::from_percent(50))) ); // Increasing the amount locks additional liquid currency. @@ -653,10 +649,10 @@ fn can_replace_requested_redeem() { dollar(150_000), Permill::from_percent(10) )); - assert_eq!(Currencies::reserved_balance(LKSM, &ROOT), dollar(149_850)); + assert_eq!(Currencies::reserved_balance(LKSM, &ROOT), dollar(149_900)); assert_eq!( RedeemRequests::::get(&ROOT), - Some((dollar(149_850), Permill::from_percent(10))) + Some((dollar(149_900), Permill::from_percent(10))) ); }); } @@ -824,3 +820,125 @@ fn redeem_can_handle_dust_available_staking_currency() { ))); }); } + +#[test] +fn process_scheduled_unbond_with_multiple_requests() { + ExtBuilder::empty().build().execute_with(|| { + assert_ok!(Currencies::update_balance( + Origin::root(), + ALICE, + LKSM, + dollar(100) as i128 + )); + assert_ok!(Currencies::update_balance( + Origin::root(), + BOB, + LKSM, + dollar(100) as i128 + )); + assert_ok!(Currencies::update_balance( + Origin::root(), + CHARLIE, + LKSM, + dollar(200) as i128 + )); + + assert_ok!(HomaLite::set_total_staking_currency(Origin::root(), dollar(40))); + + let rate1 = HomaLite::get_exchange_rate(); + assert_eq!(HomaLite::get_exchange_rate(), Ratio::saturating_from_rational(1, 10)); + + assert_ok!(HomaLite::request_redeem( + Origin::signed(ALICE), + dollar(100), + Permill::zero() + )); + + assert_ok!(HomaLite::request_redeem( + Origin::signed(BOB), + dollar(100), + Permill::zero() + )); + + assert_ok!(HomaLite::request_redeem( + Origin::signed(CHARLIE), + dollar(200), + Permill::zero() + )); + + assert_ok!(HomaLite::replace_schedule_unbond(Origin::root(), vec![(dollar(30), 1)],)); + MockRelayBlockNumberProvider::set(1); + HomaLite::on_idle(MockRelayBlockNumberProvider::get(), 5_000_000_000); + + let rate2 = HomaLite::get_exchange_rate(); + assert!(rate1 < rate2); + + // Some rounding error + assert_eq!(AvailableStakingBalance::::get(), 1); + + // Some rounding error, 10 KSM - 1 KSM unbond fee + assert_eq!(Currencies::free_balance(KSM, &ALICE), 8999999999999); + assert_eq!(Currencies::free_balance(LKSM, &ALICE), 0); + + // 10 KSM - 1 KSM unbond fee + assert_eq!(Currencies::free_balance(KSM, &BOB), 9000000000000); + assert_eq!(Currencies::free_balance(LKSM, &BOB), 0); + + // 10 KSM - 1 KSM unbond fee + assert_eq!(Currencies::free_balance(KSM, &CHARLIE), 9000000000000); + // 100 LKSM minus fee + assert_eq!(Currencies::reserved_balance(LKSM, &CHARLIE), 99899999999996); + }); +} + +#[test] +fn not_overcharge_redeem_fee() { + ExtBuilder::empty().build().execute_with(|| { + assert_ok!(Currencies::update_balance( + Origin::root(), + ALICE, + LKSM, + dollar(100) as i128 + )); + + assert_ok!(HomaLite::set_total_staking_currency(Origin::root(), dollar(10))); + + assert_ok!(HomaLite::request_redeem( + Origin::signed(ALICE), + dollar(50), + Permill::zero() + )); + + let fee = dollar(50) / 1000; + + assert_eq!(Currencies::free_balance(LKSM, &ALICE), dollar(50)); + assert_eq!(Currencies::reserved_balance(LKSM, &ALICE), dollar(50) - fee); + + assert_ok!(HomaLite::request_redeem( + Origin::signed(ALICE), + dollar(50) - fee, + Permill::zero() + )); + + assert_eq!(Currencies::free_balance(LKSM, &ALICE), dollar(50)); + assert_eq!(Currencies::reserved_balance(LKSM, &ALICE), dollar(50) - fee); + + assert_ok!(HomaLite::request_redeem( + Origin::signed(ALICE), + dollar(100) - fee, + Permill::zero() + )); + + assert_eq!(Currencies::free_balance(LKSM, &ALICE), 0); + assert_eq!(Currencies::reserved_balance(LKSM, &ALICE), dollar(100) - fee * 2); + + assert_ok!(HomaLite::request_redeem( + Origin::signed(ALICE), + dollar(20) - fee * 2, + Permill::zero() + )); + + assert_eq!(Currencies::free_balance(LKSM, &ALICE), dollar(80)); + assert_eq!(Currencies::reserved_balance(LKSM, &ALICE), dollar(20) - fee * 2); + }); +} diff --git a/runtime/acala/src/lib.rs b/runtime/acala/src/lib.rs index c0cd5ae5e..46b8f099f 100644 --- a/runtime/acala/src/lib.rs +++ b/runtime/acala/src/lib.rs @@ -798,7 +798,7 @@ impl module_prices::Config for Runtime { type GetStakingCurrencyId = GetStakingCurrencyId; type GetLiquidCurrencyId = GetLiquidCurrencyId; type LockOrigin = EnsureRootOrTwoThirdsGeneralCouncil; - type LiquidStakingExchangeRateProvider = module_homa_lite::LiquidExchangeProvider; + type LiquidStakingExchangeRateProvider = HomaLite; type DEX = Dex; type Currency = Currencies; type CurrencyIdMapping = EvmCurrencyIdMapping; diff --git a/runtime/integration-tests/src/homa_lite.rs b/runtime/integration-tests/src/homa_lite.rs index 954b77372..440c6f20f 100644 --- a/runtime/integration-tests/src/homa_lite.rs +++ b/runtime/integration-tests/src/homa_lite.rs @@ -18,232 +18,291 @@ //! Tests the Homa-lite module, and its cross-chain functionalities. -#[cfg(any(feature = "with-mandala-runtime", feature = "with-karura-runtime"))] -mod common_tests { - use crate::setup::*; - use frame_support::{assert_noop, assert_ok}; - use orml_traits::{MultiCurrency, MultiReservableCurrency}; +use crate::setup::*; +use frame_support::{assert_noop, assert_ok}; +use module_support::ExchangeRateProvider; +use orml_traits::{MultiCurrency, MultiReservableCurrency}; + +#[test] +fn homa_lite_mint_works() { + ExtBuilder::default() + .balances(vec![ + (alice(), RELAY_CHAIN_CURRENCY, 5_000 * dollar(RELAY_CHAIN_CURRENCY)), + (bob(), RELAY_CHAIN_CURRENCY, 5_000 * dollar(RELAY_CHAIN_CURRENCY)), + (bob(), LIQUID_CURRENCY, 1_000_000 * dollar(LIQUID_CURRENCY)), + ]) + .build() + .execute_with(|| { + let amount = 1000 * dollar(RELAY_CHAIN_CURRENCY); - #[test] - fn homa_lite_mint_works() { - ExtBuilder::default() - .balances(vec![ - (alice(), RELAY_CHAIN_CURRENCY, 5_000 * dollar(RELAY_CHAIN_CURRENCY)), - (bob(), RELAY_CHAIN_CURRENCY, 5_000 * dollar(RELAY_CHAIN_CURRENCY)), - (bob(), LIQUID_CURRENCY, 1_000_000 * dollar(LIQUID_CURRENCY)), - ]) - .build() - .execute_with(|| { - let amount = 1000 * dollar(RELAY_CHAIN_CURRENCY); - - assert_noop!( - HomaLite::mint(Origin::signed(alice()), amount), - module_homa_lite::Error::::ExceededStakingCurrencyMintCap + assert_noop!( + HomaLite::mint(Origin::signed(alice()), amount), + module_homa_lite::Error::::ExceededStakingCurrencyMintCap + ); + + // Set the total staking amount + let liquid_issuance = Currencies::total_issuance(LIQUID_CURRENCY); + assert_eq!(liquid_issuance, 1_000_000 * dollar(LIQUID_CURRENCY)); + + let staking_total = liquid_issuance / 5; + + // Set the exchange rate to 1(S) : 5(L) + assert_ok!(HomaLite::set_total_staking_currency(Origin::root(), staking_total)); + + assert_ok!(HomaLite::set_minting_cap(Origin::root(), 10 * staking_total)); + + // Exchange rate set to 1(Staking) : 5(Liquid) ratio + // liquid = (amount - MintFee) * exchange_rate * (1 - MaxRewardPerEra) + #[cfg(feature = "with-mandala-runtime")] + let liquid_amount_1 = 49_974_999_500_250; + #[cfg(feature = "with-karura-runtime")] + let liquid_amount_1 = 4_997_499_000_500_000; + + assert_ok!(HomaLite::mint(Origin::signed(alice()), amount)); + assert_eq!(Currencies::free_balance(LIQUID_CURRENCY, &alice()), liquid_amount_1); + System::assert_last_event(Event::HomaLite(module_homa_lite::Event::Minted( + alice(), + amount, + liquid_amount_1, + ))); + + // Total issuance for liquid currnecy increased. + let new_liquid_issuance = Currencies::total_issuance(LIQUID_CURRENCY); + #[cfg(feature = "with-mandala-runtime")] + assert_eq!(new_liquid_issuance, 10_049_974_999_500_250); + #[cfg(feature = "with-karura-runtime")] + assert_eq!(new_liquid_issuance, 1_004_997_499_000_500_000); + + // liquid = (amount - MintFee) * (new_liquid_issuance / new_staking_total) * (1 - MaxRewardPerEra) + #[cfg(feature = "with-mandala-runtime")] // Mandala uses DOT, which has 10 d.p. accuracy. + let liquid_amount_2 = 49_974_875_181_840; + #[cfg(feature = "with-karura-runtime")] // Karura uses KSM, which has 12 d.p. accuracy. + let liquid_amount_2 = 4_997_486_563_940_292; + + assert_ok!(HomaLite::mint(Origin::signed(alice()), amount)); + System::assert_last_event(Event::HomaLite(module_homa_lite::Event::Minted( + alice(), + amount, + liquid_amount_2, + ))); + + #[cfg(feature = "with-mandala-runtime")] + assert_eq!(Currencies::free_balance(LIQUID_CURRENCY, &alice()), 99_949_874_682_090); + #[cfg(feature = "with-karura-runtime")] + assert_eq!( + Currencies::free_balance(LIQUID_CURRENCY, &alice()), + 9_994_985_564_440_292 + ); + }); +} + +#[test] +fn homa_lite_mint_can_match_redeem_requests() { + ExtBuilder::default() + .balances(vec![ + (AccountId::from(ALICE), LIQUID_CURRENCY, 5_000 * dollar(LIQUID_CURRENCY)), + (AccountId::from(BOB), LIQUID_CURRENCY, 5_000 * dollar(LIQUID_CURRENCY)), + ( + AccountId::from(CHARLIE), + LIQUID_CURRENCY, + 5_000 * dollar(LIQUID_CURRENCY), + ), + ( + AccountId::from(DAVE), + RELAY_CHAIN_CURRENCY, + 1_200 * dollar(RELAY_CHAIN_CURRENCY), + ), + ]) + .build() + .execute_with(|| { + // Default exchange rate is 1S : 10L + assert_ok!(HomaLite::set_minting_cap( + Origin::root(), + 20_000 * dollar(RELAY_CHAIN_CURRENCY) + )); + + // insert redeem requests + assert_ok!(HomaLite::request_redeem( + Origin::signed(AccountId::from(ALICE)), + 5_000 * dollar(LIQUID_CURRENCY), + Permill::zero() + )); + assert_ok!(HomaLite::request_redeem( + Origin::signed(AccountId::from(BOB)), + 5_000 * dollar(LIQUID_CURRENCY), + Permill::from_percent(10) + )); + assert_ok!(HomaLite::request_redeem( + Origin::signed(AccountId::from(CHARLIE)), + 5_000 * dollar(LIQUID_CURRENCY), + Permill::from_percent(1) + )); + + // Minter pays no fee if minted via matching redeem requests, since no XCM transfer is needed. + assert_ok!(HomaLite::mint_for_requests( + Origin::signed(AccountId::from(DAVE)), + 1_200 * dollar(RELAY_CHAIN_CURRENCY), + vec![AccountId::from(ALICE), AccountId::from(BOB)] + )); + + #[cfg(feature = "with-mandala-runtime")] + { + // Base withdraw fee = 0.014085 + // for ALICE: liquid_amount = +5000 - 4929.575 (redeem) - 70.425(fee) = 0 + // staking_amount = +492.9575 + // + // for BOB: liquid_amount = +5000 - 4929.575 (redeem) - 70.425(fee) = 0 + // staking_amount = -492.9575 - extra_fee(10%) + // = -492.9575 - 49.29575 = +443.66175 + // + // for CHARlIE:liquid_amount = +5000 - 2140.85 (redeem) - 70.425(fee) = 2788.725 + // staking_amount = +214.085 - extra_fee(1%) + // = +214.085 - 2.14085 = +211.94415 + // + // for minter: liquid_amount = +12_000 + // staking_amount = 1200(initial) - 1_200(mint) + extra_fee = + // = 49.29575 + 2.14085 = 51.4366 + assert_eq!(Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(ALICE)), 0); + assert_eq!( + Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(ALICE)), + 4_929_575_000_000 ); - // Set the total staking amount - let liquid_issuance = Currencies::total_issuance(LIQUID_CURRENCY); - assert_eq!(liquid_issuance, 1_000_000 * dollar(LIQUID_CURRENCY)); - - let staking_total = liquid_issuance / 5; - - // Set the exchange rate to 1(S) : 5(L) - assert_ok!(HomaLite::set_total_staking_currency(Origin::root(), staking_total)); - - assert_ok!(HomaLite::set_minting_cap(Origin::root(), 10 * staking_total)); - - // Exchange rate set to 1(Staking) : 5(Liquid) ratio - // liquid = (amount - MintFee) * exchange_rate * (1 - MaxRewardPerEra) - #[cfg(feature = "with-mandala-runtime")] - let liquid_amount_1 = 49_974_999_500_250; - #[cfg(feature = "with-karura-runtime")] - let liquid_amount_1 = 4_997_499_000_500_000; - - assert_ok!(HomaLite::mint(Origin::signed(alice()), amount)); - assert_eq!(Currencies::free_balance(LIQUID_CURRENCY, &alice()), liquid_amount_1); - System::assert_last_event(Event::HomaLite(module_homa_lite::Event::Minted( - alice(), - amount, - liquid_amount_1, - ))); - - // Total issuance for liquid currnecy increased. - let new_liquid_issuance = Currencies::total_issuance(LIQUID_CURRENCY); - #[cfg(feature = "with-mandala-runtime")] - assert_eq!(new_liquid_issuance, 10_049_974_999_500_250); - #[cfg(feature = "with-karura-runtime")] - assert_eq!(new_liquid_issuance, 1_004_997_499_000_500_000); - - // liquid = (amount - MintFee) * (new_liquid_issuance / new_staking_total) * (1 - MaxRewardPerEra) - #[cfg(feature = "with-mandala-runtime")] // Mandala uses DOT, which has 10 d.p. accuracy. - let liquid_amount_2 = 49_974_875_181_840; - #[cfg(feature = "with-karura-runtime")] // Karura uses KSM, which has 12 d.p. accuracy. - let liquid_amount_2 = 4_997_486_563_940_292; - - assert_ok!(HomaLite::mint(Origin::signed(alice()), amount)); - System::assert_last_event(Event::HomaLite(module_homa_lite::Event::Minted( - alice(), - amount, - liquid_amount_2, - ))); - - #[cfg(feature = "with-mandala-runtime")] - assert_eq!(Currencies::free_balance(LIQUID_CURRENCY, &alice()), 99_949_874_682_090); - #[cfg(feature = "with-karura-runtime")] + assert_eq!(Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(BOB)), 0); assert_eq!( - Currencies::free_balance(LIQUID_CURRENCY, &alice()), - 9_994_985_564_440_292 + Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(BOB)), + 4_436_617_500_000 ); - }); - } - #[test] - fn homa_lite_mint_can_match_redeem_requests() { - ExtBuilder::default() - .balances(vec![ - (AccountId::from(ALICE), LIQUID_CURRENCY, 5_000 * dollar(LIQUID_CURRENCY)), - (AccountId::from(BOB), LIQUID_CURRENCY, 5_000 * dollar(LIQUID_CURRENCY)), - ( - AccountId::from(CHARLIE), - LIQUID_CURRENCY, - 5_000 * dollar(LIQUID_CURRENCY), - ), - ( - AccountId::from(DAVE), - RELAY_CHAIN_CURRENCY, - 1_200 * dollar(RELAY_CHAIN_CURRENCY), - ), - ]) - .build() - .execute_with(|| { - // Default exchange rate is 1S : 10L - assert_ok!(HomaLite::set_minting_cap( - Origin::root(), - 20_000 * dollar(RELAY_CHAIN_CURRENCY) - )); - - // insert redeem requests - assert_ok!(HomaLite::request_redeem( - Origin::signed(AccountId::from(ALICE)), - 5_000 * dollar(LIQUID_CURRENCY), - Permill::zero() - )); - assert_ok!(HomaLite::request_redeem( - Origin::signed(AccountId::from(BOB)), - 5_000 * dollar(LIQUID_CURRENCY), - Permill::from_percent(10) - )); - assert_ok!(HomaLite::request_redeem( - Origin::signed(AccountId::from(CHARLIE)), - 5_000 * dollar(LIQUID_CURRENCY), - Permill::from_percent(1) - )); - - // Minter pays no fee if minted via matching redeem requests, since no XCM transfer is needed. - assert_ok!(HomaLite::mint_for_requests( - Origin::signed(AccountId::from(DAVE)), - 1_200 * dollar(RELAY_CHAIN_CURRENCY), - vec![AccountId::from(ALICE), AccountId::from(BOB)] - )); - - #[cfg(feature = "with-mandala-runtime")] - { - // Base withdraw fee = 0.014085 - // for ALICE: liquid_amount = +5000 - 4929.575 (redeem) - 70.425(fee) = 0 - // staking_amount = +492.9575 - // - // for BOB: liquid_amount = +5000 - 4929.575 (redeem) - 70.425(fee) = 0 - // staking_amount = -492.9575 - extra_fee(10%) - // = -492.9575 - 49.29575 = +443.66175 - // - // for CHARlIE:liquid_amount = +5000 - 2140.85 (redeem) - 70.425(fee) = 2788.725 - // staking_amount = +214.085 - extra_fee(1%) - // = +214.085 - 2.14085 = +211.94415 - // - // for minter: liquid_amount = +12_000 - // staking_amount = 1200(initial) - 1_200(mint) + extra_fee = - // = 49.29575 + 2.14085 = 51.4366 - assert_eq!(Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(ALICE)), 0); - assert_eq!( - Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(ALICE)), - 4_929_575_000_000 - ); - - assert_eq!(Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(BOB)), 0); - assert_eq!( - Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(BOB)), - 4_436_617_500_000 - ); - - assert_eq!(Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(CHARLIE)), 0); - assert_eq!( - Currencies::reserved_balance(LIQUID_CURRENCY, &AccountId::from(CHARLIE)), - 27_887_250_000_000 - ); - assert_eq!( - Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(CHARLIE)), - 2_119_441_500_000 - ); - - assert_eq!( - Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(DAVE)), - 12_000 * dollar(LIQUID_CURRENCY) - ); - assert_eq!( - Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(DAVE)), - 514_366_000_000 - ); - } - #[cfg(feature = "with-karura-runtime")] - { - // Base withdraw fee = 0.0035 - // for ALICE: liquid_amount = +5000 - 4982.5 (redeem) - 17.5(fee) = 0 - // staking_amount = +498.25 - // - // for BOB: liquid_amount = +5000 - 4982.5 (redeem) - 17.5(fee) = 0 - // staking_amount = +498.25 - extra_fee(10%) - // = +498.25 - 49.825 = -448.425 - // - // for CHARlIE:liquid_amount = +5000 -2035 (redeem) - 17.5(fee) = 2947.5 - // staking_amount = +203.5 - extra_fee(1%) - // = +203.5 s- 2.035 = +201.465 - // - // for minter: liquid_amount = +12_000 - // staking_amount = 1200(initial) -1_200(mint) + extra_fee = - // = 49.825 + 2.035 = 51.86 - assert_eq!(Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(ALICE)), 0); - assert_eq!( - Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(ALICE)), - 498_250_000_000_000 - ); - - assert_eq!(Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(BOB)), 0); - assert_eq!( - Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(BOB)), - 448_425_000_000_000 - ); - - assert_eq!(Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(CHARLIE)), 0); - assert_eq!( - Currencies::reserved_balance(LIQUID_CURRENCY, &AccountId::from(CHARLIE)), - 2_947_500_000_000_000 - ); - assert_eq!( - Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(CHARLIE)), - 201_465_000_000_000 - ); - - assert_eq!( - Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(DAVE)), - 12_000 * dollar(LIQUID_CURRENCY) - ); - assert_eq!( - Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(DAVE)), - 51_860_000_000_000 - ); - } - }); - } + assert_eq!(Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(CHARLIE)), 0); + assert_eq!( + Currencies::reserved_balance(LIQUID_CURRENCY, &AccountId::from(CHARLIE)), + 27_887_250_000_000 + ); + assert_eq!( + Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(CHARLIE)), + 2_119_441_500_000 + ); + + assert_eq!( + Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(DAVE)), + 12_000 * dollar(LIQUID_CURRENCY) + ); + assert_eq!( + Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(DAVE)), + 514_366_000_000 + ); + } + #[cfg(feature = "with-karura-runtime")] + { + // Base withdraw fee = 0.0035 + // for ALICE: liquid_amount = +5000 - 4982.5 (redeem) - 17.5(fee) = 0 + // staking_amount = +498.25 + // + // for BOB: liquid_amount = +5000 - 4982.5 (redeem) - 17.5(fee) = 0 + // staking_amount = +498.25 - extra_fee(10%) + // = +498.25 - 49.825 = -448.425 + // + // for CHARlIE:liquid_amount = +5000 -2035 (redeem) - 17.5(fee) = 2947.5 + // staking_amount = +203.5 - extra_fee(1%) + // = +203.5 s- 2.035 = +201.465 + // + // for minter: liquid_amount = +12_000 + // staking_amount = 1200(initial) -1_200(mint) + extra_fee = + // = 49.825 + 2.035 = 51.86 + assert_eq!(Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(ALICE)), 0); + assert_eq!( + Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(ALICE)), + 498_250_000_000_000 + ); + + assert_eq!(Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(BOB)), 0); + assert_eq!( + Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(BOB)), + 448_425_000_000_000 + ); + + assert_eq!(Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(CHARLIE)), 0); + assert_eq!( + Currencies::reserved_balance(LIQUID_CURRENCY, &AccountId::from(CHARLIE)), + 2_947_500_000_000_000 + ); + assert_eq!( + Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(CHARLIE)), + 201_465_000_000_000 + ); + + assert_eq!( + Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(DAVE)), + 12_000 * dollar(LIQUID_CURRENCY) + ); + assert_eq!( + Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(DAVE)), + 51_860_000_000_000 + ); + } + }); +} + +#[test] +fn homa_lite_mint_and_redeem() { + ExtBuilder::default() + .balances(vec![ + (alice(), RELAY_CHAIN_CURRENCY, 200 * dollar(RELAY_CHAIN_CURRENCY)), + (bob(), RELAY_CHAIN_CURRENCY, 100 * dollar(RELAY_CHAIN_CURRENCY)), + ]) + .build() + .execute_with(|| { + let rate1 = DefaultExchangeRate::get(); + assert_eq!(rate1, HomaLite::get_exchange_rate()); + + assert_ok!(HomaLite::set_minting_cap( + Origin::root(), + 300 * dollar(RELAY_CHAIN_CURRENCY) + )); + + assert_ok!(HomaLite::mint( + Origin::signed(alice()), + 100 * dollar(RELAY_CHAIN_CURRENCY) + )); + + let rate2 = HomaLite::get_exchange_rate(); + assert!(rate1 < rate2); + + assert_ok!(HomaLite::adjust_total_staking_currency( + Origin::root(), + 10i128 * dollar(RELAY_CHAIN_CURRENCY) as i128 + )); + + let rate3 = HomaLite::get_exchange_rate(); + assert!(rate2 < rate3); + assert!(Ratio::saturating_from_rational(110, 1000) < rate3); + + assert_ok!(HomaLite::mint( + Origin::signed(bob()), + 100 * dollar(RELAY_CHAIN_CURRENCY) + )); + + let rate4 = HomaLite::get_exchange_rate(); + assert!(rate3 < rate4); + + assert_ok!(HomaLite::request_redeem( + Origin::signed(bob()), + 100 * dollar(RELAY_CHAIN_CURRENCY), + Permill::from_percent(0) + )); + + let rate5 = HomaLite::get_exchange_rate(); + assert!(rate4 < rate5); + + assert_ok!(HomaLite::mint( + Origin::signed(alice()), + 100 * dollar(RELAY_CHAIN_CURRENCY) + )); + + let rate6 = HomaLite::get_exchange_rate(); + assert!(rate5 < rate6); + }); } #[cfg(feature = "with-karura-runtime")] diff --git a/runtime/integration-tests/src/honzon.rs b/runtime/integration-tests/src/honzon.rs index 2bf6b9d77..e52a4c323 100644 --- a/runtime/integration-tests/src/honzon.rs +++ b/runtime/integration-tests/src/honzon.rs @@ -113,10 +113,7 @@ fn liquidate_cdp() { ]) .build() .execute_with(|| { - assert_ok!(set_oracle_price(vec![( - RELAY_CHAIN_CURRENCY, - Price::saturating_from_rational(10000, 1) - )])); // 10000 usd + set_oracle_price(vec![(RELAY_CHAIN_CURRENCY, Price::saturating_from_rational(10000, 1))]); // 10000 usd assert_ok!(Dex::add_liquidity( Origin::signed(AccountId::from(BOB)), @@ -242,10 +239,7 @@ fn test_honzon_module() { )]) .build() .execute_with(|| { - assert_ok!(set_oracle_price(vec![( - RELAY_CHAIN_CURRENCY, - Price::saturating_from_rational(1, 1) - )])); + set_oracle_price(vec![(RELAY_CHAIN_CURRENCY, Price::saturating_from_rational(1, 1))]); assert_ok!(CdpEngine::set_collateral_params( Origin::root(), @@ -404,10 +398,10 @@ fn test_cdp_engine_module() { module_cdp_engine::Error::::NoDebitValue, ); - assert_ok!(set_oracle_price(vec![ + set_oracle_price(vec![ (USD_CURRENCY, Price::saturating_from_rational(1, 1)), - (RELAY_CHAIN_CURRENCY, Price::saturating_from_rational(3, 1)) - ])); + (RELAY_CHAIN_CURRENCY, Price::saturating_from_rational(3, 1)), + ]); assert_ok!(CdpEngine::adjust_position( &AccountId::from(ALICE), @@ -465,10 +459,7 @@ fn cdp_treasury_handles_honzon_surplus_correctly() { .build() .execute_with(|| { System::set_block_number(1); - assert_ok!(set_oracle_price(vec![( - RELAY_CHAIN_CURRENCY, - Price::saturating_from_rational(100, 1) - )])); + set_oracle_price(vec![(RELAY_CHAIN_CURRENCY, Price::saturating_from_rational(100, 1))]); assert_ok!(CdpEngine::set_collateral_params( Origin::root(), RELAY_CHAIN_CURRENCY, diff --git a/runtime/integration-tests/src/lib.rs b/runtime/integration-tests/src/lib.rs index 54041c1cd..16266cb33 100644 --- a/runtime/integration-tests/src/lib.rs +++ b/runtime/integration-tests/src/lib.rs @@ -39,6 +39,9 @@ mod honzon; #[cfg(any(feature = "with-mandala-runtime", feature = "with-karura-runtime",))] mod nft; +#[cfg(any(feature = "with-mandala-runtime", feature = "with-karura-runtime",))] +mod prices; + #[cfg(any(feature = "with-mandala-runtime", feature = "with-karura-runtime",))] mod proxy; diff --git a/runtime/integration-tests/src/prices.rs b/runtime/integration-tests/src/prices.rs new file mode 100644 index 000000000..b536985cb --- /dev/null +++ b/runtime/integration-tests/src/prices.rs @@ -0,0 +1,90 @@ +// This file is part of Acala. + +// Copyright (C) 2020-2021 Acala Foundation. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use crate::setup::*; +use module_prices::RealTimePriceProvider; +use module_support::PriceProvider; + +#[cfg(any(feature = "with-karura-runtime"))] +#[test] +fn test_default_liquid_currency_price() { + ExtBuilder::default() + .balances(vec![( + alice(), + RELAY_CHAIN_CURRENCY, + 100 * dollar(RELAY_CHAIN_CURRENCY), + )]) + .build() + .execute_with(|| { + assert_eq!(RealTimePriceProvider::::get_price(RELAY_CHAIN_CURRENCY), None); + assert_eq!(RealTimePriceProvider::::get_price(LIQUID_CURRENCY), None); + + let relaychain_price = Price::saturating_from_rational(10, 1); + + set_oracle_price(vec![(RELAY_CHAIN_CURRENCY, relaychain_price)]); + + assert_eq!( + RealTimePriceProvider::::get_relative_price(RELAY_CHAIN_CURRENCY, USD_CURRENCY), + Some(relaychain_price) + ); + + let default_ratio = DefaultExchangeRate::get(); + assert_eq!( + RealTimePriceProvider::::get_relative_price(LIQUID_CURRENCY, USD_CURRENCY), + Some(relaychain_price * default_ratio) + ); + + assert_eq!( + RealTimePriceProvider::::get_relative_price(LIQUID_CURRENCY, RELAY_CHAIN_CURRENCY), + Some(default_ratio) + ); + }); +} + +#[cfg(any(feature = "with-karura-runtime"))] +#[test] +fn test_update_liquid_currency_price() { + ExtBuilder::default() + .balances(vec![(alice(), LIQUID_CURRENCY, 1000 * dollar(LIQUID_CURRENCY))]) + .build() + .execute_with(|| { + let relaychain_price = Price::saturating_from_rational(10, 1); + + set_oracle_price(vec![(RELAY_CHAIN_CURRENCY, relaychain_price)]); + + assert_ok!(HomaLite::set_total_staking_currency( + Origin::root(), + 100 * dollar(RELAY_CHAIN_CURRENCY) + )); + + assert_eq!( + RealTimePriceProvider::::get_relative_price(LIQUID_CURRENCY, RELAY_CHAIN_CURRENCY), + Some(Ratio::saturating_from_rational(100, 1000)) + ); + + assert_ok!(HomaLite::set_total_staking_currency( + Origin::root(), + 110 * dollar(RELAY_CHAIN_CURRENCY) + )); + + assert_eq!( + RealTimePriceProvider::::get_relative_price(LIQUID_CURRENCY, RELAY_CHAIN_CURRENCY), + Some(Ratio::saturating_from_rational(110, 1000)) + ); + }); +} diff --git a/runtime/integration-tests/src/proxy.rs b/runtime/integration-tests/src/proxy.rs index 612af21d0..9efeb4611 100644 --- a/runtime/integration-tests/src/proxy.rs +++ b/runtime/integration-tests/src/proxy.rs @@ -112,10 +112,7 @@ fn proxy_permissions_correct() { .execute_with(|| { // runtimes have different minimum debit dust requirements let min_debit: Balance = 100 * MinimumDebitValue::get(); - assert_ok!(set_oracle_price(vec![( - RELAY_CHAIN_CURRENCY, - Price::saturating_from_rational(100, 1) - )])); + set_oracle_price(vec![(RELAY_CHAIN_CURRENCY, Price::saturating_from_rational(100, 1))]); assert_ok!(CdpEngine::set_collateral_params( Origin::root(), RELAY_CHAIN_CURRENCY, diff --git a/runtime/integration-tests/src/relaychain/kusama_cross_chain_transfer.rs b/runtime/integration-tests/src/relaychain/kusama_cross_chain_transfer.rs index de7a99aa5..e62553c61 100644 --- a/runtime/integration-tests/src/relaychain/kusama_cross_chain_transfer.rs +++ b/runtime/integration-tests/src/relaychain/kusama_cross_chain_transfer.rs @@ -61,13 +61,16 @@ fn transfer_to_relay_chain() { Origin::signed(ALICE.into()), KSM, dollar(KSM), - Box::new(MultiLocation::new( - 1, - X1(Junction::AccountId32 { - id: BOB, - network: NetworkId::Any, - }) - )), + Box::new( + MultiLocation::new( + 1, + X1(Junction::AccountId32 { + id: BOB, + network: NetworkId::Any, + }) + ) + .into() + ), 4_000_000_000 )); }); diff --git a/runtime/integration-tests/src/setup.rs b/runtime/integration-tests/src/setup.rs index afa9988b9..d53c69b2a 100644 --- a/runtime/integration-tests/src/setup.rs +++ b/runtime/integration-tests/src/setup.rs @@ -46,12 +46,13 @@ mod mandala_imports { pub use mandala_runtime::{ create_x2_parachain_multilocation, get_all_module_accounts, AcalaOracle, AccountId, AuctionManager, Authority, AuthoritysOriginId, Balance, Balances, BlockNumber, Call, CdpEngine, CdpTreasury, CreateClassDeposit, - CreateTokenDeposit, Currencies, CurrencyId, CurrencyIdConvert, DataDepositPerByte, Dex, EmergencyShutdown, - EnabledTradingPairs, Event, EvmAccounts, ExistentialDeposits, Get, GetNativeCurrencyId, HomaLite, Honzon, - Loans, MinimumDebitValue, MultiLocation, NativeTokenExistentialDeposit, NetworkId, NftPalletId, OneDay, Origin, - OriginCaller, ParachainInfo, ParachainSystem, Proxy, ProxyType, RelayChainSovereignSubAccount, Runtime, - Scheduler, Session, SessionManager, SevenDays, System, Timestamp, TokenSymbol, Tokens, TreasuryAccount, - TreasuryPalletId, Utility, Vesting, XcmConfig, XcmExecutor, XcmUnbondFee, NFT, + CreateTokenDeposit, Currencies, CurrencyId, CurrencyIdConvert, DataDepositPerByte, DefaultExchangeRate, Dex, + EmergencyShutdown, EnabledTradingPairs, Event, EvmAccounts, ExistentialDeposits, Get, GetNativeCurrencyId, + HomaLite, Honzon, Loans, MinimumDebitValue, MultiLocation, NativeTokenExistentialDeposit, NetworkId, + NftPalletId, OneDay, Origin, OriginCaller, ParachainInfo, ParachainSystem, Proxy, ProxyType, + RelayChainSovereignSubAccount, Runtime, Scheduler, Session, SessionManager, SevenDays, System, Timestamp, + TokenSymbol, Tokens, TreasuryAccount, TreasuryPalletId, Utility, Vesting, XcmConfig, XcmExecutor, XcmUnbondFee, + NFT, }; pub use runtime_common::{dollar, ACA, AUSD, DOT, LDOT}; @@ -73,13 +74,13 @@ mod karura_imports { pub use karura_runtime::{ constants::parachains, create_x2_parachain_multilocation, get_all_module_accounts, AcalaOracle, AccountId, AuctionManager, Authority, AuthoritysOriginId, Balance, Balances, BlockNumber, Call, CdpEngine, CdpTreasury, - CreateClassDeposit, CreateTokenDeposit, Currencies, CurrencyId, CurrencyIdConvert, DataDepositPerByte, Dex, - EmergencyShutdown, Event, EvmAccounts, ExistentialDeposits, Get, GetNativeCurrencyId, HomaLite, Honzon, - KaruraFoundationAccounts, Loans, MinimumDebitValue, MultiLocation, NativeTokenExistentialDeposit, NetworkId, - NftPalletId, OneDay, Origin, OriginCaller, ParachainAccount, ParachainInfo, ParachainSystem, Proxy, ProxyType, - RelayChainBlockNumberProvider, RelayChainSovereignSubAccount, Runtime, Scheduler, Session, SessionManager, - SevenDays, System, Timestamp, TokenSymbol, Tokens, TreasuryPalletId, Utility, Vesting, XTokens, XcmConfig, - XcmExecutor, XcmUnbondFee, NFT, + CreateClassDeposit, CreateTokenDeposit, Currencies, CurrencyId, CurrencyIdConvert, DataDepositPerByte, + DefaultExchangeRate, Dex, EmergencyShutdown, Event, EvmAccounts, ExistentialDeposits, Get, GetNativeCurrencyId, + HomaLite, Honzon, KaruraFoundationAccounts, Loans, MinimumDebitValue, MultiLocation, + NativeTokenExistentialDeposit, NetworkId, NftPalletId, OneDay, Origin, OriginCaller, ParachainAccount, + ParachainInfo, ParachainSystem, Proxy, ProxyType, RelayChainBlockNumberProvider, RelayChainSovereignSubAccount, + Runtime, Scheduler, Session, SessionManager, SevenDays, System, Timestamp, TokenSymbol, Tokens, + TreasuryPalletId, Utility, Vesting, XTokens, XcmConfig, XcmExecutor, XcmUnbondFee, NFT, }; pub use primitives::TradingPair; pub use runtime_common::{dollar, KAR, KSM, KUSD, LKSM}; @@ -112,12 +113,12 @@ mod acala_imports { constants::parachains, create_x2_parachain_multilocation, get_all_module_accounts, AcalaFoundationAccounts, AcalaOracle, AccountId, AuctionManager, Authority, AuthoritysOriginId, Balance, Balances, BlockNumber, Call, CdpEngine, CdpTreasury, CreateClassDeposit, CreateTokenDeposit, Currencies, CurrencyId, CurrencyIdConvert, - DataDepositPerByte, Dex, EmergencyShutdown, Event, EvmAccounts, ExistentialDeposits, Get, GetNativeCurrencyId, - HomaLite, Honzon, Loans, MinimumDebitValue, MultiLocation, NativeTokenExistentialDeposit, NetworkId, - NftPalletId, OneDay, Origin, OriginCaller, ParachainAccount, ParachainInfo, ParachainSystem, Perbill, Permill, - Proxy, ProxyType, RelayChainBlockNumberProvider, RelayChainSovereignSubAccount, Runtime, Scheduler, Session, - SessionManager, SevenDays, System, Timestamp, TokenSymbol, Tokens, TreasuryPalletId, Utility, Vesting, XTokens, - XcmConfig, XcmExecutor, XcmUnbondFee, NFT, + DataDepositPerByte, DefaultExchangeRate, Dex, EmergencyShutdown, Event, EvmAccounts, ExistentialDeposits, Get, + GetNativeCurrencyId, HomaLite, Honzon, Loans, MinimumDebitValue, MultiLocation, NativeTokenExistentialDeposit, + NetworkId, NftPalletId, OneDay, Origin, OriginCaller, ParachainAccount, ParachainInfo, ParachainSystem, + Perbill, Permill, Proxy, ProxyType, RelayChainBlockNumberProvider, RelayChainSovereignSubAccount, Runtime, + Scheduler, Session, SessionManager, SevenDays, System, Timestamp, TokenSymbol, Tokens, TreasuryPalletId, + Utility, Vesting, XTokens, XcmConfig, XcmExecutor, XcmUnbondFee, NFT, }; pub use frame_support::parameter_types; pub use primitives::TradingPair; @@ -285,13 +286,21 @@ impl ExtBuilder { ) .unwrap(); + >::assimilate_storage( + &pallet_xcm::GenesisConfig { + safe_xcm_version: Some(2), + }, + &mut t, + ) + .unwrap(); + let mut ext = sp_io::TestExternalities::new(t); ext.execute_with(|| System::set_block_number(1)); ext } } -pub fn set_oracle_price(prices: Vec<(CurrencyId, Price)>) -> DispatchResult { +pub fn set_oracle_price(prices: Vec<(CurrencyId, Price)>) { AcalaOracle::on_finalize(0); assert_ok!(AcalaOracle::feed_values( Origin::signed(AccountId::from(ORACLE1)), @@ -313,7 +322,6 @@ pub fn set_oracle_price(prices: Vec<(CurrencyId, Price)>) -> DispatchResult { Origin::signed(AccountId::from(ORACLE5)), prices, )); - Ok(()) } pub fn alice_key() -> libsecp256k1::SecretKey { diff --git a/runtime/karura/src/lib.rs b/runtime/karura/src/lib.rs index 39a79f147..5bd38da31 100644 --- a/runtime/karura/src/lib.rs +++ b/runtime/karura/src/lib.rs @@ -794,7 +794,7 @@ impl module_prices::Config for Runtime { type GetStakingCurrencyId = GetStakingCurrencyId; type GetLiquidCurrencyId = GetLiquidCurrencyId; type LockOrigin = EnsureRootOrTwoThirdsGeneralCouncil; - type LiquidStakingExchangeRateProvider = module_homa_lite::LiquidExchangeProvider; + type LiquidStakingExchangeRateProvider = HomaLite; type DEX = Dex; type Currency = Currencies; type CurrencyIdMapping = EvmCurrencyIdMapping; diff --git a/runtime/mandala/src/lib.rs b/runtime/mandala/src/lib.rs index 9b4cc01ec..8da8dc693 100644 --- a/runtime/mandala/src/lib.rs +++ b/runtime/mandala/src/lib.rs @@ -55,6 +55,7 @@ use module_evm::{CallInfo, CreateInfo}; use module_evm_accounts::EvmAddressMapping; pub use module_evm_manager::EvmCurrencyIdMapping; use module_relaychain::RelayChainCallBuilder; +use module_support::ExchangeRateProvider; use module_transaction_payment::{Multiplier, TargetedFeeAdjustment}; use scale_info::TypeInfo;