diff --git a/runtime/integration-tests/src/authority.rs b/runtime/integration-tests/src/authority.rs
new file mode 100644
index 000000000..345ed9eaa
--- /dev/null
+++ b/runtime/integration-tests/src/authority.rs
@@ -0,0 +1,268 @@
+// 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 frame_support::traits::{schedule::DispatchTime, OriginTrait};
+use orml_authority::DelayedOrigin;
+
+#[test]
+fn test_authority_module() {
+ #[cfg(feature = "with-mandala-runtime")]
+ const AUTHORITY_ORIGIN_ID: u8 = 70u8;
+
+ #[cfg(feature = "with-karura-runtime")]
+ const AUTHORITY_ORIGIN_ID: u8 = 60u8;
+
+ ExtBuilder::default()
+ .balances(vec![
+ (AccountId::from(ALICE), USD_CURRENCY, 1_000 * dollar(USD_CURRENCY)),
+ (
+ AccountId::from(ALICE),
+ RELAY_CHAIN_CURRENCY,
+ 1_000 * dollar(RELAY_CHAIN_CURRENCY),
+ ),
+ (TreasuryAccount::get(), USD_CURRENCY, 1_000 * dollar(USD_CURRENCY)),
+ ])
+ .build()
+ .execute_with(|| {
+ let ensure_root_call = Call::System(frame_system::Call::fill_block { ratio: Perbill::one() });
+ let call = Call::Authority(orml_authority::Call::dispatch_as {
+ as_origin: AuthoritysOriginId::Root,
+ call: Box::new(ensure_root_call.clone()),
+ });
+
+ // dispatch_as
+ assert_ok!(Authority::dispatch_as(
+ Origin::root(),
+ AuthoritysOriginId::Root,
+ Box::new(ensure_root_call.clone())
+ ));
+
+ assert_noop!(
+ Authority::dispatch_as(
+ Origin::signed(AccountId::from(BOB)),
+ AuthoritysOriginId::Root,
+ Box::new(ensure_root_call.clone())
+ ),
+ BadOrigin
+ );
+
+ assert_noop!(
+ Authority::dispatch_as(
+ Origin::signed(AccountId::from(BOB)),
+ AuthoritysOriginId::Treasury,
+ Box::new(ensure_root_call.clone())
+ ),
+ BadOrigin
+ );
+
+ // schedule_dispatch
+ run_to_block(1);
+ // Treasury transfer
+ let transfer_call = Call::Currencies(module_currencies::Call::transfer {
+ dest: AccountId::from(BOB).into(),
+ currency_id: USD_CURRENCY,
+ amount: 500 * dollar(USD_CURRENCY),
+ });
+ let treasury_reserve_call = Call::Authority(orml_authority::Call::dispatch_as {
+ as_origin: AuthoritysOriginId::Treasury,
+ call: Box::new(transfer_call.clone()),
+ });
+
+ let one_day_later = OneDay::get() + 1;
+
+ assert_ok!(Authority::schedule_dispatch(
+ Origin::root(),
+ DispatchTime::At(one_day_later),
+ 0,
+ true,
+ Box::new(treasury_reserve_call.clone())
+ ));
+
+ assert_ok!(Authority::schedule_dispatch(
+ Origin::root(),
+ DispatchTime::At(one_day_later),
+ 0,
+ true,
+ Box::new(call.clone())
+ ));
+ System::assert_last_event(Event::Authority(orml_authority::Event::Scheduled(
+ OriginCaller::Authority(DelayedOrigin {
+ delay: one_day_later - 1,
+ origin: Box::new(OriginCaller::system(RawOrigin::Root)),
+ }),
+ 1,
+ )));
+
+ run_to_block(one_day_later);
+
+ assert_eq!(
+ Currencies::free_balance(USD_CURRENCY, &TreasuryPalletId::get().into_account()),
+ 500 * dollar(USD_CURRENCY)
+ );
+ assert_eq!(
+ Currencies::free_balance(USD_CURRENCY, &AccountId::from(BOB)),
+ 500 * dollar(USD_CURRENCY)
+ );
+
+ // delay < SevenDays
+ #[cfg(feature = "with-mandala-runtime")]
+ System::assert_last_event(Event::Scheduler(pallet_scheduler::Event::::Dispatched(
+ (OneDay::get() + 1, 1),
+ Some([AUTHORITY_ORIGIN_ID, 64, 56, 0, 0, 0, 0, 1, 0, 0, 0].to_vec()),
+ Err(DispatchError::BadOrigin),
+ )));
+ #[cfg(feature = "with-karura-runtime")]
+ System::assert_last_event(Event::Scheduler(pallet_scheduler::Event::::Dispatched(
+ (OneDay::get() + 1, 1),
+ Some([AUTHORITY_ORIGIN_ID, 32, 28, 0, 0, 0, 0, 1, 0, 0, 0].to_vec()),
+ Err(DispatchError::BadOrigin),
+ )));
+
+ let seven_days_later = one_day_later + SevenDays::get() + 1;
+
+ // delay = SevenDays
+ assert_ok!(Authority::schedule_dispatch(
+ Origin::root(),
+ DispatchTime::At(seven_days_later),
+ 0,
+ true,
+ Box::new(call.clone())
+ ));
+
+ run_to_block(seven_days_later);
+
+ #[cfg(feature = "with-mandala-runtime")]
+ System::assert_last_event(Event::Scheduler(pallet_scheduler::Event::::Dispatched(
+ (seven_days_later, 0),
+ Some([AUTHORITY_ORIGIN_ID, 193, 137, 1, 0, 0, 0, 2, 0, 0, 0].to_vec()),
+ Ok(()),
+ )));
+
+ #[cfg(feature = "with-karura-runtime")]
+ System::assert_last_event(Event::Scheduler(pallet_scheduler::Event::::Dispatched(
+ (seven_days_later, 0),
+ Some([AUTHORITY_ORIGIN_ID, 225, 196, 0, 0, 0, 0, 2, 0, 0, 0].to_vec()),
+ Ok(()),
+ )));
+
+ // with_delayed_origin = false
+ assert_ok!(Authority::schedule_dispatch(
+ Origin::root(),
+ DispatchTime::At(seven_days_later + 1),
+ 0,
+ false,
+ Box::new(call.clone())
+ ));
+ System::assert_last_event(Event::Authority(orml_authority::Event::Scheduled(
+ OriginCaller::system(RawOrigin::Root),
+ 3,
+ )));
+
+ run_to_block(seven_days_later + 1);
+ System::assert_last_event(Event::Scheduler(pallet_scheduler::Event::::Dispatched(
+ (seven_days_later + 1, 0),
+ Some([0, 0, 3, 0, 0, 0].to_vec()),
+ Ok(()),
+ )));
+
+ assert_ok!(Authority::schedule_dispatch(
+ Origin::root(),
+ DispatchTime::At(seven_days_later + 2),
+ 0,
+ false,
+ Box::new(call.clone())
+ ));
+
+ // fast_track_scheduled_dispatch
+ assert_ok!(Authority::fast_track_scheduled_dispatch(
+ Origin::root(),
+ Box::new(frame_system::RawOrigin::Root.into()),
+ 4,
+ DispatchTime::At(seven_days_later + 3),
+ ));
+
+ // delay_scheduled_dispatch
+ assert_ok!(Authority::delay_scheduled_dispatch(
+ Origin::root(),
+ Box::new(frame_system::RawOrigin::Root.into()),
+ 4,
+ 4,
+ ));
+
+ // cancel_scheduled_dispatch
+ assert_ok!(Authority::schedule_dispatch(
+ Origin::root(),
+ DispatchTime::At(seven_days_later + 2),
+ 0,
+ true,
+ Box::new(call.clone())
+ ));
+ System::assert_last_event(Event::Authority(orml_authority::Event::Scheduled(
+ OriginCaller::Authority(DelayedOrigin {
+ delay: 1,
+ origin: Box::new(OriginCaller::system(RawOrigin::Root)),
+ }),
+ 5,
+ )));
+
+ let schedule_origin = {
+ let origin: ::Origin = From::from(Origin::root());
+ let origin: ::Origin = From::from(DelayedOrigin::<
+ BlockNumber,
+ ::PalletsOrigin,
+ > {
+ delay: 1,
+ origin: Box::new(origin.caller().clone()),
+ });
+ origin
+ };
+
+ let pallets_origin = Box::new(schedule_origin.caller().clone());
+ assert_ok!(Authority::cancel_scheduled_dispatch(Origin::root(), pallets_origin, 5));
+ System::assert_last_event(Event::Authority(orml_authority::Event::Cancelled(
+ OriginCaller::Authority(DelayedOrigin {
+ delay: 1,
+ origin: Box::new(OriginCaller::system(RawOrigin::Root)),
+ }),
+ 5,
+ )));
+
+ assert_ok!(Authority::schedule_dispatch(
+ Origin::root(),
+ DispatchTime::At(seven_days_later + 3),
+ 0,
+ false,
+ Box::new(call.clone())
+ ));
+ System::assert_last_event(Event::Authority(orml_authority::Event::Scheduled(
+ OriginCaller::system(RawOrigin::Root),
+ 6,
+ )));
+
+ assert_ok!(Authority::cancel_scheduled_dispatch(
+ Origin::root(),
+ Box::new(frame_system::RawOrigin::Root.into()),
+ 6
+ ));
+ System::assert_last_event(Event::Authority(orml_authority::Event::Cancelled(
+ OriginCaller::system(RawOrigin::Root),
+ 6,
+ )));
+ });
+}
diff --git a/runtime/integration-tests/src/dex.rs b/runtime/integration-tests/src/dex.rs
new file mode 100644
index 000000000..02f3a0ff5
--- /dev/null
+++ b/runtime/integration-tests/src/dex.rs
@@ -0,0 +1,166 @@
+// 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::*;
+
+#[test]
+fn test_dex_module() {
+ ExtBuilder::default()
+ .balances(vec![
+ (
+ // NetworkContractSource
+ MockAddressMapping::get_account_id(&H160::from_low_u64_be(0)),
+ NATIVE_CURRENCY,
+ 1_000_000_000 * dollar(NATIVE_CURRENCY),
+ ),
+ (
+ AccountId::from(ALICE),
+ USD_CURRENCY,
+ 1_000_000_000 * dollar(NATIVE_CURRENCY),
+ ),
+ (
+ AccountId::from(ALICE),
+ RELAY_CHAIN_CURRENCY,
+ 1_000_000_000 * dollar(NATIVE_CURRENCY),
+ ),
+ (AccountId::from(BOB), USD_CURRENCY, 1_000_000 * dollar(NATIVE_CURRENCY)),
+ (
+ AccountId::from(BOB),
+ RELAY_CHAIN_CURRENCY,
+ 1_000_000_000 * dollar(NATIVE_CURRENCY),
+ ),
+ ])
+ .build()
+ .execute_with(|| {
+ assert_eq!(Dex::get_liquidity_pool(RELAY_CHAIN_CURRENCY, USD_CURRENCY), (0, 0));
+ assert_eq!(Currencies::total_issuance(LPTOKEN), 0);
+ assert_eq!(Currencies::free_balance(LPTOKEN, &AccountId::from(ALICE)), 0);
+
+ assert_noop!(
+ Dex::add_liquidity(
+ Origin::signed(AccountId::from(ALICE)),
+ RELAY_CHAIN_CURRENCY,
+ USD_CURRENCY,
+ 0,
+ 10_000_000 * dollar(USD_CURRENCY),
+ 0,
+ false,
+ ),
+ module_dex::Error::::InvalidLiquidityIncrement,
+ );
+
+ assert_ok!(Dex::add_liquidity(
+ Origin::signed(AccountId::from(ALICE)),
+ RELAY_CHAIN_CURRENCY,
+ USD_CURRENCY,
+ 10_000 * dollar(RELAY_CHAIN_CURRENCY),
+ 10_000_000 * dollar(USD_CURRENCY),
+ 0,
+ false,
+ ));
+
+ let add_liquidity_event = Event::Dex(module_dex::Event::AddLiquidity(
+ AccountId::from(ALICE),
+ USD_CURRENCY,
+ 10_000_000 * dollar(USD_CURRENCY),
+ RELAY_CHAIN_CURRENCY,
+ 10_000 * dollar(RELAY_CHAIN_CURRENCY),
+ 20_000_000 * dollar(USD_CURRENCY),
+ ));
+ assert!(System::events()
+ .iter()
+ .any(|record| record.event == add_liquidity_event));
+
+ assert_eq!(
+ Dex::get_liquidity_pool(RELAY_CHAIN_CURRENCY, USD_CURRENCY),
+ (10_000 * dollar(RELAY_CHAIN_CURRENCY), 10_000_000 * dollar(USD_CURRENCY))
+ );
+ assert_eq!(Currencies::total_issuance(LPTOKEN), 20_000_000 * dollar(USD_CURRENCY));
+ assert_eq!(
+ Currencies::free_balance(LPTOKEN, &AccountId::from(ALICE)),
+ 20_000_000 * dollar(USD_CURRENCY)
+ );
+ assert_ok!(Dex::add_liquidity(
+ Origin::signed(AccountId::from(BOB)),
+ RELAY_CHAIN_CURRENCY,
+ USD_CURRENCY,
+ 1 * dollar(RELAY_CHAIN_CURRENCY),
+ 1_000 * dollar(USD_CURRENCY),
+ 0,
+ false,
+ ));
+ assert_eq!(
+ Dex::get_liquidity_pool(RELAY_CHAIN_CURRENCY, USD_CURRENCY),
+ (10_001 * dollar(RELAY_CHAIN_CURRENCY), 10_001_000 * dollar(USD_CURRENCY))
+ );
+ assert_eq!(Currencies::total_issuance(LPTOKEN), 20_002_000 * dollar(USD_CURRENCY));
+ assert_eq!(
+ Currencies::free_balance(LPTOKEN, &AccountId::from(BOB)),
+ 2000 * dollar(USD_CURRENCY)
+ );
+ assert_noop!(
+ Dex::add_liquidity(
+ Origin::signed(AccountId::from(BOB)),
+ RELAY_CHAIN_CURRENCY,
+ USD_CURRENCY,
+ 1,
+ 999,
+ 0,
+ false,
+ ),
+ module_dex::Error::::InvalidLiquidityIncrement,
+ );
+ assert_eq!(
+ Dex::get_liquidity_pool(RELAY_CHAIN_CURRENCY, USD_CURRENCY),
+ (10_001 * dollar(RELAY_CHAIN_CURRENCY), 10_001_000 * dollar(USD_CURRENCY))
+ );
+ assert_eq!(Currencies::total_issuance(LPTOKEN), 20_002_000 * dollar(USD_CURRENCY));
+ assert_eq!(
+ Currencies::free_balance(LPTOKEN, &AccountId::from(BOB)),
+ 2_000 * dollar(USD_CURRENCY)
+ );
+ assert_ok!(Dex::add_liquidity(
+ Origin::signed(AccountId::from(BOB)),
+ RELAY_CHAIN_CURRENCY,
+ USD_CURRENCY,
+ 2 * dollar(RELAY_CHAIN_CURRENCY),
+ 1_000 * dollar(USD_CURRENCY),
+ 0,
+ false,
+ ));
+ assert_eq!(
+ Dex::get_liquidity_pool(RELAY_CHAIN_CURRENCY, USD_CURRENCY),
+ (10_002 * dollar(RELAY_CHAIN_CURRENCY), 10_002_000 * dollar(USD_CURRENCY))
+ );
+ assert_ok!(Dex::add_liquidity(
+ Origin::signed(AccountId::from(BOB)),
+ RELAY_CHAIN_CURRENCY,
+ USD_CURRENCY,
+ 1 * dollar(RELAY_CHAIN_CURRENCY),
+ 1_001 * dollar(USD_CURRENCY),
+ 0,
+ false,
+ ));
+ assert_eq!(
+ Dex::get_liquidity_pool(RELAY_CHAIN_CURRENCY, USD_CURRENCY),
+ (10_003 * dollar(RELAY_CHAIN_CURRENCY), 10_003_000 * dollar(USD_CURRENCY))
+ );
+
+ assert_eq!(Currencies::total_issuance(LPTOKEN), 20_005_999_999_999_999_995);
+ });
+}
diff --git a/runtime/integration-tests/src/evm_tests.rs b/runtime/integration-tests/src/evm.rs
similarity index 90%
rename from runtime/integration-tests/src/evm_tests.rs
rename to runtime/integration-tests/src/evm.rs
index 731e546b8..3cbca1e12 100644
--- a/runtime/integration-tests/src/evm_tests.rs
+++ b/runtime/integration-tests/src/evm.rs
@@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
-use crate::integration_tests::*;
+use crate::setup::*;
use frame_support::assert_ok;
use module_evm_accounts::EvmAddressMapping;
@@ -602,3 +602,59 @@ fn should_not_kill_contract_on_transfer_all_tokens() {
assert!(!System::account_exists(&contract_account_id));
});
}
+
+#[test]
+fn test_evm_accounts_module() {
+ ExtBuilder::default()
+ .balances(vec![(bob(), NATIVE_CURRENCY, 1_000 * dollar(NATIVE_CURRENCY))])
+ .build()
+ .execute_with(|| {
+ assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 0);
+ assert_eq!(Balances::free_balance(bob()), 1_000 * dollar(NATIVE_CURRENCY));
+ assert_ok!(EvmAccounts::claim_account(
+ Origin::signed(AccountId::from(ALICE)),
+ EvmAccounts::eth_address(&alice_key()),
+ EvmAccounts::eth_sign(&alice_key(), &AccountId::from(ALICE).encode(), &[][..])
+ ));
+ System::assert_last_event(Event::EvmAccounts(module_evm_accounts::Event::ClaimAccount(
+ AccountId::from(ALICE),
+ EvmAccounts::eth_address(&alice_key()),
+ )));
+
+ // claim another eth address
+ assert_noop!(
+ EvmAccounts::claim_account(
+ Origin::signed(AccountId::from(ALICE)),
+ EvmAccounts::eth_address(&alice_key()),
+ EvmAccounts::eth_sign(&alice_key(), &AccountId::from(ALICE).encode(), &[][..])
+ ),
+ module_evm_accounts::Error::::AccountIdHasMapped
+ );
+ assert_noop!(
+ EvmAccounts::claim_account(
+ Origin::signed(AccountId::from(BOB)),
+ EvmAccounts::eth_address(&alice_key()),
+ EvmAccounts::eth_sign(&alice_key(), &AccountId::from(BOB).encode(), &[][..])
+ ),
+ module_evm_accounts::Error::::EthAddressHasMapped
+ );
+
+ // evm padded address will transfer_all to origin.
+ assert_eq!(Balances::free_balance(bob()), 1_000 * dollar(NATIVE_CURRENCY));
+ assert_eq!(Balances::free_balance(&AccountId::from(BOB)), 0);
+ assert_eq!(System::providers(&bob()), 1);
+ assert_eq!(System::providers(&AccountId::from(BOB)), 0);
+ assert_ok!(EvmAccounts::claim_account(
+ Origin::signed(AccountId::from(BOB)),
+ EvmAccounts::eth_address(&bob_key()),
+ EvmAccounts::eth_sign(&bob_key(), &AccountId::from(BOB).encode(), &[][..])
+ ));
+ assert_eq!(System::providers(&bob()), 0);
+ assert_eq!(System::providers(&AccountId::from(BOB)), 1);
+ assert_eq!(Balances::free_balance(bob()), 0);
+ assert_eq!(
+ Balances::free_balance(&AccountId::from(BOB)),
+ 1_000 * dollar(NATIVE_CURRENCY)
+ );
+ });
+}
diff --git a/runtime/integration-tests/src/homa_lite_tests.rs b/runtime/integration-tests/src/homa_lite.rs
similarity index 99%
rename from runtime/integration-tests/src/homa_lite_tests.rs
rename to runtime/integration-tests/src/homa_lite.rs
index ddd0b34d7..954b77372 100644
--- a/runtime/integration-tests/src/homa_lite_tests.rs
+++ b/runtime/integration-tests/src/homa_lite.rs
@@ -20,7 +20,7 @@
#[cfg(any(feature = "with-mandala-runtime", feature = "with-karura-runtime"))]
mod common_tests {
- use crate::integration_tests::*;
+ use crate::setup::*;
use frame_support::{assert_noop, assert_ok};
use orml_traits::{MultiCurrency, MultiReservableCurrency};
@@ -248,14 +248,13 @@ mod common_tests {
#[cfg(feature = "with-karura-runtime")]
mod karura_only_tests {
- use crate::integration_tests::*;
- use crate::kusama_test_net::*;
+ use crate::relaychain::kusama_test_net::*;
+ use crate::setup::*;
use frame_support::{assert_ok, traits::Hooks};
use orml_traits::MultiCurrency;
use sp_runtime::{traits::BlockNumberProvider, MultiAddress};
- use xcm::latest::prelude::*;
use xcm_emulator::TestExt;
#[test]
diff --git a/runtime/integration-tests/src/honzon.rs b/runtime/integration-tests/src/honzon.rs
new file mode 100644
index 000000000..2bf6b9d77
--- /dev/null
+++ b/runtime/integration-tests/src/honzon.rs
@@ -0,0 +1,575 @@
+// 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_cdp_engine::LiquidationStrategy;
+
+#[test]
+fn emergency_shutdown_and_cdp_treasury() {
+ ExtBuilder::default()
+ .balances(vec![
+ (AccountId::from(ALICE), USD_CURRENCY, 2_000_000 * dollar(USD_CURRENCY)),
+ (AccountId::from(BOB), USD_CURRENCY, 8_000_000 * dollar(USD_CURRENCY)),
+ (
+ AccountId::from(BOB),
+ RELAY_CHAIN_CURRENCY,
+ 300_000_000 * dollar(RELAY_CHAIN_CURRENCY),
+ ),
+ (
+ AccountId::from(BOB),
+ LIQUID_CURRENCY,
+ 50_000_000 * dollar(LIQUID_CURRENCY),
+ ),
+ ])
+ .build()
+ .execute_with(|| {
+ assert_ok!(CdpTreasury::deposit_collateral(
+ &AccountId::from(BOB),
+ RELAY_CHAIN_CURRENCY,
+ 200_000_000 * dollar(RELAY_CHAIN_CURRENCY)
+ ));
+ assert_ok!(CdpTreasury::deposit_collateral(
+ &AccountId::from(BOB),
+ LIQUID_CURRENCY,
+ 40_000_000 * dollar(LIQUID_CURRENCY)
+ ));
+ assert_eq!(
+ CdpTreasury::total_collaterals(RELAY_CHAIN_CURRENCY),
+ 200_000_000 * dollar(RELAY_CHAIN_CURRENCY)
+ );
+ assert_eq!(
+ CdpTreasury::total_collaterals(LIQUID_CURRENCY),
+ 40_000_000 * dollar(LIQUID_CURRENCY)
+ );
+
+ // Total liquidity to collaterize is calculated using Stable currency - USD
+ assert_noop!(
+ EmergencyShutdown::refund_collaterals(
+ Origin::signed(AccountId::from(ALICE)),
+ 1_000_000 * dollar(USD_CURRENCY)
+ ),
+ module_emergency_shutdown::Error::::CanNotRefund,
+ );
+ assert_ok!(EmergencyShutdown::emergency_shutdown(Origin::root()));
+ assert_ok!(EmergencyShutdown::open_collateral_refund(Origin::root()));
+ assert_ok!(EmergencyShutdown::refund_collaterals(
+ Origin::signed(AccountId::from(ALICE)),
+ 1_000_000 * dollar(USD_CURRENCY)
+ ));
+
+ assert_eq!(
+ CdpTreasury::total_collaterals(RELAY_CHAIN_CURRENCY),
+ 180_000_000 * dollar(RELAY_CHAIN_CURRENCY)
+ );
+ assert_eq!(
+ CdpTreasury::total_collaterals(LIQUID_CURRENCY),
+ 36_000_000 * dollar(LIQUID_CURRENCY)
+ );
+ assert_eq!(
+ Currencies::free_balance(USD_CURRENCY, &AccountId::from(ALICE)),
+ 1_000_000 * dollar(USD_CURRENCY)
+ );
+ assert_eq!(
+ Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(ALICE)),
+ 20_000_000 * dollar(RELAY_CHAIN_CURRENCY)
+ );
+ assert_eq!(
+ Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(ALICE)),
+ 4_000_000 * dollar(LIQUID_CURRENCY)
+ );
+ });
+}
+
+#[test]
+fn liquidate_cdp() {
+ ExtBuilder::default()
+ .balances(vec![
+ (
+ AccountId::from(ALICE),
+ RELAY_CHAIN_CURRENCY,
+ 51 * dollar(RELAY_CHAIN_CURRENCY),
+ ),
+ (AccountId::from(BOB), USD_CURRENCY, 1_000_001 * dollar(USD_CURRENCY)),
+ (
+ AccountId::from(BOB),
+ RELAY_CHAIN_CURRENCY,
+ 102 * dollar(RELAY_CHAIN_CURRENCY),
+ ),
+ ])
+ .build()
+ .execute_with(|| {
+ assert_ok!(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)),
+ RELAY_CHAIN_CURRENCY,
+ USD_CURRENCY,
+ 100 * dollar(RELAY_CHAIN_CURRENCY),
+ 1_000_000 * dollar(USD_CURRENCY),
+ 0,
+ false,
+ ));
+
+ assert_ok!(CdpEngine::set_collateral_params(
+ Origin::root(),
+ RELAY_CHAIN_CURRENCY,
+ Change::NewValue(Some(Rate::zero())),
+ Change::NewValue(Some(Ratio::saturating_from_rational(200, 100))),
+ Change::NewValue(Some(Rate::saturating_from_rational(20, 100))),
+ Change::NewValue(Some(Ratio::saturating_from_rational(200, 100))),
+ Change::NewValue(1_000_000 * dollar(USD_CURRENCY)),
+ ));
+
+ assert_ok!(CdpEngine::adjust_position(
+ &AccountId::from(ALICE),
+ RELAY_CHAIN_CURRENCY,
+ (50 * dollar(RELAY_CHAIN_CURRENCY)) as i128,
+ (2_500_000 * dollar(USD_CURRENCY)) as i128,
+ ));
+
+ assert_ok!(CdpEngine::adjust_position(
+ &AccountId::from(BOB),
+ RELAY_CHAIN_CURRENCY,
+ dollar(RELAY_CHAIN_CURRENCY) as i128,
+ (50_000 * dollar(USD_CURRENCY)) as i128,
+ ));
+
+ assert_eq!(
+ Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).debit,
+ 2_500_000 * dollar(USD_CURRENCY)
+ );
+ assert_eq!(
+ Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).collateral,
+ 50 * dollar(RELAY_CHAIN_CURRENCY)
+ );
+ assert_eq!(
+ Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(BOB)).debit,
+ 50_000 * dollar(USD_CURRENCY)
+ );
+ assert_eq!(
+ Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(BOB)).collateral,
+ dollar(RELAY_CHAIN_CURRENCY)
+ );
+ assert_eq!(CdpTreasury::debit_pool(), 0);
+ assert_eq!(AuctionManager::collateral_auctions(0), None);
+
+ assert_ok!(CdpEngine::set_collateral_params(
+ Origin::root(),
+ RELAY_CHAIN_CURRENCY,
+ Change::NoChange,
+ Change::NewValue(Some(Ratio::saturating_from_rational(400, 100))),
+ Change::NoChange,
+ Change::NewValue(Some(Ratio::saturating_from_rational(400, 100))),
+ Change::NoChange,
+ ));
+
+ assert_ok!(CdpEngine::liquidate_unsafe_cdp(
+ AccountId::from(ALICE),
+ RELAY_CHAIN_CURRENCY
+ ));
+
+ let liquidate_alice_xbtc_cdp_event = Event::CdpEngine(module_cdp_engine::Event::LiquidateUnsafeCDP(
+ RELAY_CHAIN_CURRENCY,
+ AccountId::from(ALICE),
+ 50 * dollar(RELAY_CHAIN_CURRENCY),
+ 250_000 * dollar(USD_CURRENCY),
+ LiquidationStrategy::Auction,
+ ));
+
+ assert!(System::events()
+ .iter()
+ .any(|record| record.event == liquidate_alice_xbtc_cdp_event));
+
+ assert_eq!(Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).debit, 0);
+ assert_eq!(
+ Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).collateral,
+ 0
+ );
+ assert!(AuctionManager::collateral_auctions(0).is_some());
+ assert_eq!(CdpTreasury::debit_pool(), 250_000 * dollar(USD_CURRENCY));
+
+ assert_ok!(CdpEngine::liquidate_unsafe_cdp(
+ AccountId::from(BOB),
+ RELAY_CHAIN_CURRENCY
+ ));
+
+ let liquidate_bob_xbtc_cdp_event = Event::CdpEngine(module_cdp_engine::Event::LiquidateUnsafeCDP(
+ RELAY_CHAIN_CURRENCY,
+ AccountId::from(BOB),
+ dollar(RELAY_CHAIN_CURRENCY),
+ 5_000 * dollar(USD_CURRENCY),
+ LiquidationStrategy::Exchange,
+ ));
+ assert!(System::events()
+ .iter()
+ .any(|record| record.event == liquidate_bob_xbtc_cdp_event));
+
+ assert_eq!(Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(BOB)).debit, 0);
+ assert_eq!(
+ Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(BOB)).collateral,
+ 0
+ );
+ assert_eq!(CdpTreasury::debit_pool(), 255_000 * dollar(USD_CURRENCY));
+ assert!(CdpTreasury::surplus_pool() >= 5_000 * dollar(USD_CURRENCY));
+ });
+}
+
+#[test]
+fn test_honzon_module() {
+ ExtBuilder::default()
+ .balances(vec![(
+ AccountId::from(ALICE),
+ RELAY_CHAIN_CURRENCY,
+ 1_000 * dollar(RELAY_CHAIN_CURRENCY),
+ )])
+ .build()
+ .execute_with(|| {
+ assert_ok!(set_oracle_price(vec![(
+ RELAY_CHAIN_CURRENCY,
+ Price::saturating_from_rational(1, 1)
+ )]));
+
+ assert_ok!(CdpEngine::set_collateral_params(
+ Origin::root(),
+ RELAY_CHAIN_CURRENCY,
+ Change::NewValue(Some(Rate::saturating_from_rational(1, 100000))),
+ Change::NewValue(Some(Ratio::saturating_from_rational(3, 2))),
+ Change::NewValue(Some(Rate::saturating_from_rational(2, 10))),
+ Change::NewValue(Some(Ratio::saturating_from_rational(9, 5))),
+ Change::NewValue(10_000 * dollar(USD_CURRENCY)),
+ ));
+ assert_ok!(CdpEngine::adjust_position(
+ &AccountId::from(ALICE),
+ RELAY_CHAIN_CURRENCY,
+ (100 * dollar(RELAY_CHAIN_CURRENCY)) as i128,
+ (500 * dollar(USD_CURRENCY)) as i128
+ ));
+ assert_eq!(
+ Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(ALICE)),
+ 900 * dollar(RELAY_CHAIN_CURRENCY)
+ );
+ assert_eq!(
+ Currencies::free_balance(USD_CURRENCY, &AccountId::from(ALICE)),
+ 50 * dollar(USD_CURRENCY)
+ );
+ assert_eq!(
+ Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).debit,
+ 500 * dollar(USD_CURRENCY)
+ );
+ assert_eq!(
+ Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).collateral,
+ 100 * dollar(RELAY_CHAIN_CURRENCY)
+ );
+ assert_eq!(
+ CdpEngine::liquidate(
+ Origin::none(),
+ RELAY_CHAIN_CURRENCY,
+ MultiAddress::Id(AccountId::from(ALICE))
+ )
+ .is_ok(),
+ false
+ );
+ assert_ok!(CdpEngine::set_collateral_params(
+ Origin::root(),
+ RELAY_CHAIN_CURRENCY,
+ Change::NoChange,
+ Change::NewValue(Some(Ratio::saturating_from_rational(3, 1))),
+ Change::NoChange,
+ Change::NoChange,
+ Change::NoChange,
+ ));
+ assert_ok!(CdpEngine::liquidate(
+ Origin::none(),
+ RELAY_CHAIN_CURRENCY,
+ MultiAddress::Id(AccountId::from(ALICE))
+ ));
+
+ assert_eq!(
+ Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(ALICE)),
+ 900 * dollar(RELAY_CHAIN_CURRENCY)
+ );
+ assert_eq!(
+ Currencies::free_balance(USD_CURRENCY, &AccountId::from(ALICE)),
+ 50 * dollar(USD_CURRENCY)
+ );
+ assert_eq!(Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).debit, 0);
+ assert_eq!(
+ Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).collateral,
+ 0
+ );
+ });
+}
+
+#[test]
+fn test_cdp_engine_module() {
+ ExtBuilder::default()
+ .balances(vec![
+ (AccountId::from(ALICE), USD_CURRENCY, 2_000 * dollar(USD_CURRENCY)),
+ (
+ AccountId::from(ALICE),
+ RELAY_CHAIN_CURRENCY,
+ 2_000 * dollar(RELAY_CHAIN_CURRENCY),
+ ),
+ ])
+ .build()
+ .execute_with(|| {
+ assert_ok!(CdpEngine::set_collateral_params(
+ Origin::root(),
+ RELAY_CHAIN_CURRENCY,
+ Change::NewValue(Some(Rate::saturating_from_rational(1, 100000))),
+ Change::NewValue(Some(Ratio::saturating_from_rational(3, 2))),
+ Change::NewValue(Some(Rate::saturating_from_rational(2, 10))),
+ Change::NewValue(Some(Ratio::saturating_from_rational(9, 5))),
+ Change::NewValue(10_000 * dollar(USD_CURRENCY)),
+ ));
+
+ let new_collateral_params = CdpEngine::collateral_params(RELAY_CHAIN_CURRENCY);
+
+ assert_eq!(
+ new_collateral_params.interest_rate_per_sec,
+ Some(Rate::saturating_from_rational(1, 100000))
+ );
+ assert_eq!(
+ new_collateral_params.liquidation_ratio,
+ Some(Ratio::saturating_from_rational(3, 2))
+ );
+ assert_eq!(
+ new_collateral_params.liquidation_penalty,
+ Some(Rate::saturating_from_rational(2, 10))
+ );
+ assert_eq!(
+ new_collateral_params.required_collateral_ratio,
+ Some(Ratio::saturating_from_rational(9, 5))
+ );
+ assert_eq!(
+ new_collateral_params.maximum_total_debit_value,
+ 10_000 * dollar(USD_CURRENCY)
+ );
+
+ assert_eq!(
+ CdpEngine::calculate_collateral_ratio(
+ RELAY_CHAIN_CURRENCY,
+ 100 * dollar(RELAY_CHAIN_CURRENCY),
+ 50 * dollar(USD_CURRENCY),
+ Price::saturating_from_rational(1 * dollar(USD_CURRENCY), dollar(RELAY_CHAIN_CURRENCY)),
+ ),
+ Ratio::saturating_from_rational(100 * 10, 50)
+ );
+
+ assert_ok!(CdpEngine::check_debit_cap(
+ RELAY_CHAIN_CURRENCY,
+ 99_999 * dollar(USD_CURRENCY)
+ ));
+ assert_eq!(
+ CdpEngine::check_debit_cap(RELAY_CHAIN_CURRENCY, 100_001 * dollar(USD_CURRENCY)).is_ok(),
+ false
+ );
+
+ assert_ok!(CdpEngine::adjust_position(
+ &AccountId::from(ALICE),
+ RELAY_CHAIN_CURRENCY,
+ (200 * dollar(RELAY_CHAIN_CURRENCY)) as i128,
+ 0
+ ));
+ assert_eq!(
+ Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(ALICE)),
+ 1800 * dollar(RELAY_CHAIN_CURRENCY)
+ );
+ assert_eq!(Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).debit, 0);
+ assert_eq!(
+ Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).collateral,
+ 200 * dollar(RELAY_CHAIN_CURRENCY)
+ );
+
+ assert_noop!(
+ CdpEngine::settle_cdp_has_debit(AccountId::from(ALICE), RELAY_CHAIN_CURRENCY),
+ module_cdp_engine::Error::::NoDebitValue,
+ );
+
+ assert_ok!(set_oracle_price(vec![
+ (USD_CURRENCY, Price::saturating_from_rational(1, 1)),
+ (RELAY_CHAIN_CURRENCY, Price::saturating_from_rational(3, 1))
+ ]));
+
+ assert_ok!(CdpEngine::adjust_position(
+ &AccountId::from(ALICE),
+ RELAY_CHAIN_CURRENCY,
+ 0,
+ (200 * dollar(USD_CURRENCY)) as i128
+ ));
+ assert_eq!(
+ Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).debit,
+ 200 * dollar(USD_CURRENCY)
+ );
+ assert_eq!(CdpTreasury::debit_pool(), 0);
+ assert_eq!(CdpTreasury::total_collaterals(RELAY_CHAIN_CURRENCY), 0);
+ assert_ok!(CdpEngine::settle_cdp_has_debit(
+ AccountId::from(ALICE),
+ RELAY_CHAIN_CURRENCY
+ ));
+
+ let settle_cdp_in_debit_event = Event::CdpEngine(module_cdp_engine::Event::SettleCDPInDebit(
+ RELAY_CHAIN_CURRENCY,
+ AccountId::from(ALICE),
+ ));
+ assert!(System::events()
+ .iter()
+ .any(|record| record.event == settle_cdp_in_debit_event));
+
+ assert_eq!(Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).debit, 0);
+ assert_eq!(CdpTreasury::debit_pool(), 20 * dollar(USD_CURRENCY));
+
+ // DOT is 10 decimal places where as ksm is 12 decimals. Hence the difference in collaterals.
+ #[cfg(feature = "with-mandala-runtime")]
+ assert_eq!(CdpTreasury::total_collaterals(RELAY_CHAIN_CURRENCY), 66_666_666_666);
+ #[cfg(feature = "with-karura-runtime")]
+ assert_eq!(CdpTreasury::total_collaterals(RELAY_CHAIN_CURRENCY), 6_666_666_666_666);
+ });
+}
+
+// Honzon's surplus can be transfered and DebitExchangeRate updates accordingly
+#[test]
+fn cdp_treasury_handles_honzon_surplus_correctly() {
+ ExtBuilder::default()
+ .balances(vec![
+ (
+ AccountId::from(ALICE),
+ RELAY_CHAIN_CURRENCY,
+ 100 * dollar(RELAY_CHAIN_CURRENCY),
+ ),
+ (AccountId::from(BOB), USD_CURRENCY, 10_000 * dollar(USD_CURRENCY)),
+ (
+ AccountId::from(BOB),
+ RELAY_CHAIN_CURRENCY,
+ 100 * dollar(RELAY_CHAIN_CURRENCY),
+ ),
+ ])
+ .build()
+ .execute_with(|| {
+ System::set_block_number(1);
+ assert_ok!(set_oracle_price(vec![(
+ RELAY_CHAIN_CURRENCY,
+ Price::saturating_from_rational(100, 1)
+ )]));
+ assert_ok!(CdpEngine::set_collateral_params(
+ Origin::root(),
+ RELAY_CHAIN_CURRENCY,
+ Change::NewValue(Some(Rate::saturating_from_rational(1, 10000))),
+ Change::NewValue(Some(Ratio::saturating_from_rational(200, 100))),
+ Change::NewValue(Some(Rate::saturating_from_rational(20, 100))),
+ Change::NewValue(Some(Ratio::saturating_from_rational(200, 100))),
+ Change::NewValue(1_000_000 * dollar(USD_CURRENCY)),
+ ));
+ assert_ok!(Dex::add_liquidity(
+ Origin::signed(AccountId::from(BOB)),
+ RELAY_CHAIN_CURRENCY,
+ USD_CURRENCY,
+ 100 * dollar(RELAY_CHAIN_CURRENCY),
+ 10_000 * dollar(USD_CURRENCY),
+ 0,
+ false,
+ ));
+
+ // Honzon loans work
+ assert_ok!(Honzon::adjust_loan(
+ Origin::signed(AccountId::from(ALICE)),
+ RELAY_CHAIN_CURRENCY,
+ 50 * dollar(RELAY_CHAIN_CURRENCY) as i128,
+ 500 * dollar(USD_CURRENCY) as i128
+ ));
+ assert_eq!(
+ Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).collateral,
+ 50 * dollar(RELAY_CHAIN_CURRENCY)
+ );
+ assert_eq!(
+ Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).debit,
+ 500 * dollar(USD_CURRENCY)
+ );
+ assert_eq!(
+ Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(ALICE)),
+ 50 * dollar(RELAY_CHAIN_CURRENCY)
+ );
+ assert_eq!(
+ Currencies::free_balance(USD_CURRENCY, &AccountId::from(ALICE)),
+ 50 * dollar(USD_CURRENCY)
+ );
+ assert_eq!(Currencies::free_balance(USD_CURRENCY, &CdpTreasury::account_id()), 0);
+ assert_eq!(CdpTreasury::get_surplus_pool(), 0);
+ assert_eq!(CdpTreasury::get_debit_pool(), 0);
+ run_to_block(2);
+
+ // Empty treasury recieves stablecoins into surplus pool from loan
+ assert_eq!(CdpTreasury::get_surplus_pool(), 160248248179);
+ assert_eq!(CdpTreasury::get_debit_pool(), 0);
+ // Honzon generated cdp treasury surplus can be transfered
+ assert_eq!(Currencies::free_balance(USD_CURRENCY, &AccountId::from(BOB)), 0);
+ assert_eq!(
+ CdpEngine::debit_exchange_rate(RELAY_CHAIN_CURRENCY),
+ // about 1/10
+ Some(Ratio::saturating_from_rational(
+ 100320496496359801 as i64,
+ 1000000000000000000 as i64
+ ))
+ );
+ // Cdp treasury cannot be reaped
+ assert_ok!(Currencies::transfer(
+ Origin::signed(CdpTreasury::account_id()),
+ sp_runtime::MultiAddress::Id(AccountId::from(BOB)),
+ USD_CURRENCY,
+ CdpTreasury::get_surplus_pool() - 1
+ ));
+ assert_eq!(
+ Currencies::free_balance(USD_CURRENCY, &AccountId::from(BOB)),
+ 160248248178
+ );
+ assert_eq!(Currencies::free_balance(USD_CURRENCY, &CdpTreasury::account_id()), 1);
+ run_to_block(3);
+ // Debt exchange rate updates
+ assert_eq!(
+ CdpEngine::debit_exchange_rate(RELAY_CHAIN_CURRENCY),
+ // Around 1/10, increasing from last check
+ Some(Ratio::saturating_from_rational(
+ 100330528546009436 as i64,
+ 1000000000000000000 as i64
+ ))
+ );
+
+ // Closing loan will add to treasury debit_pool
+ assert_ok!(Honzon::close_loan_has_debit_by_dex(
+ Origin::signed(AccountId::from(ALICE)),
+ RELAY_CHAIN_CURRENCY,
+ 5 * dollar(RELAY_CHAIN_CURRENCY),
+ None
+ ));
+ // Just over 50 dollar(USD_CURRENCY), due to interest on loan
+ assert_eq!(CdpTreasury::get_debit_pool(), 50165264273004);
+ assert_eq!(Loans::total_positions(RELAY_CHAIN_CURRENCY).debit, 0);
+ run_to_block(4);
+ // Debt exchange rate doesn't update due to no debit positions
+ assert_eq!(
+ CdpEngine::debit_exchange_rate(RELAY_CHAIN_CURRENCY),
+ Some(Ratio::saturating_from_rational(
+ 100330528546009436 as i64,
+ 1000000000000000000 as i64
+ ))
+ )
+ });
+}
diff --git a/runtime/integration-tests/src/integration_tests.rs b/runtime/integration-tests/src/integration_tests.rs
deleted file mode 100644
index 6d364debd..000000000
--- a/runtime/integration-tests/src/integration_tests.rs
+++ /dev/null
@@ -1,2313 +0,0 @@
-// 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 acala_service::chain_spec::mandala::evm_genesis;
-pub use codec::Encode;
-use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
-use frame_support::{
- assert_noop, assert_ok,
- traits::{schedule::DispatchTime, Currency, GenesisBuild, OnFinalize, OnInitialize, OriginTrait, ValidatorSet},
- weights::constants::*,
-};
-use frame_system::RawOrigin;
-
-use module_cdp_engine::LiquidationStrategy;
-pub use module_support::{
- mocks::MockAddressMapping, AddressMapping, CDPTreasury, DEXManager, Price, Rate, Ratio, RiskManager,
-};
-use orml_authority::DelayedOrigin;
-pub use orml_traits::{location::RelativeLocations, Change, GetByKey, MultiCurrency};
-use orml_vesting::VestingSchedule;
-pub use primitives::currency::*;
-pub use sp_core::H160;
-use sp_io::hashing::keccak_256;
-pub use sp_runtime::{
- traits::{AccountIdConversion, BadOrigin, BlakeTwo256, Convert, Hash, Zero},
- DispatchError, DispatchResult, FixedPointNumber, MultiAddress, Perbill, Permill,
-};
-
-use xcm::latest::prelude::*;
-
-#[cfg(feature = "with-mandala-runtime")]
-pub use mandala_imports::*;
-#[cfg(feature = "with-mandala-runtime")]
-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,
- };
-
- pub use runtime_common::{dollar, ACA, AUSD, DOT, LDOT};
- pub const NATIVE_CURRENCY: CurrencyId = ACA;
- pub const LIQUID_CURRENCY: CurrencyId = LDOT;
- pub const RELAY_CHAIN_CURRENCY: CurrencyId = DOT;
- pub const USD_CURRENCY: CurrencyId = AUSD;
- pub const LPTOKEN: CurrencyId = CurrencyId::DexShare(
- primitives::DexShare::Token(TokenSymbol::AUSD),
- primitives::DexShare::Token(TokenSymbol::DOT),
- );
-}
-
-#[cfg(feature = "with-karura-runtime")]
-pub use karura_imports::*;
-#[cfg(feature = "with-karura-runtime")]
-mod karura_imports {
- pub use frame_support::parameter_types;
- 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,
- };
- pub use primitives::TradingPair;
- pub use runtime_common::{dollar, KAR, KSM, KUSD, LKSM};
- pub use sp_runtime::traits::AccountIdConversion;
-
- parameter_types! {
- pub EnabledTradingPairs: Vec = vec![
- TradingPair::from_currency_ids(USD_CURRENCY, NATIVE_CURRENCY).unwrap(),
- TradingPair::from_currency_ids(USD_CURRENCY, RELAY_CHAIN_CURRENCY).unwrap(),
- TradingPair::from_currency_ids(USD_CURRENCY, LIQUID_CURRENCY).unwrap(),
- ];
- pub TreasuryAccount: AccountId = TreasuryPalletId::get().into_account();
- }
-
- pub const NATIVE_CURRENCY: CurrencyId = KAR;
- pub const LIQUID_CURRENCY: CurrencyId = LKSM;
- pub const RELAY_CHAIN_CURRENCY: CurrencyId = KSM;
- pub const USD_CURRENCY: CurrencyId = KUSD;
- pub const LPTOKEN: CurrencyId = CurrencyId::DexShare(
- primitives::DexShare::Token(TokenSymbol::KUSD),
- primitives::DexShare::Token(TokenSymbol::KSM),
- );
-}
-
-#[cfg(feature = "with-acala-runtime")]
-pub use acala_imports::*;
-#[cfg(feature = "with-acala-runtime")]
-mod acala_imports {
- pub use acala_runtime::{
- 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,
- };
- pub use frame_support::parameter_types;
- pub use primitives::TradingPair;
- pub use runtime_common::{dollar, ACA, AUSD, DOT, LDOT};
- pub use sp_runtime::traits::AccountIdConversion;
-
- parameter_types! {
- pub EnabledTradingPairs: Vec = vec![
- TradingPair::from_currency_ids(USD_CURRENCY, NATIVE_CURRENCY).unwrap(),
- TradingPair::from_currency_ids(USD_CURRENCY, RELAY_CHAIN_CURRENCY).unwrap(),
- TradingPair::from_currency_ids(USD_CURRENCY, LIQUID_CURRENCY).unwrap(),
- ];
- pub TreasuryAccount: AccountId = TreasuryPalletId::get().into_account();
- }
-
- pub const NATIVE_CURRENCY: CurrencyId = ACA;
- pub const LIQUID_CURRENCY: CurrencyId = LDOT;
- pub const RELAY_CHAIN_CURRENCY: CurrencyId = DOT;
- pub const USD_CURRENCY: CurrencyId = AUSD;
- pub const LPTOKEN: CurrencyId = CurrencyId::DexShare(
- primitives::DexShare::Token(TokenSymbol::AUSD),
- primitives::DexShare::Token(TokenSymbol::DOT),
- );
-}
-
-const ORACLE1: [u8; 32] = [0u8; 32];
-const ORACLE2: [u8; 32] = [1u8; 32];
-const ORACLE3: [u8; 32] = [2u8; 32];
-const ORACLE4: [u8; 32] = [3u8; 32];
-const ORACLE5: [u8; 32] = [4u8; 32];
-
-pub const ALICE: [u8; 32] = [4u8; 32];
-pub const BOB: [u8; 32] = [5u8; 32];
-pub const CHARLIE: [u8; 32] = [6u8; 32];
-pub const DAVE: [u8; 32] = [7u8; 32];
-
-pub const INIT_TIMESTAMP: u64 = 30_000;
-pub const BLOCK_TIME: u64 = 1000;
-
-pub fn run_to_block(n: u32) {
- while System::block_number() < n {
- Scheduler::on_finalize(System::block_number());
- System::set_block_number(System::block_number() + 1);
- Timestamp::set_timestamp((System::block_number() as u64 * BLOCK_TIME) + INIT_TIMESTAMP);
- CdpEngine::on_initialize(System::block_number());
- Scheduler::on_initialize(System::block_number());
- Scheduler::on_initialize(System::block_number());
- Session::on_initialize(System::block_number());
- SessionManager::on_initialize(System::block_number());
- }
-}
-
-pub fn set_relaychain_block_number(number: BlockNumber) {
- ParachainSystem::on_initialize(number);
-
- let (relay_storage_root, proof) = RelayStateSproofBuilder::default().into_state_root_and_proof();
-
- assert_ok!(ParachainSystem::set_validation_data(
- Origin::none(),
- cumulus_primitives_parachain_inherent::ParachainInherentData {
- validation_data: cumulus_primitives_core::PersistedValidationData {
- parent_head: Default::default(),
- relay_parent_number: number,
- relay_parent_storage_root: relay_storage_root,
- max_pov_size: Default::default(),
- },
- relay_chain_state: proof,
- downward_messages: Default::default(),
- horizontal_messages: Default::default(),
- }
- ));
-}
-
-pub struct ExtBuilder {
- balances: Vec<(AccountId, CurrencyId, Balance)>,
-}
-
-impl Default for ExtBuilder {
- fn default() -> Self {
- Self { balances: vec![] }
- }
-}
-
-impl ExtBuilder {
- pub fn balances(mut self, balances: Vec<(AccountId, CurrencyId, Balance)>) -> Self {
- self.balances = balances;
- self
- }
-
- pub fn build(self) -> sp_io::TestExternalities {
- let evm_genesis_accounts = evm_genesis();
-
- let mut t = frame_system::GenesisConfig::default()
- .build_storage::()
- .unwrap();
-
- let native_currency_id = GetNativeCurrencyId::get();
- let existential_deposit = NativeTokenExistentialDeposit::get();
- let initial_enabled_trading_pairs = EnabledTradingPairs::get();
-
- module_dex::GenesisConfig:: {
- initial_enabled_trading_pairs: initial_enabled_trading_pairs,
- initial_listing_trading_pairs: Default::default(),
- initial_added_liquidity_pools: vec![],
- }
- .assimilate_storage(&mut t)
- .unwrap();
-
- pallet_balances::GenesisConfig:: {
- balances: self
- .balances
- .clone()
- .into_iter()
- .filter(|(_, currency_id, _)| *currency_id == native_currency_id)
- .map(|(account_id, _, initial_balance)| (account_id, initial_balance))
- .chain(
- get_all_module_accounts()
- .iter()
- .map(|x| (x.clone(), existential_deposit)),
- )
- .collect::>(),
- }
- .assimilate_storage(&mut t)
- .unwrap();
-
- orml_tokens::GenesisConfig:: {
- balances: self
- .balances
- .into_iter()
- .filter(|(_, currency_id, _)| *currency_id != native_currency_id)
- .collect::>(),
- }
- .assimilate_storage(&mut t)
- .unwrap();
-
- pallet_membership::GenesisConfig:: {
- members: vec![
- AccountId::from(ORACLE1),
- AccountId::from(ORACLE2),
- AccountId::from(ORACLE3),
- AccountId::from(ORACLE4),
- AccountId::from(ORACLE5),
- ],
- phantom: Default::default(),
- }
- .assimilate_storage(&mut t)
- .unwrap();
-
- module_evm::GenesisConfig:: {
- accounts: evm_genesis_accounts,
- treasury: Default::default(),
- }
- .assimilate_storage(&mut t)
- .unwrap();
-
- module_session_manager::GenesisConfig:: { session_duration: 10 }
- .assimilate_storage(&mut t)
- .unwrap();
-
- >::assimilate_storage(
- ¶chain_info::GenesisConfig {
- parachain_id: 2000.into(),
- },
- &mut t,
- )
- .unwrap();
-
- let mut ext = sp_io::TestExternalities::new(t);
- ext.execute_with(|| System::set_block_number(1));
- ext
- }
-}
-
-fn set_oracle_price(prices: Vec<(CurrencyId, Price)>) -> DispatchResult {
- AcalaOracle::on_finalize(0);
- assert_ok!(AcalaOracle::feed_values(
- Origin::signed(AccountId::from(ORACLE1)),
- prices.clone(),
- ));
- assert_ok!(AcalaOracle::feed_values(
- Origin::signed(AccountId::from(ORACLE2)),
- prices.clone(),
- ));
- assert_ok!(AcalaOracle::feed_values(
- Origin::signed(AccountId::from(ORACLE3)),
- prices.clone(),
- ));
- assert_ok!(AcalaOracle::feed_values(
- Origin::signed(AccountId::from(ORACLE4)),
- prices.clone(),
- ));
- assert_ok!(AcalaOracle::feed_values(
- Origin::signed(AccountId::from(ORACLE5)),
- prices,
- ));
- Ok(())
-}
-
-pub fn alice_key() -> libsecp256k1::SecretKey {
- libsecp256k1::SecretKey::parse(&keccak_256(b"Alice")).unwrap()
-}
-
-pub fn bob_key() -> libsecp256k1::SecretKey {
- libsecp256k1::SecretKey::parse(&keccak_256(b"Bob")).unwrap()
-}
-
-pub fn alice() -> AccountId {
- let address = EvmAccounts::eth_address(&alice_key());
- let mut data = [0u8; 32];
- data[0..4].copy_from_slice(b"evm:");
- data[4..24].copy_from_slice(&address[..]);
- AccountId::from(Into::<[u8; 32]>::into(data))
-}
-
-pub fn bob() -> AccountId {
- let address = EvmAccounts::eth_address(&bob_key());
- let mut data = [0u8; 32];
- data[0..4].copy_from_slice(b"evm:");
- data[4..24].copy_from_slice(&address[..]);
- AccountId::from(Into::<[u8; 32]>::into(data))
-}
-
-#[test]
-fn emergency_shutdown_and_cdp_treasury() {
- ExtBuilder::default()
- .balances(vec![
- (AccountId::from(ALICE), USD_CURRENCY, 2_000_000 * dollar(USD_CURRENCY)),
- (AccountId::from(BOB), USD_CURRENCY, 8_000_000 * dollar(USD_CURRENCY)),
- (
- AccountId::from(BOB),
- RELAY_CHAIN_CURRENCY,
- 300_000_000 * dollar(RELAY_CHAIN_CURRENCY),
- ),
- (
- AccountId::from(BOB),
- LIQUID_CURRENCY,
- 50_000_000 * dollar(LIQUID_CURRENCY),
- ),
- ])
- .build()
- .execute_with(|| {
- assert_ok!(CdpTreasury::deposit_collateral(
- &AccountId::from(BOB),
- RELAY_CHAIN_CURRENCY,
- 200_000_000 * dollar(RELAY_CHAIN_CURRENCY)
- ));
- assert_ok!(CdpTreasury::deposit_collateral(
- &AccountId::from(BOB),
- LIQUID_CURRENCY,
- 40_000_000 * dollar(LIQUID_CURRENCY)
- ));
- assert_eq!(
- CdpTreasury::total_collaterals(RELAY_CHAIN_CURRENCY),
- 200_000_000 * dollar(RELAY_CHAIN_CURRENCY)
- );
- assert_eq!(
- CdpTreasury::total_collaterals(LIQUID_CURRENCY),
- 40_000_000 * dollar(LIQUID_CURRENCY)
- );
-
- // Total liquidity to collaterize is calculated using Stable currency - USD
- assert_noop!(
- EmergencyShutdown::refund_collaterals(
- Origin::signed(AccountId::from(ALICE)),
- 1_000_000 * dollar(USD_CURRENCY)
- ),
- module_emergency_shutdown::Error::::CanNotRefund,
- );
- assert_ok!(EmergencyShutdown::emergency_shutdown(Origin::root()));
- assert_ok!(EmergencyShutdown::open_collateral_refund(Origin::root()));
- assert_ok!(EmergencyShutdown::refund_collaterals(
- Origin::signed(AccountId::from(ALICE)),
- 1_000_000 * dollar(USD_CURRENCY)
- ));
-
- assert_eq!(
- CdpTreasury::total_collaterals(RELAY_CHAIN_CURRENCY),
- 180_000_000 * dollar(RELAY_CHAIN_CURRENCY)
- );
- assert_eq!(
- CdpTreasury::total_collaterals(LIQUID_CURRENCY),
- 36_000_000 * dollar(LIQUID_CURRENCY)
- );
- assert_eq!(
- Currencies::free_balance(USD_CURRENCY, &AccountId::from(ALICE)),
- 1_000_000 * dollar(USD_CURRENCY)
- );
- assert_eq!(
- Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(ALICE)),
- 20_000_000 * dollar(RELAY_CHAIN_CURRENCY)
- );
- assert_eq!(
- Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(ALICE)),
- 4_000_000 * dollar(LIQUID_CURRENCY)
- );
- });
-}
-
-#[test]
-fn liquidate_cdp() {
- ExtBuilder::default()
- .balances(vec![
- (
- AccountId::from(ALICE),
- RELAY_CHAIN_CURRENCY,
- 51 * dollar(RELAY_CHAIN_CURRENCY),
- ),
- (AccountId::from(BOB), USD_CURRENCY, 1_000_001 * dollar(USD_CURRENCY)),
- (
- AccountId::from(BOB),
- RELAY_CHAIN_CURRENCY,
- 102 * dollar(RELAY_CHAIN_CURRENCY),
- ),
- ])
- .build()
- .execute_with(|| {
- assert_ok!(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)),
- RELAY_CHAIN_CURRENCY,
- USD_CURRENCY,
- 100 * dollar(RELAY_CHAIN_CURRENCY),
- 1_000_000 * dollar(USD_CURRENCY),
- 0,
- false,
- ));
-
- assert_ok!(CdpEngine::set_collateral_params(
- Origin::root(),
- RELAY_CHAIN_CURRENCY,
- Change::NewValue(Some(Rate::zero())),
- Change::NewValue(Some(Ratio::saturating_from_rational(200, 100))),
- Change::NewValue(Some(Rate::saturating_from_rational(20, 100))),
- Change::NewValue(Some(Ratio::saturating_from_rational(200, 100))),
- Change::NewValue(1_000_000 * dollar(USD_CURRENCY)),
- ));
-
- assert_ok!(CdpEngine::adjust_position(
- &AccountId::from(ALICE),
- RELAY_CHAIN_CURRENCY,
- (50 * dollar(RELAY_CHAIN_CURRENCY)) as i128,
- (2_500_000 * dollar(USD_CURRENCY)) as i128,
- ));
-
- assert_ok!(CdpEngine::adjust_position(
- &AccountId::from(BOB),
- RELAY_CHAIN_CURRENCY,
- dollar(RELAY_CHAIN_CURRENCY) as i128,
- (50_000 * dollar(USD_CURRENCY)) as i128,
- ));
-
- assert_eq!(
- Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).debit,
- 2_500_000 * dollar(USD_CURRENCY)
- );
- assert_eq!(
- Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).collateral,
- 50 * dollar(RELAY_CHAIN_CURRENCY)
- );
- assert_eq!(
- Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(BOB)).debit,
- 50_000 * dollar(USD_CURRENCY)
- );
- assert_eq!(
- Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(BOB)).collateral,
- dollar(RELAY_CHAIN_CURRENCY)
- );
- assert_eq!(CdpTreasury::debit_pool(), 0);
- assert_eq!(AuctionManager::collateral_auctions(0), None);
-
- assert_ok!(CdpEngine::set_collateral_params(
- Origin::root(),
- RELAY_CHAIN_CURRENCY,
- Change::NoChange,
- Change::NewValue(Some(Ratio::saturating_from_rational(400, 100))),
- Change::NoChange,
- Change::NewValue(Some(Ratio::saturating_from_rational(400, 100))),
- Change::NoChange,
- ));
-
- assert_ok!(CdpEngine::liquidate_unsafe_cdp(
- AccountId::from(ALICE),
- RELAY_CHAIN_CURRENCY
- ));
-
- let liquidate_alice_xbtc_cdp_event = Event::CdpEngine(module_cdp_engine::Event::LiquidateUnsafeCDP(
- RELAY_CHAIN_CURRENCY,
- AccountId::from(ALICE),
- 50 * dollar(RELAY_CHAIN_CURRENCY),
- 250_000 * dollar(USD_CURRENCY),
- LiquidationStrategy::Auction,
- ));
-
- assert!(System::events()
- .iter()
- .any(|record| record.event == liquidate_alice_xbtc_cdp_event));
-
- assert_eq!(Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).debit, 0);
- assert_eq!(
- Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).collateral,
- 0
- );
- assert!(AuctionManager::collateral_auctions(0).is_some());
- assert_eq!(CdpTreasury::debit_pool(), 250_000 * dollar(USD_CURRENCY));
-
- assert_ok!(CdpEngine::liquidate_unsafe_cdp(
- AccountId::from(BOB),
- RELAY_CHAIN_CURRENCY
- ));
-
- let liquidate_bob_xbtc_cdp_event = Event::CdpEngine(module_cdp_engine::Event::LiquidateUnsafeCDP(
- RELAY_CHAIN_CURRENCY,
- AccountId::from(BOB),
- dollar(RELAY_CHAIN_CURRENCY),
- 5_000 * dollar(USD_CURRENCY),
- LiquidationStrategy::Exchange,
- ));
- assert!(System::events()
- .iter()
- .any(|record| record.event == liquidate_bob_xbtc_cdp_event));
-
- assert_eq!(Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(BOB)).debit, 0);
- assert_eq!(
- Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(BOB)).collateral,
- 0
- );
- assert_eq!(CdpTreasury::debit_pool(), 255_000 * dollar(USD_CURRENCY));
- assert!(CdpTreasury::surplus_pool() >= 5_000 * dollar(USD_CURRENCY));
- });
-}
-
-#[test]
-fn test_dex_module() {
- ExtBuilder::default()
- .balances(vec![
- (
- // NetworkContractSource
- MockAddressMapping::get_account_id(&H160::from_low_u64_be(0)),
- NATIVE_CURRENCY,
- 1_000_000_000 * dollar(NATIVE_CURRENCY),
- ),
- (
- AccountId::from(ALICE),
- USD_CURRENCY,
- 1_000_000_000 * dollar(NATIVE_CURRENCY),
- ),
- (
- AccountId::from(ALICE),
- RELAY_CHAIN_CURRENCY,
- 1_000_000_000 * dollar(NATIVE_CURRENCY),
- ),
- (AccountId::from(BOB), USD_CURRENCY, 1_000_000 * dollar(NATIVE_CURRENCY)),
- (
- AccountId::from(BOB),
- RELAY_CHAIN_CURRENCY,
- 1_000_000_000 * dollar(NATIVE_CURRENCY),
- ),
- ])
- .build()
- .execute_with(|| {
- assert_eq!(Dex::get_liquidity_pool(RELAY_CHAIN_CURRENCY, USD_CURRENCY), (0, 0));
- assert_eq!(Currencies::total_issuance(LPTOKEN), 0);
- assert_eq!(Currencies::free_balance(LPTOKEN, &AccountId::from(ALICE)), 0);
-
- assert_noop!(
- Dex::add_liquidity(
- Origin::signed(AccountId::from(ALICE)),
- RELAY_CHAIN_CURRENCY,
- USD_CURRENCY,
- 0,
- 10_000_000 * dollar(USD_CURRENCY),
- 0,
- false,
- ),
- module_dex::Error::::InvalidLiquidityIncrement,
- );
-
- assert_ok!(Dex::add_liquidity(
- Origin::signed(AccountId::from(ALICE)),
- RELAY_CHAIN_CURRENCY,
- USD_CURRENCY,
- 10_000 * dollar(RELAY_CHAIN_CURRENCY),
- 10_000_000 * dollar(USD_CURRENCY),
- 0,
- false,
- ));
-
- let add_liquidity_event = Event::Dex(module_dex::Event::AddLiquidity(
- AccountId::from(ALICE),
- USD_CURRENCY,
- 10_000_000 * dollar(USD_CURRENCY),
- RELAY_CHAIN_CURRENCY,
- 10_000 * dollar(RELAY_CHAIN_CURRENCY),
- 20_000_000 * dollar(USD_CURRENCY),
- ));
- assert!(System::events()
- .iter()
- .any(|record| record.event == add_liquidity_event));
-
- assert_eq!(
- Dex::get_liquidity_pool(RELAY_CHAIN_CURRENCY, USD_CURRENCY),
- (10_000 * dollar(RELAY_CHAIN_CURRENCY), 10_000_000 * dollar(USD_CURRENCY))
- );
- assert_eq!(Currencies::total_issuance(LPTOKEN), 20_000_000 * dollar(USD_CURRENCY));
- assert_eq!(
- Currencies::free_balance(LPTOKEN, &AccountId::from(ALICE)),
- 20_000_000 * dollar(USD_CURRENCY)
- );
- assert_ok!(Dex::add_liquidity(
- Origin::signed(AccountId::from(BOB)),
- RELAY_CHAIN_CURRENCY,
- USD_CURRENCY,
- 1 * dollar(RELAY_CHAIN_CURRENCY),
- 1_000 * dollar(USD_CURRENCY),
- 0,
- false,
- ));
- assert_eq!(
- Dex::get_liquidity_pool(RELAY_CHAIN_CURRENCY, USD_CURRENCY),
- (10_001 * dollar(RELAY_CHAIN_CURRENCY), 10_001_000 * dollar(USD_CURRENCY))
- );
- assert_eq!(Currencies::total_issuance(LPTOKEN), 20_002_000 * dollar(USD_CURRENCY));
- assert_eq!(
- Currencies::free_balance(LPTOKEN, &AccountId::from(BOB)),
- 2000 * dollar(USD_CURRENCY)
- );
- assert_noop!(
- Dex::add_liquidity(
- Origin::signed(AccountId::from(BOB)),
- RELAY_CHAIN_CURRENCY,
- USD_CURRENCY,
- 1,
- 999,
- 0,
- false,
- ),
- module_dex::Error::::InvalidLiquidityIncrement,
- );
- assert_eq!(
- Dex::get_liquidity_pool(RELAY_CHAIN_CURRENCY, USD_CURRENCY),
- (10_001 * dollar(RELAY_CHAIN_CURRENCY), 10_001_000 * dollar(USD_CURRENCY))
- );
- assert_eq!(Currencies::total_issuance(LPTOKEN), 20_002_000 * dollar(USD_CURRENCY));
- assert_eq!(
- Currencies::free_balance(LPTOKEN, &AccountId::from(BOB)),
- 2_000 * dollar(USD_CURRENCY)
- );
- assert_ok!(Dex::add_liquidity(
- Origin::signed(AccountId::from(BOB)),
- RELAY_CHAIN_CURRENCY,
- USD_CURRENCY,
- 2 * dollar(RELAY_CHAIN_CURRENCY),
- 1_000 * dollar(USD_CURRENCY),
- 0,
- false,
- ));
- assert_eq!(
- Dex::get_liquidity_pool(RELAY_CHAIN_CURRENCY, USD_CURRENCY),
- (10_002 * dollar(RELAY_CHAIN_CURRENCY), 10_002_000 * dollar(USD_CURRENCY))
- );
- assert_ok!(Dex::add_liquidity(
- Origin::signed(AccountId::from(BOB)),
- RELAY_CHAIN_CURRENCY,
- USD_CURRENCY,
- 1 * dollar(RELAY_CHAIN_CURRENCY),
- 1_001 * dollar(USD_CURRENCY),
- 0,
- false,
- ));
- assert_eq!(
- Dex::get_liquidity_pool(RELAY_CHAIN_CURRENCY, USD_CURRENCY),
- (10_003 * dollar(RELAY_CHAIN_CURRENCY), 10_003_000 * dollar(USD_CURRENCY))
- );
-
- assert_eq!(Currencies::total_issuance(LPTOKEN), 20_005_999_999_999_999_995);
- });
-}
-
-#[test]
-fn test_honzon_module() {
- ExtBuilder::default()
- .balances(vec![(
- AccountId::from(ALICE),
- RELAY_CHAIN_CURRENCY,
- 1_000 * dollar(RELAY_CHAIN_CURRENCY),
- )])
- .build()
- .execute_with(|| {
- assert_ok!(set_oracle_price(vec![(
- RELAY_CHAIN_CURRENCY,
- Price::saturating_from_rational(1, 1)
- )]));
-
- assert_ok!(CdpEngine::set_collateral_params(
- Origin::root(),
- RELAY_CHAIN_CURRENCY,
- Change::NewValue(Some(Rate::saturating_from_rational(1, 100000))),
- Change::NewValue(Some(Ratio::saturating_from_rational(3, 2))),
- Change::NewValue(Some(Rate::saturating_from_rational(2, 10))),
- Change::NewValue(Some(Ratio::saturating_from_rational(9, 5))),
- Change::NewValue(10_000 * dollar(USD_CURRENCY)),
- ));
- assert_ok!(CdpEngine::adjust_position(
- &AccountId::from(ALICE),
- RELAY_CHAIN_CURRENCY,
- (100 * dollar(RELAY_CHAIN_CURRENCY)) as i128,
- (500 * dollar(USD_CURRENCY)) as i128
- ));
- assert_eq!(
- Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(ALICE)),
- 900 * dollar(RELAY_CHAIN_CURRENCY)
- );
- assert_eq!(
- Currencies::free_balance(USD_CURRENCY, &AccountId::from(ALICE)),
- 50 * dollar(USD_CURRENCY)
- );
- assert_eq!(
- Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).debit,
- 500 * dollar(USD_CURRENCY)
- );
- assert_eq!(
- Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).collateral,
- 100 * dollar(RELAY_CHAIN_CURRENCY)
- );
- assert_eq!(
- CdpEngine::liquidate(
- Origin::none(),
- RELAY_CHAIN_CURRENCY,
- MultiAddress::Id(AccountId::from(ALICE))
- )
- .is_ok(),
- false
- );
- assert_ok!(CdpEngine::set_collateral_params(
- Origin::root(),
- RELAY_CHAIN_CURRENCY,
- Change::NoChange,
- Change::NewValue(Some(Ratio::saturating_from_rational(3, 1))),
- Change::NoChange,
- Change::NoChange,
- Change::NoChange,
- ));
- assert_ok!(CdpEngine::liquidate(
- Origin::none(),
- RELAY_CHAIN_CURRENCY,
- MultiAddress::Id(AccountId::from(ALICE))
- ));
-
- assert_eq!(
- Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(ALICE)),
- 900 * dollar(RELAY_CHAIN_CURRENCY)
- );
- assert_eq!(
- Currencies::free_balance(USD_CURRENCY, &AccountId::from(ALICE)),
- 50 * dollar(USD_CURRENCY)
- );
- assert_eq!(Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).debit, 0);
- assert_eq!(
- Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).collateral,
- 0
- );
- });
-}
-
-#[test]
-fn test_cdp_engine_module() {
- ExtBuilder::default()
- .balances(vec![
- (AccountId::from(ALICE), USD_CURRENCY, 2_000 * dollar(USD_CURRENCY)),
- (
- AccountId::from(ALICE),
- RELAY_CHAIN_CURRENCY,
- 2_000 * dollar(RELAY_CHAIN_CURRENCY),
- ),
- ])
- .build()
- .execute_with(|| {
- assert_ok!(CdpEngine::set_collateral_params(
- Origin::root(),
- RELAY_CHAIN_CURRENCY,
- Change::NewValue(Some(Rate::saturating_from_rational(1, 100000))),
- Change::NewValue(Some(Ratio::saturating_from_rational(3, 2))),
- Change::NewValue(Some(Rate::saturating_from_rational(2, 10))),
- Change::NewValue(Some(Ratio::saturating_from_rational(9, 5))),
- Change::NewValue(10_000 * dollar(USD_CURRENCY)),
- ));
-
- let new_collateral_params = CdpEngine::collateral_params(RELAY_CHAIN_CURRENCY);
-
- assert_eq!(
- new_collateral_params.interest_rate_per_sec,
- Some(Rate::saturating_from_rational(1, 100000))
- );
- assert_eq!(
- new_collateral_params.liquidation_ratio,
- Some(Ratio::saturating_from_rational(3, 2))
- );
- assert_eq!(
- new_collateral_params.liquidation_penalty,
- Some(Rate::saturating_from_rational(2, 10))
- );
- assert_eq!(
- new_collateral_params.required_collateral_ratio,
- Some(Ratio::saturating_from_rational(9, 5))
- );
- assert_eq!(
- new_collateral_params.maximum_total_debit_value,
- 10_000 * dollar(USD_CURRENCY)
- );
-
- assert_eq!(
- CdpEngine::calculate_collateral_ratio(
- RELAY_CHAIN_CURRENCY,
- 100 * dollar(RELAY_CHAIN_CURRENCY),
- 50 * dollar(USD_CURRENCY),
- Price::saturating_from_rational(1 * dollar(USD_CURRENCY), dollar(RELAY_CHAIN_CURRENCY)),
- ),
- Ratio::saturating_from_rational(100 * 10, 50)
- );
-
- assert_ok!(CdpEngine::check_debit_cap(
- RELAY_CHAIN_CURRENCY,
- 99_999 * dollar(USD_CURRENCY)
- ));
- assert_eq!(
- CdpEngine::check_debit_cap(RELAY_CHAIN_CURRENCY, 100_001 * dollar(USD_CURRENCY)).is_ok(),
- false
- );
-
- assert_ok!(CdpEngine::adjust_position(
- &AccountId::from(ALICE),
- RELAY_CHAIN_CURRENCY,
- (200 * dollar(RELAY_CHAIN_CURRENCY)) as i128,
- 0
- ));
- assert_eq!(
- Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(ALICE)),
- 1800 * dollar(RELAY_CHAIN_CURRENCY)
- );
- assert_eq!(Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).debit, 0);
- assert_eq!(
- Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).collateral,
- 200 * dollar(RELAY_CHAIN_CURRENCY)
- );
-
- assert_noop!(
- CdpEngine::settle_cdp_has_debit(AccountId::from(ALICE), RELAY_CHAIN_CURRENCY),
- module_cdp_engine::Error::::NoDebitValue,
- );
-
- assert_ok!(set_oracle_price(vec![
- (USD_CURRENCY, Price::saturating_from_rational(1, 1)),
- (RELAY_CHAIN_CURRENCY, Price::saturating_from_rational(3, 1))
- ]));
-
- assert_ok!(CdpEngine::adjust_position(
- &AccountId::from(ALICE),
- RELAY_CHAIN_CURRENCY,
- 0,
- (200 * dollar(USD_CURRENCY)) as i128
- ));
- assert_eq!(
- Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).debit,
- 200 * dollar(USD_CURRENCY)
- );
- assert_eq!(CdpTreasury::debit_pool(), 0);
- assert_eq!(CdpTreasury::total_collaterals(RELAY_CHAIN_CURRENCY), 0);
- assert_ok!(CdpEngine::settle_cdp_has_debit(
- AccountId::from(ALICE),
- RELAY_CHAIN_CURRENCY
- ));
-
- let settle_cdp_in_debit_event = Event::CdpEngine(module_cdp_engine::Event::SettleCDPInDebit(
- RELAY_CHAIN_CURRENCY,
- AccountId::from(ALICE),
- ));
- assert!(System::events()
- .iter()
- .any(|record| record.event == settle_cdp_in_debit_event));
-
- assert_eq!(Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).debit, 0);
- assert_eq!(CdpTreasury::debit_pool(), 20 * dollar(USD_CURRENCY));
-
- // DOT is 10 decimal places where as ksm is 12 decimals. Hence the difference in collaterals.
- #[cfg(feature = "with-mandala-runtime")]
- assert_eq!(CdpTreasury::total_collaterals(RELAY_CHAIN_CURRENCY), 66_666_666_666);
- #[cfg(feature = "with-karura-runtime")]
- assert_eq!(CdpTreasury::total_collaterals(RELAY_CHAIN_CURRENCY), 6_666_666_666_666);
- });
-}
-
-#[test]
-fn test_authority_module() {
- #[cfg(feature = "with-mandala-runtime")]
- const AUTHORITY_ORIGIN_ID: u8 = 70u8;
-
- #[cfg(feature = "with-karura-runtime")]
- const AUTHORITY_ORIGIN_ID: u8 = 60u8;
-
- ExtBuilder::default()
- .balances(vec![
- (AccountId::from(ALICE), USD_CURRENCY, 1_000 * dollar(USD_CURRENCY)),
- (
- AccountId::from(ALICE),
- RELAY_CHAIN_CURRENCY,
- 1_000 * dollar(RELAY_CHAIN_CURRENCY),
- ),
- (TreasuryAccount::get(), USD_CURRENCY, 1_000 * dollar(USD_CURRENCY)),
- ])
- .build()
- .execute_with(|| {
- let ensure_root_call = Call::System(frame_system::Call::fill_block { ratio: Perbill::one() });
- let call = Call::Authority(orml_authority::Call::dispatch_as {
- as_origin: AuthoritysOriginId::Root,
- call: Box::new(ensure_root_call.clone()),
- });
-
- // dispatch_as
- assert_ok!(Authority::dispatch_as(
- Origin::root(),
- AuthoritysOriginId::Root,
- Box::new(ensure_root_call.clone())
- ));
-
- assert_noop!(
- Authority::dispatch_as(
- Origin::signed(AccountId::from(BOB)),
- AuthoritysOriginId::Root,
- Box::new(ensure_root_call.clone())
- ),
- BadOrigin
- );
-
- assert_noop!(
- Authority::dispatch_as(
- Origin::signed(AccountId::from(BOB)),
- AuthoritysOriginId::Treasury,
- Box::new(ensure_root_call.clone())
- ),
- BadOrigin
- );
-
- // schedule_dispatch
- run_to_block(1);
- // Treasury transfer
- let transfer_call = Call::Currencies(module_currencies::Call::transfer {
- dest: AccountId::from(BOB).into(),
- currency_id: USD_CURRENCY,
- amount: 500 * dollar(USD_CURRENCY),
- });
- let treasury_reserve_call = Call::Authority(orml_authority::Call::dispatch_as {
- as_origin: AuthoritysOriginId::Treasury,
- call: Box::new(transfer_call.clone()),
- });
-
- let one_day_later = OneDay::get() + 1;
-
- assert_ok!(Authority::schedule_dispatch(
- Origin::root(),
- DispatchTime::At(one_day_later),
- 0,
- true,
- Box::new(treasury_reserve_call.clone())
- ));
-
- assert_ok!(Authority::schedule_dispatch(
- Origin::root(),
- DispatchTime::At(one_day_later),
- 0,
- true,
- Box::new(call.clone())
- ));
- System::assert_last_event(Event::Authority(orml_authority::Event::Scheduled(
- OriginCaller::Authority(DelayedOrigin {
- delay: one_day_later - 1,
- origin: Box::new(OriginCaller::system(RawOrigin::Root)),
- }),
- 1,
- )));
-
- run_to_block(one_day_later);
-
- assert_eq!(
- Currencies::free_balance(USD_CURRENCY, &TreasuryPalletId::get().into_account()),
- 500 * dollar(USD_CURRENCY)
- );
- assert_eq!(
- Currencies::free_balance(USD_CURRENCY, &AccountId::from(BOB)),
- 500 * dollar(USD_CURRENCY)
- );
-
- // delay < SevenDays
- #[cfg(feature = "with-mandala-runtime")]
- System::assert_last_event(Event::Scheduler(pallet_scheduler::Event::::Dispatched(
- (OneDay::get() + 1, 1),
- Some([AUTHORITY_ORIGIN_ID, 64, 56, 0, 0, 0, 0, 1, 0, 0, 0].to_vec()),
- Err(DispatchError::BadOrigin),
- )));
- #[cfg(feature = "with-karura-runtime")]
- System::assert_last_event(Event::Scheduler(pallet_scheduler::Event::::Dispatched(
- (OneDay::get() + 1, 1),
- Some([AUTHORITY_ORIGIN_ID, 32, 28, 0, 0, 0, 0, 1, 0, 0, 0].to_vec()),
- Err(DispatchError::BadOrigin),
- )));
-
- let seven_days_later = one_day_later + SevenDays::get() + 1;
-
- // delay = SevenDays
- assert_ok!(Authority::schedule_dispatch(
- Origin::root(),
- DispatchTime::At(seven_days_later),
- 0,
- true,
- Box::new(call.clone())
- ));
-
- run_to_block(seven_days_later);
-
- #[cfg(feature = "with-mandala-runtime")]
- System::assert_last_event(Event::Scheduler(pallet_scheduler::Event::::Dispatched(
- (seven_days_later, 0),
- Some([AUTHORITY_ORIGIN_ID, 193, 137, 1, 0, 0, 0, 2, 0, 0, 0].to_vec()),
- Ok(()),
- )));
-
- #[cfg(feature = "with-karura-runtime")]
- System::assert_last_event(Event::Scheduler(pallet_scheduler::Event::::Dispatched(
- (seven_days_later, 0),
- Some([AUTHORITY_ORIGIN_ID, 225, 196, 0, 0, 0, 0, 2, 0, 0, 0].to_vec()),
- Ok(()),
- )));
-
- // with_delayed_origin = false
- assert_ok!(Authority::schedule_dispatch(
- Origin::root(),
- DispatchTime::At(seven_days_later + 1),
- 0,
- false,
- Box::new(call.clone())
- ));
- System::assert_last_event(Event::Authority(orml_authority::Event::Scheduled(
- OriginCaller::system(RawOrigin::Root),
- 3,
- )));
-
- run_to_block(seven_days_later + 1);
- System::assert_last_event(Event::Scheduler(pallet_scheduler::Event::::Dispatched(
- (seven_days_later + 1, 0),
- Some([0, 0, 3, 0, 0, 0].to_vec()),
- Ok(()),
- )));
-
- assert_ok!(Authority::schedule_dispatch(
- Origin::root(),
- DispatchTime::At(seven_days_later + 2),
- 0,
- false,
- Box::new(call.clone())
- ));
-
- // fast_track_scheduled_dispatch
- assert_ok!(Authority::fast_track_scheduled_dispatch(
- Origin::root(),
- Box::new(frame_system::RawOrigin::Root.into()),
- 4,
- DispatchTime::At(seven_days_later + 3),
- ));
-
- // delay_scheduled_dispatch
- assert_ok!(Authority::delay_scheduled_dispatch(
- Origin::root(),
- Box::new(frame_system::RawOrigin::Root.into()),
- 4,
- 4,
- ));
-
- // cancel_scheduled_dispatch
- assert_ok!(Authority::schedule_dispatch(
- Origin::root(),
- DispatchTime::At(seven_days_later + 2),
- 0,
- true,
- Box::new(call.clone())
- ));
- System::assert_last_event(Event::Authority(orml_authority::Event::Scheduled(
- OriginCaller::Authority(DelayedOrigin {
- delay: 1,
- origin: Box::new(OriginCaller::system(RawOrigin::Root)),
- }),
- 5,
- )));
-
- let schedule_origin = {
- let origin: ::Origin = From::from(Origin::root());
- let origin: ::Origin = From::from(DelayedOrigin::<
- BlockNumber,
- ::PalletsOrigin,
- > {
- delay: 1,
- origin: Box::new(origin.caller().clone()),
- });
- origin
- };
-
- let pallets_origin = Box::new(schedule_origin.caller().clone());
- assert_ok!(Authority::cancel_scheduled_dispatch(Origin::root(), pallets_origin, 5));
- System::assert_last_event(Event::Authority(orml_authority::Event::Cancelled(
- OriginCaller::Authority(DelayedOrigin {
- delay: 1,
- origin: Box::new(OriginCaller::system(RawOrigin::Root)),
- }),
- 5,
- )));
-
- assert_ok!(Authority::schedule_dispatch(
- Origin::root(),
- DispatchTime::At(seven_days_later + 3),
- 0,
- false,
- Box::new(call.clone())
- ));
- System::assert_last_event(Event::Authority(orml_authority::Event::Scheduled(
- OriginCaller::system(RawOrigin::Root),
- 6,
- )));
-
- assert_ok!(Authority::cancel_scheduled_dispatch(
- Origin::root(),
- Box::new(frame_system::RawOrigin::Root.into()),
- 6
- ));
- System::assert_last_event(Event::Authority(orml_authority::Event::Cancelled(
- OriginCaller::system(RawOrigin::Root),
- 6,
- )));
- });
-}
-
-#[test]
-fn test_nft_module() {
- ExtBuilder::default()
- .balances(vec![(
- AccountId::from(ALICE),
- NATIVE_CURRENCY,
- 1_000 * dollar(NATIVE_CURRENCY),
- )])
- .build()
- .execute_with(|| {
- let metadata = vec![1];
- assert_eq!(
- Balances::free_balance(AccountId::from(ALICE)),
- 1_000 * dollar(NATIVE_CURRENCY)
- );
- assert_eq!(Balances::reserved_balance(AccountId::from(ALICE)), 0);
- assert_ok!(NFT::create_class(
- Origin::signed(AccountId::from(ALICE)),
- metadata.clone(),
- module_nft::Properties(
- module_nft::ClassProperty::Transferable
- | module_nft::ClassProperty::Burnable
- | module_nft::ClassProperty::Mintable
- ),
- Default::default(),
- ));
- let deposit =
- Proxy::deposit(1u32) + CreateClassDeposit::get() + DataDepositPerByte::get() * (metadata.len() as u128);
- assert_eq!(Balances::free_balance(&NftPalletId::get().into_sub_account(0)), 0);
- assert_eq!(
- Balances::reserved_balance(&NftPalletId::get().into_sub_account(0)),
- deposit
- );
- assert_eq!(
- Balances::free_balance(AccountId::from(ALICE)),
- 1_000 * dollar(NATIVE_CURRENCY) - deposit
- );
- assert_eq!(Balances::reserved_balance(AccountId::from(ALICE)), 0);
- assert_ok!(Balances::deposit_into_existing(
- &NftPalletId::get().into_sub_account(0),
- 1 * (CreateTokenDeposit::get() + DataDepositPerByte::get())
- ));
- assert_ok!(NFT::mint(
- Origin::signed(NftPalletId::get().into_sub_account(0)),
- MultiAddress::Id(AccountId::from(BOB)),
- 0,
- metadata.clone(),
- Default::default(),
- 1
- ));
- assert_ok!(NFT::burn(Origin::signed(AccountId::from(BOB)), (0, 0)));
- assert_eq!(
- Balances::free_balance(AccountId::from(BOB)),
- CreateTokenDeposit::get() + DataDepositPerByte::get()
- );
- assert_noop!(
- NFT::destroy_class(
- Origin::signed(NftPalletId::get().into_sub_account(0)),
- 0,
- MultiAddress::Id(AccountId::from(BOB))
- ),
- pallet_proxy::Error::::NotFound
- );
- assert_ok!(NFT::destroy_class(
- Origin::signed(NftPalletId::get().into_sub_account(0)),
- 0,
- MultiAddress::Id(AccountId::from(ALICE))
- ));
- assert_eq!(
- Balances::free_balance(AccountId::from(BOB)),
- CreateTokenDeposit::get() + DataDepositPerByte::get()
- );
- assert_eq!(Balances::reserved_balance(AccountId::from(BOB)), 0);
- assert_eq!(
- Balances::free_balance(AccountId::from(ALICE)),
- 1_000 * dollar(NATIVE_CURRENCY)
- );
- assert_eq!(Balances::reserved_balance(AccountId::from(ALICE)), 0);
- });
-}
-
-#[test]
-fn test_evm_accounts_module() {
- ExtBuilder::default()
- .balances(vec![(bob(), NATIVE_CURRENCY, 1_000 * dollar(NATIVE_CURRENCY))])
- .build()
- .execute_with(|| {
- assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 0);
- assert_eq!(Balances::free_balance(bob()), 1_000 * dollar(NATIVE_CURRENCY));
- assert_ok!(EvmAccounts::claim_account(
- Origin::signed(AccountId::from(ALICE)),
- EvmAccounts::eth_address(&alice_key()),
- EvmAccounts::eth_sign(&alice_key(), &AccountId::from(ALICE).encode(), &[][..])
- ));
- System::assert_last_event(Event::EvmAccounts(module_evm_accounts::Event::ClaimAccount(
- AccountId::from(ALICE),
- EvmAccounts::eth_address(&alice_key()),
- )));
-
- // claim another eth address
- assert_noop!(
- EvmAccounts::claim_account(
- Origin::signed(AccountId::from(ALICE)),
- EvmAccounts::eth_address(&alice_key()),
- EvmAccounts::eth_sign(&alice_key(), &AccountId::from(ALICE).encode(), &[][..])
- ),
- module_evm_accounts::Error::::AccountIdHasMapped
- );
- assert_noop!(
- EvmAccounts::claim_account(
- Origin::signed(AccountId::from(BOB)),
- EvmAccounts::eth_address(&alice_key()),
- EvmAccounts::eth_sign(&alice_key(), &AccountId::from(BOB).encode(), &[][..])
- ),
- module_evm_accounts::Error::::EthAddressHasMapped
- );
-
- // evm padded address will transfer_all to origin.
- assert_eq!(Balances::free_balance(bob()), 1_000 * dollar(NATIVE_CURRENCY));
- assert_eq!(Balances::free_balance(&AccountId::from(BOB)), 0);
- assert_eq!(System::providers(&bob()), 1);
- assert_eq!(System::providers(&AccountId::from(BOB)), 0);
- assert_ok!(EvmAccounts::claim_account(
- Origin::signed(AccountId::from(BOB)),
- EvmAccounts::eth_address(&bob_key()),
- EvmAccounts::eth_sign(&bob_key(), &AccountId::from(BOB).encode(), &[][..])
- ));
- assert_eq!(System::providers(&bob()), 0);
- assert_eq!(System::providers(&AccountId::from(BOB)), 1);
- assert_eq!(Balances::free_balance(bob()), 0);
- assert_eq!(
- Balances::free_balance(&AccountId::from(BOB)),
- 1_000 * dollar(NATIVE_CURRENCY)
- );
- });
-}
-
-#[test]
-fn test_vesting_use_relaychain_block_number() {
- ExtBuilder::default().build().execute_with(|| {
- #[cfg(feature = "with-mandala-runtime")]
- let signer: AccountId = TreasuryPalletId::get().into_account();
- #[cfg(feature = "with-karura-runtime")]
- let signer: AccountId = KaruraFoundationAccounts::get()[0].clone();
- #[cfg(feature = "with-acala-runtime")]
- let signer: AccountId = AcalaFoundationAccounts::get()[0].clone();
-
- assert_ok!(Balances::set_balance(
- Origin::root(),
- signer.clone().into(),
- 1_000 * dollar(ACA),
- 0
- ));
-
- assert_ok!(Vesting::vested_transfer(
- Origin::signed(signer),
- alice().into(),
- VestingSchedule {
- start: 10,
- period: 2,
- period_count: 5,
- per_period: 3 * dollar(NATIVE_CURRENCY),
- }
- ));
-
- assert_eq!(Balances::free_balance(&alice()), 15 * dollar(NATIVE_CURRENCY));
- assert_eq!(Balances::usable_balance(&alice()), 0);
-
- set_relaychain_block_number(10);
-
- assert_ok!(Vesting::claim(Origin::signed(alice())));
- assert_eq!(Balances::usable_balance(&alice()), 0);
-
- set_relaychain_block_number(12);
-
- assert_ok!(Vesting::claim(Origin::signed(alice())));
- assert_eq!(Balances::usable_balance(&alice()), 3 * dollar(NATIVE_CURRENCY));
-
- set_relaychain_block_number(15);
-
- assert_ok!(Vesting::claim(Origin::signed(alice())));
- assert_eq!(Balances::usable_balance(&alice()), 6 * dollar(NATIVE_CURRENCY));
-
- set_relaychain_block_number(20);
-
- assert_ok!(Vesting::claim(Origin::signed(alice())));
- assert_eq!(Balances::usable_balance(&alice()), 15 * dollar(NATIVE_CURRENCY));
-
- set_relaychain_block_number(22);
-
- assert_ok!(Vesting::claim(Origin::signed(alice())));
- assert_eq!(Balances::usable_balance(&alice()), 15 * dollar(NATIVE_CURRENCY));
- });
-}
-
-#[test]
-fn test_session_manager_module() {
- ExtBuilder::default().build().execute_with(|| {
- assert_eq!(Session::session_index(), 0);
- assert_eq!(SessionManager::session_duration(), 10);
- run_to_block(10);
- assert_eq!(Session::session_index(), 1);
- assert_eq!(SessionManager::session_duration(), 10);
-
- assert_ok!(SessionManager::schedule_session_duration(RawOrigin::Root.into(), 2, 11));
-
- run_to_block(19);
- assert_eq!(Session::session_index(), 1);
- assert_eq!(SessionManager::session_duration(), 10);
-
- run_to_block(20);
- assert_eq!(Session::session_index(), 2);
- assert_eq!(SessionManager::session_duration(), 11);
-
- run_to_block(31);
- assert_eq!(Session::session_index(), 3);
- assert_eq!(SessionManager::session_duration(), 11);
-
- assert_ok!(SessionManager::schedule_session_duration(RawOrigin::Root.into(), 4, 9));
-
- run_to_block(42);
- assert_eq!(Session::session_index(), 4);
- assert_eq!(SessionManager::session_duration(), 9);
-
- run_to_block(50);
- assert_eq!(Session::session_index(), 4);
- assert_eq!(SessionManager::session_duration(), 9);
-
- run_to_block(51);
- assert_eq!(Session::session_index(), 5);
- assert_eq!(SessionManager::session_duration(), 9);
- });
-}
-
-#[test]
-fn treasury_should_take_xcm_execution_revenue() {
- ExtBuilder::default().build().execute_with(|| {
- let dot_amount = 1000 * dollar(RELAY_CHAIN_CURRENCY);
- #[cfg(feature = "with-mandala-runtime")]
- let actual_amount = 9_999_999_760_000;
- #[cfg(feature = "with-karura-runtime")]
- let actual_amount = 999_999_952_000_000;
- #[cfg(feature = "with-acala-runtime")]
- let actual_amount = 999_999_952_000_000;
-
- #[cfg(feature = "with-mandala-runtime")]
- let shallow_weight = 3_000_000;
- #[cfg(feature = "with-karura-runtime")]
- let shallow_weight = 600_000_000;
- #[cfg(feature = "with-acala-runtime")]
- let shallow_weight = 600_000_000;
- let origin = MultiLocation::parent();
-
- // receive relay chain token
- let asset: MultiAsset = (MultiLocation::parent(), dot_amount).into();
- let mut msg = Xcm(vec![
- ReserveAssetDeposited(asset.clone().into()),
- BuyExecution {
- fees: asset,
- weight_limit: Limited(shallow_weight),
- },
- DepositAsset {
- assets: All.into(),
- max_assets: u32::max_value(),
- beneficiary: X1(Junction::AccountId32 {
- network: NetworkId::Any,
- id: ALICE,
- })
- .into(),
- },
- ]);
- use xcm_executor::traits::WeightBounds;
- let debt = ::Weigher::weight(&mut msg).unwrap_or_default();
- assert_eq!(debt, shallow_weight);
-
- assert_eq!(Tokens::free_balance(RELAY_CHAIN_CURRENCY, &ALICE.into()), 0);
- assert_eq!(Tokens::free_balance(RELAY_CHAIN_CURRENCY, &TreasuryAccount::get()), 0);
-
- let weight_limit = debt;
- assert_eq!(
- XcmExecutor::::execute_xcm(origin, msg, weight_limit),
- Outcome::Complete(shallow_weight)
- );
-
- assert_eq!(Tokens::free_balance(RELAY_CHAIN_CURRENCY, &ALICE.into()), actual_amount);
- assert_eq!(
- Tokens::free_balance(RELAY_CHAIN_CURRENCY, &TreasuryAccount::get()),
- dot_amount - actual_amount
- );
- });
-}
-
-#[test]
-fn currency_id_convert() {
- ExtBuilder::default().build().execute_with(|| {
- let id: u32 = ParachainInfo::get().into();
-
- assert_eq!(
- CurrencyIdConvert::convert(RELAY_CHAIN_CURRENCY),
- Some(MultiLocation::parent())
- );
-
- assert_eq!(
- CurrencyIdConvert::convert(NATIVE_CURRENCY),
- Some(MultiLocation::sibling_parachain_general_key(
- id,
- NATIVE_CURRENCY.encode()
- ))
- );
- assert_eq!(
- CurrencyIdConvert::convert(USD_CURRENCY),
- Some(MultiLocation::sibling_parachain_general_key(id, USD_CURRENCY.encode()))
- );
- assert_eq!(
- CurrencyIdConvert::convert(LIQUID_CURRENCY),
- Some(MultiLocation::sibling_parachain_general_key(
- id,
- LIQUID_CURRENCY.encode()
- ))
- );
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::parent()),
- Some(RELAY_CHAIN_CURRENCY)
- );
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(
- id,
- NATIVE_CURRENCY.encode()
- )),
- Some(NATIVE_CURRENCY)
- );
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, USD_CURRENCY.encode())),
- Some(USD_CURRENCY)
- );
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(
- id,
- LIQUID_CURRENCY.encode()
- )),
- Some(LIQUID_CURRENCY)
- );
-
- #[cfg(feature = "with-mandala-runtime")]
- {
- assert_eq!(CurrencyIdConvert::convert(KAR), None);
- assert_eq!(CurrencyIdConvert::convert(KUSD), None);
- assert_eq!(CurrencyIdConvert::convert(KSM), None);
- assert_eq!(CurrencyIdConvert::convert(LKSM), None);
-
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, RENBTC.encode())),
- Some(RENBTC)
- );
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, KAR.encode())),
- None
- );
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, KUSD.encode())),
- None
- );
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, KSM.encode())),
- None
- );
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, KSM.encode())),
- None
- );
-
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id + 1, RENBTC.encode())),
- None
- );
-
- let native_currency: MultiAsset = (
- MultiLocation::sibling_parachain_general_key(id, NATIVE_CURRENCY.encode()),
- 1,
- )
- .into();
- assert_eq!(CurrencyIdConvert::convert(native_currency), Some(NATIVE_CURRENCY));
- }
-
- #[cfg(feature = "with-karura-runtime")]
- {
- assert_eq!(CurrencyIdConvert::convert(ACA), None);
- assert_eq!(CurrencyIdConvert::convert(AUSD), None);
- assert_eq!(CurrencyIdConvert::convert(DOT), None);
- assert_eq!(CurrencyIdConvert::convert(LDOT), None);
-
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, RENBTC.encode())),
- Some(RENBTC)
- );
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, ACA.encode())),
- None
- );
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, AUSD.encode())),
- None
- );
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, DOT.encode())),
- None
- );
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, LDOT.encode())),
- None
- );
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(
- parachains::bifrost::ID,
- parachains::bifrost::BNC_KEY.to_vec()
- )),
- Some(BNC)
- );
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(
- parachains::bifrost::ID,
- parachains::bifrost::VSKSM_KEY.to_vec()
- )),
- Some(VSKSM)
- );
-
- assert_eq!(
- CurrencyIdConvert::convert(BNC),
- Some(MultiLocation::sibling_parachain_general_key(
- parachains::bifrost::ID,
- parachains::bifrost::BNC_KEY.to_vec()
- ))
- );
- assert_eq!(
- CurrencyIdConvert::convert(VSKSM),
- Some(MultiLocation::sibling_parachain_general_key(
- parachains::bifrost::ID,
- parachains::bifrost::VSKSM_KEY.to_vec()
- ))
- );
-
- let native_currency: MultiAsset = (
- MultiLocation::sibling_parachain_general_key(id, NATIVE_CURRENCY.encode()),
- 1,
- )
- .into();
- assert_eq!(CurrencyIdConvert::convert(native_currency), Some(NATIVE_CURRENCY));
- }
-
- #[cfg(feature = "with-acala-runtime")]
- {
- assert_eq!(CurrencyIdConvert::convert(KAR), None);
- assert_eq!(CurrencyIdConvert::convert(KUSD), None);
- assert_eq!(CurrencyIdConvert::convert(KSM), None);
- assert_eq!(CurrencyIdConvert::convert(LKSM), None);
-
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, RENBTC.encode())),
- Some(RENBTC)
- );
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, KAR.encode())),
- None
- );
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, KUSD.encode())),
- None
- );
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, KSM.encode())),
- None
- );
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, LKSM.encode())),
- None
- );
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(
- parachains::bifrost::ID,
- parachains::bifrost::BNC_KEY.to_vec()
- )),
- None
- );
- assert_eq!(
- CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(
- parachains::bifrost::ID,
- parachains::bifrost::VSKSM_KEY.to_vec()
- )),
- None
- );
-
- assert_eq!(
- CurrencyIdConvert::convert(BNC),
- Some(MultiLocation::sibling_parachain_general_key(
- parachains::bifrost::ID,
- parachains::bifrost::BNC_KEY.to_vec()
- ))
- );
- assert_eq!(
- CurrencyIdConvert::convert(VSKSM),
- Some(MultiLocation::sibling_parachain_general_key(
- parachains::bifrost::ID,
- parachains::bifrost::VSKSM_KEY.to_vec()
- ))
- );
-
- let native_currency: MultiAsset = (
- MultiLocation::sibling_parachain_general_key(id, NATIVE_CURRENCY.encode()),
- 1,
- )
- .into();
- assert_eq!(CurrencyIdConvert::convert(native_currency), Some(NATIVE_CURRENCY));
- }
- });
-}
-
-#[test]
-fn sanity_check_weight_per_time_constants_are_as_expected() {
- // These values comes from Substrate, we want to make sure that if it
- // ever changes we don't accidently break Polkadot
- assert_eq!(WEIGHT_PER_SECOND, 1_000_000_000_000);
- assert_eq!(WEIGHT_PER_MILLIS, WEIGHT_PER_SECOND / 1000);
- assert_eq!(WEIGHT_PER_MICROS, WEIGHT_PER_MILLIS / 1000);
- assert_eq!(WEIGHT_PER_NANOS, WEIGHT_PER_MICROS / 1000);
-}
-
-#[test]
-fn parachain_subaccounts_are_unique() {
- ExtBuilder::default().build().execute_with(|| {
- let parachain: AccountId = ParachainInfo::parachain_id().into_account();
- assert_eq!(
- parachain,
- hex_literal::hex!["70617261d0070000000000000000000000000000000000000000000000000000"].into()
- );
-
- assert_eq!(
- RelayChainSovereignSubAccount::get(),
- create_x2_parachain_multilocation(0)
- );
-
- assert_eq!(
- create_x2_parachain_multilocation(0),
- MultiLocation::new(
- 1,
- X1(Junction::AccountId32 {
- network: NetworkId::Any,
- id: hex_literal::hex!["d7b8926b326dd349355a9a7cca6606c1e0eb6fd2b506066b518c7155ff0d8297"].into(),
- })
- ),
- );
- assert_eq!(
- create_x2_parachain_multilocation(1),
- MultiLocation::new(
- 1,
- X1(Junction::AccountId32 {
- network: NetworkId::Any,
- id: hex_literal::hex!["74d37d762e06c6841a5dad64463a9afe0684f7e45245f6a7296ca613cca74669"].into(),
- })
- ),
- );
- });
-}
-
-#[test]
-fn treasury_handles_dust_correctly() {
- ExtBuilder::default()
- .balances(vec![
- (
- AccountId::from(BOB),
- RELAY_CHAIN_CURRENCY,
- ExistentialDeposits::get(&RELAY_CHAIN_CURRENCY),
- ),
- (
- AccountId::from(ALICE),
- RELAY_CHAIN_CURRENCY,
- ExistentialDeposits::get(&RELAY_CHAIN_CURRENCY),
- ),
- (
- AccountId::from(BOB),
- LIQUID_CURRENCY,
- ExistentialDeposits::get(&LIQUID_CURRENCY),
- ),
- (
- AccountId::from(ALICE),
- LIQUID_CURRENCY,
- ExistentialDeposits::get(&LIQUID_CURRENCY),
- ),
- (
- AccountId::from(BOB),
- USD_CURRENCY,
- ExistentialDeposits::get(&USD_CURRENCY),
- ),
- (
- AccountId::from(ALICE),
- USD_CURRENCY,
- ExistentialDeposits::get(&USD_CURRENCY),
- ),
- ])
- .build()
- .execute_with(|| {
- let relay_ed = ExistentialDeposits::get(&RELAY_CHAIN_CURRENCY);
- let liquid_ed = ExistentialDeposits::get(&LIQUID_CURRENCY);
- let usd_ed = ExistentialDeposits::get(&USD_CURRENCY);
-
- // Test empty treasury recieves dust tokens of relay
- assert_eq!(
- Currencies::free_balance(RELAY_CHAIN_CURRENCY, &TreasuryAccount::get()),
- 0
- );
- assert_ok!(Currencies::transfer(
- Origin::signed(AccountId::from(ALICE)),
- sp_runtime::MultiAddress::Id(AccountId::from(BOB)),
- RELAY_CHAIN_CURRENCY,
- 1
- ));
- assert_eq!(
- Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(BOB)),
- relay_ed + 1
- );
-
- // ALICE account is reaped and treasury recieves dust tokens
- assert_eq!(
- Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(ALICE)),
- 0
- );
- // Treasury can have under the existential deposit
- assert_eq!(
- Currencies::free_balance(RELAY_CHAIN_CURRENCY, &TreasuryAccount::get()),
- relay_ed - 1
- );
-
- // treasury can send funds when under existential deposit
- assert_ok!(Currencies::transfer(
- Origin::signed(TreasuryAccount::get()),
- sp_runtime::MultiAddress::Id(AccountId::from(BOB)),
- RELAY_CHAIN_CURRENCY,
- relay_ed - 2
- ));
- assert_eq!(
- Currencies::free_balance(RELAY_CHAIN_CURRENCY, &TreasuryAccount::get()),
- 1
- );
-
- assert_ok!(Currencies::transfer(
- Origin::signed(AccountId::from(BOB)),
- sp_runtime::MultiAddress::Id(AccountId::from(ALICE)),
- RELAY_CHAIN_CURRENCY,
- relay_ed
- ));
- assert_eq!(
- Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(ALICE)),
- relay_ed
- );
- assert_eq!(Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(BOB)), 0);
- assert_eq!(
- Currencies::free_balance(RELAY_CHAIN_CURRENCY, &TreasuryAccount::get()),
- relay_ed
- );
- assert_ok!(Currencies::transfer(
- Origin::signed(AccountId::from(ALICE)),
- sp_runtime::MultiAddress::Id(TreasuryAccount::get()),
- RELAY_CHAIN_CURRENCY,
- relay_ed
- ));
-
- // Treasury is not reaped when going from over existential deposit to back under it
- assert_eq!(
- Currencies::free_balance(RELAY_CHAIN_CURRENCY, &TreasuryAccount::get()),
- 2 * relay_ed
- );
- assert_ok!(Currencies::transfer(
- Origin::signed(TreasuryAccount::get()),
- sp_runtime::MultiAddress::Id(AccountId::from(ALICE)),
- RELAY_CHAIN_CURRENCY,
- relay_ed + 1
- ));
- assert_eq!(
- Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(ALICE)),
- relay_ed + 1
- );
- assert_eq!(
- Currencies::free_balance(RELAY_CHAIN_CURRENCY, &TreasuryAccount::get()),
- relay_ed - 1
- );
-
- // Test empty treasury recieves dust tokens of Liquid Currency
- assert_eq!(Currencies::free_balance(LIQUID_CURRENCY, &TreasuryAccount::get()), 0);
- assert_ok!(Currencies::transfer(
- Origin::signed(AccountId::from(ALICE)),
- sp_runtime::MultiAddress::Id(AccountId::from(BOB)),
- LIQUID_CURRENCY,
- 1
- ));
- assert_eq!(
- Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(BOB)),
- liquid_ed + 1
- );
- assert_eq!(Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(ALICE)), 0);
- assert_eq!(
- Currencies::free_balance(LIQUID_CURRENCY, &TreasuryAccount::get()),
- liquid_ed - 1
- );
-
- // Test empty treasury recieves dust tokens of USD Currency using Tokens pallet
- assert_eq!(Tokens::free_balance(USD_CURRENCY, &TreasuryAccount::get()), 0);
- assert_ok!(Tokens::transfer(
- Origin::signed(AccountId::from(ALICE)),
- sp_runtime::MultiAddress::Id(AccountId::from(BOB)),
- USD_CURRENCY,
- 1
- ));
- assert_eq!(Tokens::free_balance(USD_CURRENCY, &AccountId::from(BOB)), usd_ed + 1);
- assert_eq!(Tokens::free_balance(USD_CURRENCY, &AccountId::from(ALICE)), 0);
- assert_eq!(Tokens::free_balance(USD_CURRENCY, &TreasuryAccount::get()), usd_ed - 1);
- });
-}
-
-// Honzon's surplus can be transfered and DebitExchangeRate updates accordingly
-#[test]
-fn cdp_treasury_handles_honzon_surplus_correctly() {
- ExtBuilder::default()
- .balances(vec![
- (
- AccountId::from(ALICE),
- RELAY_CHAIN_CURRENCY,
- 100 * dollar(RELAY_CHAIN_CURRENCY),
- ),
- (AccountId::from(BOB), USD_CURRENCY, 10_000 * dollar(USD_CURRENCY)),
- (
- AccountId::from(BOB),
- RELAY_CHAIN_CURRENCY,
- 100 * dollar(RELAY_CHAIN_CURRENCY),
- ),
- ])
- .build()
- .execute_with(|| {
- System::set_block_number(1);
- assert_ok!(set_oracle_price(vec![(
- RELAY_CHAIN_CURRENCY,
- Price::saturating_from_rational(100, 1)
- )]));
- assert_ok!(CdpEngine::set_collateral_params(
- Origin::root(),
- RELAY_CHAIN_CURRENCY,
- Change::NewValue(Some(Rate::saturating_from_rational(1, 10000))),
- Change::NewValue(Some(Ratio::saturating_from_rational(200, 100))),
- Change::NewValue(Some(Rate::saturating_from_rational(20, 100))),
- Change::NewValue(Some(Ratio::saturating_from_rational(200, 100))),
- Change::NewValue(1_000_000 * dollar(USD_CURRENCY)),
- ));
- assert_ok!(Dex::add_liquidity(
- Origin::signed(AccountId::from(BOB)),
- RELAY_CHAIN_CURRENCY,
- USD_CURRENCY,
- 100 * dollar(RELAY_CHAIN_CURRENCY),
- 10_000 * dollar(USD_CURRENCY),
- 0,
- false,
- ));
-
- // Honzon loans work
- assert_ok!(Honzon::adjust_loan(
- Origin::signed(AccountId::from(ALICE)),
- RELAY_CHAIN_CURRENCY,
- 50 * dollar(RELAY_CHAIN_CURRENCY) as i128,
- 500 * dollar(USD_CURRENCY) as i128
- ));
- assert_eq!(
- Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).collateral,
- 50 * dollar(RELAY_CHAIN_CURRENCY)
- );
- assert_eq!(
- Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).debit,
- 500 * dollar(USD_CURRENCY)
- );
- assert_eq!(
- Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(ALICE)),
- 50 * dollar(RELAY_CHAIN_CURRENCY)
- );
- assert_eq!(
- Currencies::free_balance(USD_CURRENCY, &AccountId::from(ALICE)),
- 50 * dollar(USD_CURRENCY)
- );
- assert_eq!(Currencies::free_balance(USD_CURRENCY, &CdpTreasury::account_id()), 0);
- assert_eq!(CdpTreasury::get_surplus_pool(), 0);
- assert_eq!(CdpTreasury::get_debit_pool(), 0);
- run_to_block(2);
-
- // Empty treasury recieves stablecoins into surplus pool from loan
- assert_eq!(CdpTreasury::get_surplus_pool(), 160248248179);
- assert_eq!(CdpTreasury::get_debit_pool(), 0);
- // Honzon generated cdp treasury surplus can be transfered
- assert_eq!(Currencies::free_balance(USD_CURRENCY, &AccountId::from(BOB)), 0);
- assert_eq!(
- CdpEngine::debit_exchange_rate(RELAY_CHAIN_CURRENCY),
- // about 1/10
- Some(Ratio::saturating_from_rational(
- 100320496496359801 as i64,
- 1000000000000000000 as i64
- ))
- );
- // Cdp treasury cannot be reaped
- assert_ok!(Currencies::transfer(
- Origin::signed(CdpTreasury::account_id()),
- sp_runtime::MultiAddress::Id(AccountId::from(BOB)),
- USD_CURRENCY,
- CdpTreasury::get_surplus_pool() - 1
- ));
- assert_eq!(
- Currencies::free_balance(USD_CURRENCY, &AccountId::from(BOB)),
- 160248248178
- );
- assert_eq!(Currencies::free_balance(USD_CURRENCY, &CdpTreasury::account_id()), 1);
- run_to_block(3);
- // Debt exchange rate updates
- assert_eq!(
- CdpEngine::debit_exchange_rate(RELAY_CHAIN_CURRENCY),
- // Around 1/10, increasing from last check
- Some(Ratio::saturating_from_rational(
- 100330528546009436 as i64,
- 1000000000000000000 as i64
- ))
- );
-
- // Closing loan will add to treasury debit_pool
- assert_ok!(Honzon::close_loan_has_debit_by_dex(
- Origin::signed(AccountId::from(ALICE)),
- RELAY_CHAIN_CURRENCY,
- 5 * dollar(RELAY_CHAIN_CURRENCY),
- None
- ));
- // Just over 50 dollar(USD_CURRENCY), due to interest on loan
- assert_eq!(CdpTreasury::get_debit_pool(), 50165264273004);
- assert_eq!(Loans::total_positions(RELAY_CHAIN_CURRENCY).debit, 0);
- run_to_block(4);
- // Debt exchange rate doesn't update due to no debit positions
- assert_eq!(
- CdpEngine::debit_exchange_rate(RELAY_CHAIN_CURRENCY),
- Some(Ratio::saturating_from_rational(
- 100330528546009436 as i64,
- 1000000000000000000 as i64
- ))
- )
- });
-}
-
-#[test]
-fn proxy_behavior_correct() {
- ExtBuilder::default()
- .balances(vec![
- (AccountId::from(ALICE), NATIVE_CURRENCY, 100 * dollar(NATIVE_CURRENCY)),
- (AccountId::from(BOB), NATIVE_CURRENCY, 100 * dollar(NATIVE_CURRENCY)),
- ])
- .build()
- .execute_with(|| {
- // proxy fails for account with no NATIVE_CURRENCY
- assert_noop!(
- Proxy::add_proxy(
- Origin::signed(AccountId::from([21; 32])),
- AccountId::from(ALICE),
- ProxyType::Any,
- 0
- ),
- pallet_balances::Error::::InsufficientBalance
- );
- let call = Box::new(Call::Currencies(module_currencies::Call::transfer {
- dest: AccountId::from(ALICE).into(),
- currency_id: NATIVE_CURRENCY,
- amount: 10 * dollar(NATIVE_CURRENCY),
- }));
-
- // Alice has all Bob's permissions now
- assert_ok!(Proxy::add_proxy(
- Origin::signed(AccountId::from(BOB)),
- AccountId::from(ALICE),
- ProxyType::Any,
- 0
- ));
- // takes deposit from bobs account for proxy
- assert!(Currencies::free_balance(NATIVE_CURRENCY, &AccountId::from(BOB)) < 100 * dollar(NATIVE_CURRENCY));
-
- // alice can now make calls for bob's account
- assert_ok!(Proxy::proxy(
- Origin::signed(AccountId::from(ALICE)),
- AccountId::from(BOB),
- None,
- call.clone()
- ));
- assert_eq!(
- Currencies::free_balance(NATIVE_CURRENCY, &AccountId::from(ALICE)),
- 110 * dollar(NATIVE_CURRENCY)
- );
-
- // alice cannot make calls for bob's account anymore
- assert_ok!(Proxy::remove_proxy(
- Origin::signed(AccountId::from(BOB)),
- AccountId::from(ALICE),
- ProxyType::Any,
- 0
- ));
- assert_noop!(
- Proxy::proxy(
- Origin::signed(AccountId::from(ALICE)),
- AccountId::from(BOB),
- None,
- call.clone()
- ),
- pallet_proxy::Error::::NotProxy
- );
- // bob's deposit is returned
- assert_eq!(
- Currencies::free_balance(NATIVE_CURRENCY, &AccountId::from(BOB)),
- 90000000000000
- );
- });
-}
-
-#[test]
-fn proxy_permissions_correct() {
- ExtBuilder::default()
- .balances(vec![
- (AccountId::from(ALICE), NATIVE_CURRENCY, 100 * dollar(NATIVE_CURRENCY)),
- (AccountId::from(BOB), NATIVE_CURRENCY, 100 * dollar(NATIVE_CURRENCY)),
- (
- AccountId::from(BOB),
- RELAY_CHAIN_CURRENCY,
- 100 * dollar(RELAY_CHAIN_CURRENCY),
- ),
- (
- AccountId::from(ALICE),
- RELAY_CHAIN_CURRENCY,
- 100 * dollar(RELAY_CHAIN_CURRENCY),
- ),
- (AccountId::from(BOB), USD_CURRENCY, 100 * dollar(USD_CURRENCY)),
- (AccountId::from(ALICE), USD_CURRENCY, 100 * dollar(USD_CURRENCY)),
- ])
- .build()
- .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)
- )]));
- assert_ok!(CdpEngine::set_collateral_params(
- Origin::root(),
- RELAY_CHAIN_CURRENCY,
- Change::NewValue(Some(Rate::saturating_from_rational(1, 10000))),
- Change::NewValue(Some(Ratio::saturating_from_rational(200, 100))),
- Change::NewValue(Some(Rate::saturating_from_rational(20, 100))),
- Change::NewValue(Some(Ratio::saturating_from_rational(200, 100))),
- Change::NewValue(1_000_000 * dollar(USD_CURRENCY)),
- ));
- assert_ok!(Dex::add_liquidity(
- Origin::signed(AccountId::from(BOB)),
- RELAY_CHAIN_CURRENCY,
- USD_CURRENCY,
- 5 * dollar(RELAY_CHAIN_CURRENCY),
- 10 * dollar(USD_CURRENCY),
- 0,
- false,
- ));
- // Alice has all Bob's permissions now
- assert_ok!(Proxy::add_proxy(
- Origin::signed(AccountId::from(BOB)),
- AccountId::from(ALICE),
- ProxyType::Any,
- 0
- ));
- let root_call = Box::new(Call::Currencies(module_currencies::Call::update_balance {
- who: AccountId::from(ALICE).into(),
- currency_id: NATIVE_CURRENCY,
- amount: 1000 * dollar(NATIVE_CURRENCY) as i128,
- }));
- let gov_call = Box::new(Call::Tips(pallet_tips::Call::report_awesome {
- reason: b"bob is awesome".to_vec(),
- who: AccountId::from(BOB),
- }));
- let transfer_call = Box::new(Call::Currencies(module_currencies::Call::transfer {
- dest: AccountId::from(BOB).into(),
- currency_id: NATIVE_CURRENCY,
- amount: 10 * dollar(NATIVE_CURRENCY),
- }));
- let adjust_loan_call = Box::new(Call::Honzon(module_honzon::Call::adjust_loan {
- currency_id: RELAY_CHAIN_CURRENCY,
- collateral_adjustment: 10 * dollar(RELAY_CHAIN_CURRENCY) as i128,
- debit_adjustment: min_debit as i128,
- }));
- let authorize_loan_call = Box::new(Call::Honzon(module_honzon::Call::authorize {
- currency_id: RELAY_CHAIN_CURRENCY,
- to: AccountId::from(BOB).into(),
- }));
- let dex_swap_call = Box::new(Call::Dex(module_dex::Call::swap_with_exact_target {
- path: vec![RELAY_CHAIN_CURRENCY, USD_CURRENCY],
- target_amount: dollar(USD_CURRENCY),
- max_supply_amount: dollar(RELAY_CHAIN_CURRENCY),
- }));
- let dex_add_liquidity_call = Box::new(Call::Dex(module_dex::Call::add_liquidity {
- currency_id_a: RELAY_CHAIN_CURRENCY,
- currency_id_b: USD_CURRENCY,
- max_amount_a: 10 * dollar(RELAY_CHAIN_CURRENCY),
- max_amount_b: 10 * dollar(USD_CURRENCY),
- min_share_increment: 0,
- stake_increment_share: false,
- }));
-
- // Proxy calls do not bypass root permision
- assert_ok!(Proxy::proxy(
- Origin::signed(AccountId::from(ALICE)),
- AccountId::from(BOB),
- None,
- root_call.clone()
- ));
- // while the proxy call executes the call being proxied fails
- assert_eq!(
- Currencies::free_balance(NATIVE_CURRENCY, &AccountId::from(ALICE)),
- 100 * dollar(NATIVE_CURRENCY)
- );
-
- // Alice's gives governance permissions to Bob
- assert_ok!(Proxy::add_proxy(
- Origin::signed(AccountId::from(ALICE)),
- AccountId::from(BOB),
- ProxyType::Governance,
- 0
- ));
- // Bob can be a proxy for alice gov call
- assert_ok!(Proxy::proxy(
- Origin::signed(AccountId::from(BOB)),
- AccountId::from(ALICE),
- Some(ProxyType::Governance),
- gov_call.clone()
- ));
- let hash = BlakeTwo256::hash_of(&(BlakeTwo256::hash(b"bob is awesome"), AccountId::from(BOB)));
- // last event was sucessful tip call
- assert_eq!(
- System::events()
- .into_iter()
- .map(|r| r.event)
- .filter_map(|e| if let Event::Tips(inner) = e { Some(inner) } else { None })
- .last()
- .unwrap(),
- pallet_tips::Event::::NewTip(hash)
- );
-
- // Bob can't proxy for alice in a non gov call, once again proxy call works but nested call fails
- assert_ok!(Proxy::proxy(
- Origin::signed(AccountId::from(BOB)),
- AccountId::from(ALICE),
- Some(ProxyType::Governance),
- transfer_call.clone()
- ));
- // the transfer call fails as Bob only had governence permission for alice
- assert!(Currencies::free_balance(NATIVE_CURRENCY, &AccountId::from(BOB)) < 100 * dollar(NATIVE_CURRENCY));
-
- assert_ok!(Proxy::add_proxy(
- Origin::signed(AccountId::from(ALICE)),
- AccountId::from(BOB),
- ProxyType::Loan,
- 0
- ));
- assert_ok!(Proxy::proxy(
- Origin::signed(AccountId::from(BOB)),
- AccountId::from(ALICE),
- Some(ProxyType::Loan),
- adjust_loan_call.clone()
- ));
- assert_eq!(
- Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).collateral,
- 10 * dollar(RELAY_CHAIN_CURRENCY)
- );
- assert_eq!(
- Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).debit,
- min_debit
- );
- // authorize call is part of the Honzon module but is not in the Loan ProxyType filter
- assert_ok!(Proxy::proxy(
- Origin::signed(AccountId::from(BOB)),
- AccountId::from(ALICE),
- Some(ProxyType::Loan),
- authorize_loan_call.clone()
- ));
- // hence the failure
- System::assert_last_event(pallet_proxy::Event::ProxyExecuted(Err(DispatchError::BadOrigin)).into());
-
- // gives Bob ability to proxy alice's account for dex swaps
- assert_ok!(Proxy::add_proxy(
- Origin::signed(AccountId::from(ALICE)),
- AccountId::from(BOB),
- ProxyType::Swap,
- 0
- ));
-
- let pre_swap = Currencies::free_balance(USD_CURRENCY, &AccountId::from(ALICE));
- assert_ok!(Proxy::proxy(
- Origin::signed(AccountId::from(BOB)),
- AccountId::from(ALICE),
- Some(ProxyType::Swap),
- dex_swap_call.clone()
- ));
- let post_swap = Currencies::free_balance(USD_CURRENCY, &AccountId::from(ALICE));
- assert_eq!(post_swap - pre_swap, dollar(USD_CURRENCY));
-
- assert_ok!(Proxy::proxy(
- Origin::signed(AccountId::from(BOB)),
- AccountId::from(ALICE),
- Some(ProxyType::Swap),
- dex_add_liquidity_call.clone()
- ));
- // again add liquidity call is part of the Dex module but is not allowed in the Swap ProxyType
- // filter
- System::assert_last_event(pallet_proxy::Event::ProxyExecuted(Err(DispatchError::BadOrigin)).into());
-
- // Tests that adding more ProxyType permssions does not effect others
- assert_ok!(Proxy::proxy(
- Origin::signed(AccountId::from(BOB)),
- AccountId::from(ALICE),
- Some(ProxyType::Loan),
- adjust_loan_call.clone()
- ));
- assert_eq!(
- Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).collateral,
- 20 * dollar(RELAY_CHAIN_CURRENCY)
- );
- assert_eq!(
- Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).debit,
- 2 * min_debit
- );
-
- // remove proxy works
- assert_ok!(Proxy::remove_proxy(
- Origin::signed(AccountId::from(ALICE)),
- AccountId::from(BOB),
- ProxyType::Loan,
- 0
- ));
- assert_noop!(
- Proxy::proxy(
- Origin::signed(AccountId::from(BOB)),
- AccountId::from(ALICE),
- Some(ProxyType::Loan),
- adjust_loan_call.clone()
- ),
- pallet_proxy::Error::::NotProxy
- );
- });
-}
diff --git a/runtime/integration-tests/src/lib.rs b/runtime/integration-tests/src/lib.rs
index 57d9cd82d..54041c1cd 100644
--- a/runtime/integration-tests/src/lib.rs
+++ b/runtime/integration-tests/src/lib.rs
@@ -19,20 +19,43 @@
#![cfg(test)]
#[cfg(any(feature = "with-mandala-runtime", feature = "with-karura-runtime",))]
-mod integration_tests;
+mod setup;
#[cfg(any(feature = "with-mandala-runtime", feature = "with-karura-runtime",))]
-mod homa_lite_tests;
+mod authority;
#[cfg(any(feature = "with-mandala-runtime", feature = "with-karura-runtime",))]
-mod evm_tests;
+mod dex;
#[cfg(any(feature = "with-mandala-runtime", feature = "with-karura-runtime",))]
-mod weights_test;
+mod evm;
+
+#[cfg(any(feature = "with-mandala-runtime", feature = "with-karura-runtime",))]
+mod homa_lite;
+
+#[cfg(any(feature = "with-mandala-runtime", feature = "with-karura-runtime",))]
+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 proxy;
+
+#[cfg(any(feature = "with-mandala-runtime", feature = "with-karura-runtime",))]
+mod runtime;
+
+#[cfg(any(feature = "with-mandala-runtime", feature = "with-karura-runtime",))]
+mod session_manager;
+
+#[cfg(any(feature = "with-mandala-runtime", feature = "with-karura-runtime",))]
+mod treasury;
+
+#[cfg(any(feature = "with-mandala-runtime", feature = "with-karura-runtime",))]
+mod vesting;
+
+#[cfg(any(feature = "with-mandala-runtime", feature = "with-karura-runtime",))]
+mod weights;
#[cfg(feature = "with-karura-runtime")]
-mod kusama_cross_chain_transfer;
-#[cfg(feature = "with-karura-runtime")]
-mod kusama_test_net;
-#[cfg(feature = "with-karura-runtime")]
-mod relay_chain_tests;
+mod relaychain;
diff --git a/runtime/integration-tests/src/nft.rs b/runtime/integration-tests/src/nft.rs
new file mode 100644
index 000000000..318260f71
--- /dev/null
+++ b/runtime/integration-tests/src/nft.rs
@@ -0,0 +1,100 @@
+// 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::*;
+
+#[test]
+fn test_nft_module() {
+ ExtBuilder::default()
+ .balances(vec![(
+ AccountId::from(ALICE),
+ NATIVE_CURRENCY,
+ 1_000 * dollar(NATIVE_CURRENCY),
+ )])
+ .build()
+ .execute_with(|| {
+ let metadata = vec![1];
+ assert_eq!(
+ Balances::free_balance(AccountId::from(ALICE)),
+ 1_000 * dollar(NATIVE_CURRENCY)
+ );
+ assert_eq!(Balances::reserved_balance(AccountId::from(ALICE)), 0);
+ assert_ok!(NFT::create_class(
+ Origin::signed(AccountId::from(ALICE)),
+ metadata.clone(),
+ module_nft::Properties(
+ module_nft::ClassProperty::Transferable
+ | module_nft::ClassProperty::Burnable
+ | module_nft::ClassProperty::Mintable
+ ),
+ Default::default(),
+ ));
+ let deposit =
+ Proxy::deposit(1u32) + CreateClassDeposit::get() + DataDepositPerByte::get() * (metadata.len() as u128);
+ assert_eq!(Balances::free_balance(&NftPalletId::get().into_sub_account(0)), 0);
+ assert_eq!(
+ Balances::reserved_balance(&NftPalletId::get().into_sub_account(0)),
+ deposit
+ );
+ assert_eq!(
+ Balances::free_balance(AccountId::from(ALICE)),
+ 1_000 * dollar(NATIVE_CURRENCY) - deposit
+ );
+ assert_eq!(Balances::reserved_balance(AccountId::from(ALICE)), 0);
+ assert_ok!(Balances::deposit_into_existing(
+ &NftPalletId::get().into_sub_account(0),
+ 1 * (CreateTokenDeposit::get() + DataDepositPerByte::get())
+ ));
+ assert_ok!(NFT::mint(
+ Origin::signed(NftPalletId::get().into_sub_account(0)),
+ MultiAddress::Id(AccountId::from(BOB)),
+ 0,
+ metadata.clone(),
+ Default::default(),
+ 1
+ ));
+ assert_ok!(NFT::burn(Origin::signed(AccountId::from(BOB)), (0, 0)));
+ assert_eq!(
+ Balances::free_balance(AccountId::from(BOB)),
+ CreateTokenDeposit::get() + DataDepositPerByte::get()
+ );
+ assert_noop!(
+ NFT::destroy_class(
+ Origin::signed(NftPalletId::get().into_sub_account(0)),
+ 0,
+ MultiAddress::Id(AccountId::from(BOB))
+ ),
+ pallet_proxy::Error::::NotFound
+ );
+ assert_ok!(NFT::destroy_class(
+ Origin::signed(NftPalletId::get().into_sub_account(0)),
+ 0,
+ MultiAddress::Id(AccountId::from(ALICE))
+ ));
+ assert_eq!(
+ Balances::free_balance(AccountId::from(BOB)),
+ CreateTokenDeposit::get() + DataDepositPerByte::get()
+ );
+ assert_eq!(Balances::reserved_balance(AccountId::from(BOB)), 0);
+ assert_eq!(
+ Balances::free_balance(AccountId::from(ALICE)),
+ 1_000 * dollar(NATIVE_CURRENCY)
+ );
+ assert_eq!(Balances::reserved_balance(AccountId::from(ALICE)), 0);
+ });
+}
diff --git a/runtime/integration-tests/src/proxy.rs b/runtime/integration-tests/src/proxy.rs
new file mode 100644
index 000000000..612af21d0
--- /dev/null
+++ b/runtime/integration-tests/src/proxy.rs
@@ -0,0 +1,321 @@
+// 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::*;
+
+#[test]
+fn proxy_behavior_correct() {
+ ExtBuilder::default()
+ .balances(vec![
+ (AccountId::from(ALICE), NATIVE_CURRENCY, 100 * dollar(NATIVE_CURRENCY)),
+ (AccountId::from(BOB), NATIVE_CURRENCY, 100 * dollar(NATIVE_CURRENCY)),
+ ])
+ .build()
+ .execute_with(|| {
+ // proxy fails for account with no NATIVE_CURRENCY
+ assert_noop!(
+ Proxy::add_proxy(
+ Origin::signed(AccountId::from([21; 32])),
+ AccountId::from(ALICE),
+ ProxyType::Any,
+ 0
+ ),
+ pallet_balances::Error::::InsufficientBalance
+ );
+ let call = Box::new(Call::Currencies(module_currencies::Call::transfer {
+ dest: AccountId::from(ALICE).into(),
+ currency_id: NATIVE_CURRENCY,
+ amount: 10 * dollar(NATIVE_CURRENCY),
+ }));
+
+ // Alice has all Bob's permissions now
+ assert_ok!(Proxy::add_proxy(
+ Origin::signed(AccountId::from(BOB)),
+ AccountId::from(ALICE),
+ ProxyType::Any,
+ 0
+ ));
+ // takes deposit from bobs account for proxy
+ assert!(Currencies::free_balance(NATIVE_CURRENCY, &AccountId::from(BOB)) < 100 * dollar(NATIVE_CURRENCY));
+
+ // alice can now make calls for bob's account
+ assert_ok!(Proxy::proxy(
+ Origin::signed(AccountId::from(ALICE)),
+ AccountId::from(BOB),
+ None,
+ call.clone()
+ ));
+ assert_eq!(
+ Currencies::free_balance(NATIVE_CURRENCY, &AccountId::from(ALICE)),
+ 110 * dollar(NATIVE_CURRENCY)
+ );
+
+ // alice cannot make calls for bob's account anymore
+ assert_ok!(Proxy::remove_proxy(
+ Origin::signed(AccountId::from(BOB)),
+ AccountId::from(ALICE),
+ ProxyType::Any,
+ 0
+ ));
+ assert_noop!(
+ Proxy::proxy(
+ Origin::signed(AccountId::from(ALICE)),
+ AccountId::from(BOB),
+ None,
+ call.clone()
+ ),
+ pallet_proxy::Error::::NotProxy
+ );
+ // bob's deposit is returned
+ assert_eq!(
+ Currencies::free_balance(NATIVE_CURRENCY, &AccountId::from(BOB)),
+ 90000000000000
+ );
+ });
+}
+
+#[test]
+fn proxy_permissions_correct() {
+ ExtBuilder::default()
+ .balances(vec![
+ (AccountId::from(ALICE), NATIVE_CURRENCY, 100 * dollar(NATIVE_CURRENCY)),
+ (AccountId::from(BOB), NATIVE_CURRENCY, 100 * dollar(NATIVE_CURRENCY)),
+ (
+ AccountId::from(BOB),
+ RELAY_CHAIN_CURRENCY,
+ 100 * dollar(RELAY_CHAIN_CURRENCY),
+ ),
+ (
+ AccountId::from(ALICE),
+ RELAY_CHAIN_CURRENCY,
+ 100 * dollar(RELAY_CHAIN_CURRENCY),
+ ),
+ (AccountId::from(BOB), USD_CURRENCY, 100 * dollar(USD_CURRENCY)),
+ (AccountId::from(ALICE), USD_CURRENCY, 100 * dollar(USD_CURRENCY)),
+ ])
+ .build()
+ .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)
+ )]));
+ assert_ok!(CdpEngine::set_collateral_params(
+ Origin::root(),
+ RELAY_CHAIN_CURRENCY,
+ Change::NewValue(Some(Rate::saturating_from_rational(1, 10000))),
+ Change::NewValue(Some(Ratio::saturating_from_rational(200, 100))),
+ Change::NewValue(Some(Rate::saturating_from_rational(20, 100))),
+ Change::NewValue(Some(Ratio::saturating_from_rational(200, 100))),
+ Change::NewValue(1_000_000 * dollar(USD_CURRENCY)),
+ ));
+ assert_ok!(Dex::add_liquidity(
+ Origin::signed(AccountId::from(BOB)),
+ RELAY_CHAIN_CURRENCY,
+ USD_CURRENCY,
+ 5 * dollar(RELAY_CHAIN_CURRENCY),
+ 10 * dollar(USD_CURRENCY),
+ 0,
+ false,
+ ));
+ // Alice has all Bob's permissions now
+ assert_ok!(Proxy::add_proxy(
+ Origin::signed(AccountId::from(BOB)),
+ AccountId::from(ALICE),
+ ProxyType::Any,
+ 0
+ ));
+ let root_call = Box::new(Call::Currencies(module_currencies::Call::update_balance {
+ who: AccountId::from(ALICE).into(),
+ currency_id: NATIVE_CURRENCY,
+ amount: 1000 * dollar(NATIVE_CURRENCY) as i128,
+ }));
+ let gov_call = Box::new(Call::Tips(pallet_tips::Call::report_awesome {
+ reason: b"bob is awesome".to_vec(),
+ who: AccountId::from(BOB),
+ }));
+ let transfer_call = Box::new(Call::Currencies(module_currencies::Call::transfer {
+ dest: AccountId::from(BOB).into(),
+ currency_id: NATIVE_CURRENCY,
+ amount: 10 * dollar(NATIVE_CURRENCY),
+ }));
+ let adjust_loan_call = Box::new(Call::Honzon(module_honzon::Call::adjust_loan {
+ currency_id: RELAY_CHAIN_CURRENCY,
+ collateral_adjustment: 10 * dollar(RELAY_CHAIN_CURRENCY) as i128,
+ debit_adjustment: min_debit as i128,
+ }));
+ let authorize_loan_call = Box::new(Call::Honzon(module_honzon::Call::authorize {
+ currency_id: RELAY_CHAIN_CURRENCY,
+ to: AccountId::from(BOB).into(),
+ }));
+ let dex_swap_call = Box::new(Call::Dex(module_dex::Call::swap_with_exact_target {
+ path: vec![RELAY_CHAIN_CURRENCY, USD_CURRENCY],
+ target_amount: dollar(USD_CURRENCY),
+ max_supply_amount: dollar(RELAY_CHAIN_CURRENCY),
+ }));
+ let dex_add_liquidity_call = Box::new(Call::Dex(module_dex::Call::add_liquidity {
+ currency_id_a: RELAY_CHAIN_CURRENCY,
+ currency_id_b: USD_CURRENCY,
+ max_amount_a: 10 * dollar(RELAY_CHAIN_CURRENCY),
+ max_amount_b: 10 * dollar(USD_CURRENCY),
+ min_share_increment: 0,
+ stake_increment_share: false,
+ }));
+
+ // Proxy calls do not bypass root permision
+ assert_ok!(Proxy::proxy(
+ Origin::signed(AccountId::from(ALICE)),
+ AccountId::from(BOB),
+ None,
+ root_call.clone()
+ ));
+ // while the proxy call executes the call being proxied fails
+ assert_eq!(
+ Currencies::free_balance(NATIVE_CURRENCY, &AccountId::from(ALICE)),
+ 100 * dollar(NATIVE_CURRENCY)
+ );
+
+ // Alice's gives governance permissions to Bob
+ assert_ok!(Proxy::add_proxy(
+ Origin::signed(AccountId::from(ALICE)),
+ AccountId::from(BOB),
+ ProxyType::Governance,
+ 0
+ ));
+ // Bob can be a proxy for alice gov call
+ assert_ok!(Proxy::proxy(
+ Origin::signed(AccountId::from(BOB)),
+ AccountId::from(ALICE),
+ Some(ProxyType::Governance),
+ gov_call.clone()
+ ));
+ let hash = BlakeTwo256::hash_of(&(BlakeTwo256::hash(b"bob is awesome"), AccountId::from(BOB)));
+ // last event was sucessful tip call
+ assert_eq!(
+ System::events()
+ .into_iter()
+ .map(|r| r.event)
+ .filter_map(|e| if let Event::Tips(inner) = e { Some(inner) } else { None })
+ .last()
+ .unwrap(),
+ pallet_tips::Event::::NewTip(hash)
+ );
+
+ // Bob can't proxy for alice in a non gov call, once again proxy call works but nested call fails
+ assert_ok!(Proxy::proxy(
+ Origin::signed(AccountId::from(BOB)),
+ AccountId::from(ALICE),
+ Some(ProxyType::Governance),
+ transfer_call.clone()
+ ));
+ // the transfer call fails as Bob only had governence permission for alice
+ assert!(Currencies::free_balance(NATIVE_CURRENCY, &AccountId::from(BOB)) < 100 * dollar(NATIVE_CURRENCY));
+
+ assert_ok!(Proxy::add_proxy(
+ Origin::signed(AccountId::from(ALICE)),
+ AccountId::from(BOB),
+ ProxyType::Loan,
+ 0
+ ));
+ assert_ok!(Proxy::proxy(
+ Origin::signed(AccountId::from(BOB)),
+ AccountId::from(ALICE),
+ Some(ProxyType::Loan),
+ adjust_loan_call.clone()
+ ));
+ assert_eq!(
+ Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).collateral,
+ 10 * dollar(RELAY_CHAIN_CURRENCY)
+ );
+ assert_eq!(
+ Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).debit,
+ min_debit
+ );
+ // authorize call is part of the Honzon module but is not in the Loan ProxyType filter
+ assert_ok!(Proxy::proxy(
+ Origin::signed(AccountId::from(BOB)),
+ AccountId::from(ALICE),
+ Some(ProxyType::Loan),
+ authorize_loan_call.clone()
+ ));
+ // hence the failure
+ System::assert_last_event(pallet_proxy::Event::ProxyExecuted(Err(DispatchError::BadOrigin)).into());
+
+ // gives Bob ability to proxy alice's account for dex swaps
+ assert_ok!(Proxy::add_proxy(
+ Origin::signed(AccountId::from(ALICE)),
+ AccountId::from(BOB),
+ ProxyType::Swap,
+ 0
+ ));
+
+ let pre_swap = Currencies::free_balance(USD_CURRENCY, &AccountId::from(ALICE));
+ assert_ok!(Proxy::proxy(
+ Origin::signed(AccountId::from(BOB)),
+ AccountId::from(ALICE),
+ Some(ProxyType::Swap),
+ dex_swap_call.clone()
+ ));
+ let post_swap = Currencies::free_balance(USD_CURRENCY, &AccountId::from(ALICE));
+ assert_eq!(post_swap - pre_swap, dollar(USD_CURRENCY));
+
+ assert_ok!(Proxy::proxy(
+ Origin::signed(AccountId::from(BOB)),
+ AccountId::from(ALICE),
+ Some(ProxyType::Swap),
+ dex_add_liquidity_call.clone()
+ ));
+ // again add liquidity call is part of the Dex module but is not allowed in the Swap ProxyType
+ // filter
+ System::assert_last_event(pallet_proxy::Event::ProxyExecuted(Err(DispatchError::BadOrigin)).into());
+
+ // Tests that adding more ProxyType permssions does not effect others
+ assert_ok!(Proxy::proxy(
+ Origin::signed(AccountId::from(BOB)),
+ AccountId::from(ALICE),
+ Some(ProxyType::Loan),
+ adjust_loan_call.clone()
+ ));
+ assert_eq!(
+ Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).collateral,
+ 20 * dollar(RELAY_CHAIN_CURRENCY)
+ );
+ assert_eq!(
+ Loans::positions(RELAY_CHAIN_CURRENCY, AccountId::from(ALICE)).debit,
+ 2 * min_debit
+ );
+
+ // remove proxy works
+ assert_ok!(Proxy::remove_proxy(
+ Origin::signed(AccountId::from(ALICE)),
+ AccountId::from(BOB),
+ ProxyType::Loan,
+ 0
+ ));
+ assert_noop!(
+ Proxy::proxy(
+ Origin::signed(AccountId::from(BOB)),
+ AccountId::from(ALICE),
+ Some(ProxyType::Loan),
+ adjust_loan_call.clone()
+ ),
+ pallet_proxy::Error::::NotProxy
+ );
+ });
+}
diff --git a/runtime/integration-tests/src/kusama_cross_chain_transfer.rs b/runtime/integration-tests/src/relaychain/kusama_cross_chain_transfer.rs
similarity index 95%
rename from runtime/integration-tests/src/kusama_cross_chain_transfer.rs
rename to runtime/integration-tests/src/relaychain/kusama_cross_chain_transfer.rs
index c66159cc4..de7a99aa5 100644
--- a/runtime/integration-tests/src/kusama_cross_chain_transfer.rs
+++ b/runtime/integration-tests/src/relaychain/kusama_cross_chain_transfer.rs
@@ -18,11 +18,10 @@
//! Cross-chain transfer tests within Kusama network.
-use crate::integration_tests::*;
-use crate::kusama_test_net::*;
+use crate::relaychain::kusama_test_net::*;
+use crate::setup::*;
use frame_support::assert_ok;
-use xcm::latest::prelude::*;
use orml_traits::MultiCurrency;
use xcm_emulator::TestExt;
diff --git a/runtime/integration-tests/src/kusama_test_net.rs b/runtime/integration-tests/src/relaychain/kusama_test_net.rs
similarity index 99%
rename from runtime/integration-tests/src/kusama_test_net.rs
rename to runtime/integration-tests/src/relaychain/kusama_test_net.rs
index 6ef6d5af7..28685ada3 100644
--- a/runtime/integration-tests/src/kusama_test_net.rs
+++ b/runtime/integration-tests/src/relaychain/kusama_test_net.rs
@@ -18,7 +18,7 @@
//! Relay chain and parachains emulation.
-use crate::integration_tests::*;
+use crate::setup::*;
use cumulus_primitives_core::ParaId;
use frame_support::traits::GenesisBuild;
diff --git a/runtime/integration-tests/src/relaychain/mod.rs b/runtime/integration-tests/src/relaychain/mod.rs
new file mode 100644
index 000000000..1f704d479
--- /dev/null
+++ b/runtime/integration-tests/src/relaychain/mod.rs
@@ -0,0 +1,21 @@
+// 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 .
+
+mod kusama_cross_chain_transfer;
+pub mod kusama_test_net;
+mod relay_chain;
diff --git a/runtime/integration-tests/src/relay_chain_tests.rs b/runtime/integration-tests/src/relaychain/relay_chain.rs
similarity index 98%
rename from runtime/integration-tests/src/relay_chain_tests.rs
rename to runtime/integration-tests/src/relaychain/relay_chain.rs
index 96e50dcdc..a4484b660 100644
--- a/runtime/integration-tests/src/relay_chain_tests.rs
+++ b/runtime/integration-tests/src/relaychain/relay_chain.rs
@@ -21,15 +21,14 @@
#[cfg(feature = "with-karura-runtime")]
mod karura_tests {
- use crate::integration_tests::*;
- use crate::kusama_test_net::*;
+ use crate::relaychain::kusama_test_net::*;
+ use crate::setup::*;
use frame_support::{assert_noop, assert_ok};
use codec::Decode;
use module_relaychain::RelayChainCallBuilder;
use module_support::CallBuilder;
- use xcm::latest::prelude::*;
use xcm_emulator::TestExt;
type KusamaCallBuilder = RelayChainCallBuilder;
diff --git a/runtime/integration-tests/src/runtime.rs b/runtime/integration-tests/src/runtime.rs
new file mode 100644
index 000000000..afaacf975
--- /dev/null
+++ b/runtime/integration-tests/src/runtime.rs
@@ -0,0 +1,280 @@
+// 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::*;
+
+#[test]
+fn currency_id_convert() {
+ ExtBuilder::default().build().execute_with(|| {
+ let id: u32 = ParachainInfo::get().into();
+
+ assert_eq!(
+ CurrencyIdConvert::convert(RELAY_CHAIN_CURRENCY),
+ Some(MultiLocation::parent())
+ );
+
+ assert_eq!(
+ CurrencyIdConvert::convert(NATIVE_CURRENCY),
+ Some(MultiLocation::sibling_parachain_general_key(
+ id,
+ NATIVE_CURRENCY.encode()
+ ))
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(USD_CURRENCY),
+ Some(MultiLocation::sibling_parachain_general_key(id, USD_CURRENCY.encode()))
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(LIQUID_CURRENCY),
+ Some(MultiLocation::sibling_parachain_general_key(
+ id,
+ LIQUID_CURRENCY.encode()
+ ))
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::parent()),
+ Some(RELAY_CHAIN_CURRENCY)
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(
+ id,
+ NATIVE_CURRENCY.encode()
+ )),
+ Some(NATIVE_CURRENCY)
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, USD_CURRENCY.encode())),
+ Some(USD_CURRENCY)
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(
+ id,
+ LIQUID_CURRENCY.encode()
+ )),
+ Some(LIQUID_CURRENCY)
+ );
+
+ #[cfg(feature = "with-mandala-runtime")]
+ {
+ assert_eq!(CurrencyIdConvert::convert(KAR), None);
+ assert_eq!(CurrencyIdConvert::convert(KUSD), None);
+ assert_eq!(CurrencyIdConvert::convert(KSM), None);
+ assert_eq!(CurrencyIdConvert::convert(LKSM), None);
+
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, RENBTC.encode())),
+ Some(RENBTC)
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, KAR.encode())),
+ None
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, KUSD.encode())),
+ None
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, KSM.encode())),
+ None
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, KSM.encode())),
+ None
+ );
+
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id + 1, RENBTC.encode())),
+ None
+ );
+
+ let native_currency: MultiAsset = (
+ MultiLocation::sibling_parachain_general_key(id, NATIVE_CURRENCY.encode()),
+ 1,
+ )
+ .into();
+ assert_eq!(CurrencyIdConvert::convert(native_currency), Some(NATIVE_CURRENCY));
+ }
+
+ #[cfg(feature = "with-karura-runtime")]
+ {
+ assert_eq!(CurrencyIdConvert::convert(ACA), None);
+ assert_eq!(CurrencyIdConvert::convert(AUSD), None);
+ assert_eq!(CurrencyIdConvert::convert(DOT), None);
+ assert_eq!(CurrencyIdConvert::convert(LDOT), None);
+
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, RENBTC.encode())),
+ Some(RENBTC)
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, ACA.encode())),
+ None
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, AUSD.encode())),
+ None
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, DOT.encode())),
+ None
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, LDOT.encode())),
+ None
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(
+ parachains::bifrost::ID,
+ parachains::bifrost::BNC_KEY.to_vec()
+ )),
+ Some(BNC)
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(
+ parachains::bifrost::ID,
+ parachains::bifrost::VSKSM_KEY.to_vec()
+ )),
+ Some(VSKSM)
+ );
+
+ assert_eq!(
+ CurrencyIdConvert::convert(BNC),
+ Some(MultiLocation::sibling_parachain_general_key(
+ parachains::bifrost::ID,
+ parachains::bifrost::BNC_KEY.to_vec()
+ ))
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(VSKSM),
+ Some(MultiLocation::sibling_parachain_general_key(
+ parachains::bifrost::ID,
+ parachains::bifrost::VSKSM_KEY.to_vec()
+ ))
+ );
+
+ let native_currency: MultiAsset = (
+ MultiLocation::sibling_parachain_general_key(id, NATIVE_CURRENCY.encode()),
+ 1,
+ )
+ .into();
+ assert_eq!(CurrencyIdConvert::convert(native_currency), Some(NATIVE_CURRENCY));
+ }
+
+ #[cfg(feature = "with-acala-runtime")]
+ {
+ assert_eq!(CurrencyIdConvert::convert(KAR), None);
+ assert_eq!(CurrencyIdConvert::convert(KUSD), None);
+ assert_eq!(CurrencyIdConvert::convert(KSM), None);
+ assert_eq!(CurrencyIdConvert::convert(LKSM), None);
+
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, RENBTC.encode())),
+ Some(RENBTC)
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, KAR.encode())),
+ None
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, KUSD.encode())),
+ None
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, KSM.encode())),
+ None
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(id, LKSM.encode())),
+ None
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(
+ parachains::bifrost::ID,
+ parachains::bifrost::BNC_KEY.to_vec()
+ )),
+ None
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(MultiLocation::sibling_parachain_general_key(
+ parachains::bifrost::ID,
+ parachains::bifrost::VSKSM_KEY.to_vec()
+ )),
+ None
+ );
+
+ assert_eq!(
+ CurrencyIdConvert::convert(BNC),
+ Some(MultiLocation::sibling_parachain_general_key(
+ parachains::bifrost::ID,
+ parachains::bifrost::BNC_KEY.to_vec()
+ ))
+ );
+ assert_eq!(
+ CurrencyIdConvert::convert(VSKSM),
+ Some(MultiLocation::sibling_parachain_general_key(
+ parachains::bifrost::ID,
+ parachains::bifrost::VSKSM_KEY.to_vec()
+ ))
+ );
+
+ let native_currency: MultiAsset = (
+ MultiLocation::sibling_parachain_general_key(id, NATIVE_CURRENCY.encode()),
+ 1,
+ )
+ .into();
+ assert_eq!(CurrencyIdConvert::convert(native_currency), Some(NATIVE_CURRENCY));
+ }
+ });
+}
+
+#[test]
+fn parachain_subaccounts_are_unique() {
+ ExtBuilder::default().build().execute_with(|| {
+ let parachain: AccountId = ParachainInfo::parachain_id().into_account();
+ assert_eq!(
+ parachain,
+ hex_literal::hex!["70617261d0070000000000000000000000000000000000000000000000000000"].into()
+ );
+
+ assert_eq!(
+ RelayChainSovereignSubAccount::get(),
+ create_x2_parachain_multilocation(0)
+ );
+
+ assert_eq!(
+ create_x2_parachain_multilocation(0),
+ MultiLocation::new(
+ 1,
+ X1(Junction::AccountId32 {
+ network: NetworkId::Any,
+ id: hex_literal::hex!["d7b8926b326dd349355a9a7cca6606c1e0eb6fd2b506066b518c7155ff0d8297"].into(),
+ })
+ ),
+ );
+ assert_eq!(
+ create_x2_parachain_multilocation(1),
+ MultiLocation::new(
+ 1,
+ X1(Junction::AccountId32 {
+ network: NetworkId::Any,
+ id: hex_literal::hex!["74d37d762e06c6841a5dad64463a9afe0684f7e45245f6a7296ca613cca74669"].into(),
+ })
+ ),
+ );
+ });
+}
diff --git a/runtime/integration-tests/src/session_manager.rs b/runtime/integration-tests/src/session_manager.rs
new file mode 100644
index 000000000..77ef55438
--- /dev/null
+++ b/runtime/integration-tests/src/session_manager.rs
@@ -0,0 +1,59 @@
+// 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 frame_support::traits::ValidatorSet;
+
+#[test]
+fn test_session_manager_module() {
+ ExtBuilder::default().build().execute_with(|| {
+ assert_eq!(Session::session_index(), 0);
+ assert_eq!(SessionManager::session_duration(), 10);
+ run_to_block(10);
+ assert_eq!(Session::session_index(), 1);
+ assert_eq!(SessionManager::session_duration(), 10);
+
+ assert_ok!(SessionManager::schedule_session_duration(RawOrigin::Root.into(), 2, 11));
+
+ run_to_block(19);
+ assert_eq!(Session::session_index(), 1);
+ assert_eq!(SessionManager::session_duration(), 10);
+
+ run_to_block(20);
+ assert_eq!(Session::session_index(), 2);
+ assert_eq!(SessionManager::session_duration(), 11);
+
+ run_to_block(31);
+ assert_eq!(Session::session_index(), 3);
+ assert_eq!(SessionManager::session_duration(), 11);
+
+ assert_ok!(SessionManager::schedule_session_duration(RawOrigin::Root.into(), 4, 9));
+
+ run_to_block(42);
+ assert_eq!(Session::session_index(), 4);
+ assert_eq!(SessionManager::session_duration(), 9);
+
+ run_to_block(50);
+ assert_eq!(Session::session_index(), 4);
+ assert_eq!(SessionManager::session_duration(), 9);
+
+ run_to_block(51);
+ assert_eq!(Session::session_index(), 5);
+ assert_eq!(SessionManager::session_duration(), 9);
+ });
+}
diff --git a/runtime/integration-tests/src/setup.rs b/runtime/integration-tests/src/setup.rs
new file mode 100644
index 000000000..afa9988b9
--- /dev/null
+++ b/runtime/integration-tests/src/setup.rs
@@ -0,0 +1,341 @@
+// 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 acala_service::chain_spec::mandala::evm_genesis;
+pub use codec::Encode;
+use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
+use frame_support::traits::{GenesisBuild, OnFinalize, OnInitialize};
+pub use frame_support::{assert_noop, assert_ok, traits::Currency};
+pub use frame_system::RawOrigin;
+
+pub use module_support::{
+ mocks::MockAddressMapping, AddressMapping, CDPTreasury, DEXManager, Price, Rate, Ratio, RiskManager,
+};
+
+pub use orml_traits::{location::RelativeLocations, Change, GetByKey, MultiCurrency};
+
+pub use primitives::currency::*;
+pub use sp_core::H160;
+use sp_io::hashing::keccak_256;
+pub use sp_runtime::{
+ traits::{AccountIdConversion, BadOrigin, BlakeTwo256, Convert, Hash, Zero},
+ DispatchError, DispatchResult, FixedPointNumber, MultiAddress, Perbill, Permill,
+};
+
+pub use xcm::latest::prelude::*;
+
+#[cfg(feature = "with-mandala-runtime")]
+pub use mandala_imports::*;
+#[cfg(feature = "with-mandala-runtime")]
+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,
+ };
+
+ pub use runtime_common::{dollar, ACA, AUSD, DOT, LDOT};
+ pub const NATIVE_CURRENCY: CurrencyId = ACA;
+ pub const LIQUID_CURRENCY: CurrencyId = LDOT;
+ pub const RELAY_CHAIN_CURRENCY: CurrencyId = DOT;
+ pub const USD_CURRENCY: CurrencyId = AUSD;
+ pub const LPTOKEN: CurrencyId = CurrencyId::DexShare(
+ primitives::DexShare::Token(TokenSymbol::AUSD),
+ primitives::DexShare::Token(TokenSymbol::DOT),
+ );
+}
+
+#[cfg(feature = "with-karura-runtime")]
+pub use karura_imports::*;
+#[cfg(feature = "with-karura-runtime")]
+mod karura_imports {
+ pub use frame_support::parameter_types;
+ 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,
+ };
+ pub use primitives::TradingPair;
+ pub use runtime_common::{dollar, KAR, KSM, KUSD, LKSM};
+ pub use sp_runtime::traits::AccountIdConversion;
+
+ parameter_types! {
+ pub EnabledTradingPairs: Vec = vec![
+ TradingPair::from_currency_ids(USD_CURRENCY, NATIVE_CURRENCY).unwrap(),
+ TradingPair::from_currency_ids(USD_CURRENCY, RELAY_CHAIN_CURRENCY).unwrap(),
+ TradingPair::from_currency_ids(USD_CURRENCY, LIQUID_CURRENCY).unwrap(),
+ ];
+ pub TreasuryAccount: AccountId = TreasuryPalletId::get().into_account();
+ }
+
+ pub const NATIVE_CURRENCY: CurrencyId = KAR;
+ pub const LIQUID_CURRENCY: CurrencyId = LKSM;
+ pub const RELAY_CHAIN_CURRENCY: CurrencyId = KSM;
+ pub const USD_CURRENCY: CurrencyId = KUSD;
+ pub const LPTOKEN: CurrencyId = CurrencyId::DexShare(
+ primitives::DexShare::Token(TokenSymbol::KUSD),
+ primitives::DexShare::Token(TokenSymbol::KSM),
+ );
+}
+
+#[cfg(feature = "with-acala-runtime")]
+pub use acala_imports::*;
+#[cfg(feature = "with-acala-runtime")]
+mod acala_imports {
+ pub use acala_runtime::{
+ 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,
+ };
+ pub use frame_support::parameter_types;
+ pub use primitives::TradingPair;
+ pub use runtime_common::{dollar, ACA, AUSD, DOT, LDOT};
+ pub use sp_runtime::traits::AccountIdConversion;
+
+ parameter_types! {
+ pub EnabledTradingPairs: Vec = vec![
+ TradingPair::from_currency_ids(USD_CURRENCY, NATIVE_CURRENCY).unwrap(),
+ TradingPair::from_currency_ids(USD_CURRENCY, RELAY_CHAIN_CURRENCY).unwrap(),
+ TradingPair::from_currency_ids(USD_CURRENCY, LIQUID_CURRENCY).unwrap(),
+ ];
+ pub TreasuryAccount: AccountId = TreasuryPalletId::get().into_account();
+ }
+
+ pub const NATIVE_CURRENCY: CurrencyId = ACA;
+ pub const LIQUID_CURRENCY: CurrencyId = LDOT;
+ pub const RELAY_CHAIN_CURRENCY: CurrencyId = DOT;
+ pub const USD_CURRENCY: CurrencyId = AUSD;
+ pub const LPTOKEN: CurrencyId = CurrencyId::DexShare(
+ primitives::DexShare::Token(TokenSymbol::AUSD),
+ primitives::DexShare::Token(TokenSymbol::DOT),
+ );
+}
+
+const ORACLE1: [u8; 32] = [0u8; 32];
+const ORACLE2: [u8; 32] = [1u8; 32];
+const ORACLE3: [u8; 32] = [2u8; 32];
+const ORACLE4: [u8; 32] = [3u8; 32];
+const ORACLE5: [u8; 32] = [4u8; 32];
+
+pub const ALICE: [u8; 32] = [4u8; 32];
+pub const BOB: [u8; 32] = [5u8; 32];
+pub const CHARLIE: [u8; 32] = [6u8; 32];
+pub const DAVE: [u8; 32] = [7u8; 32];
+
+pub const INIT_TIMESTAMP: u64 = 30_000;
+pub const BLOCK_TIME: u64 = 1000;
+
+pub fn run_to_block(n: u32) {
+ while System::block_number() < n {
+ Scheduler::on_finalize(System::block_number());
+ System::set_block_number(System::block_number() + 1);
+ Timestamp::set_timestamp((System::block_number() as u64 * BLOCK_TIME) + INIT_TIMESTAMP);
+ CdpEngine::on_initialize(System::block_number());
+ Scheduler::on_initialize(System::block_number());
+ Scheduler::on_initialize(System::block_number());
+ Session::on_initialize(System::block_number());
+ SessionManager::on_initialize(System::block_number());
+ }
+}
+
+pub fn set_relaychain_block_number(number: BlockNumber) {
+ ParachainSystem::on_initialize(number);
+
+ let (relay_storage_root, proof) = RelayStateSproofBuilder::default().into_state_root_and_proof();
+
+ assert_ok!(ParachainSystem::set_validation_data(
+ Origin::none(),
+ cumulus_primitives_parachain_inherent::ParachainInherentData {
+ validation_data: cumulus_primitives_core::PersistedValidationData {
+ parent_head: Default::default(),
+ relay_parent_number: number,
+ relay_parent_storage_root: relay_storage_root,
+ max_pov_size: Default::default(),
+ },
+ relay_chain_state: proof,
+ downward_messages: Default::default(),
+ horizontal_messages: Default::default(),
+ }
+ ));
+}
+
+pub struct ExtBuilder {
+ balances: Vec<(AccountId, CurrencyId, Balance)>,
+}
+
+impl Default for ExtBuilder {
+ fn default() -> Self {
+ Self { balances: vec![] }
+ }
+}
+
+impl ExtBuilder {
+ pub fn balances(mut self, balances: Vec<(AccountId, CurrencyId, Balance)>) -> Self {
+ self.balances = balances;
+ self
+ }
+
+ pub fn build(self) -> sp_io::TestExternalities {
+ let evm_genesis_accounts = evm_genesis();
+
+ let mut t = frame_system::GenesisConfig::default()
+ .build_storage::()
+ .unwrap();
+
+ let native_currency_id = GetNativeCurrencyId::get();
+ let existential_deposit = NativeTokenExistentialDeposit::get();
+ let initial_enabled_trading_pairs = EnabledTradingPairs::get();
+
+ module_dex::GenesisConfig:: {
+ initial_enabled_trading_pairs: initial_enabled_trading_pairs,
+ initial_listing_trading_pairs: Default::default(),
+ initial_added_liquidity_pools: vec![],
+ }
+ .assimilate_storage(&mut t)
+ .unwrap();
+
+ pallet_balances::GenesisConfig:: {
+ balances: self
+ .balances
+ .clone()
+ .into_iter()
+ .filter(|(_, currency_id, _)| *currency_id == native_currency_id)
+ .map(|(account_id, _, initial_balance)| (account_id, initial_balance))
+ .chain(
+ get_all_module_accounts()
+ .iter()
+ .map(|x| (x.clone(), existential_deposit)),
+ )
+ .collect::>(),
+ }
+ .assimilate_storage(&mut t)
+ .unwrap();
+
+ orml_tokens::GenesisConfig:: {
+ balances: self
+ .balances
+ .into_iter()
+ .filter(|(_, currency_id, _)| *currency_id != native_currency_id)
+ .collect::>(),
+ }
+ .assimilate_storage(&mut t)
+ .unwrap();
+
+ pallet_membership::GenesisConfig:: {
+ members: vec![
+ AccountId::from(ORACLE1),
+ AccountId::from(ORACLE2),
+ AccountId::from(ORACLE3),
+ AccountId::from(ORACLE4),
+ AccountId::from(ORACLE5),
+ ],
+ phantom: Default::default(),
+ }
+ .assimilate_storage(&mut t)
+ .unwrap();
+
+ module_evm::GenesisConfig:: {
+ accounts: evm_genesis_accounts,
+ treasury: Default::default(),
+ }
+ .assimilate_storage(&mut t)
+ .unwrap();
+
+ module_session_manager::GenesisConfig:: { session_duration: 10 }
+ .assimilate_storage(&mut t)
+ .unwrap();
+
+ >::assimilate_storage(
+ ¶chain_info::GenesisConfig {
+ parachain_id: 2000.into(),
+ },
+ &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 {
+ AcalaOracle::on_finalize(0);
+ assert_ok!(AcalaOracle::feed_values(
+ Origin::signed(AccountId::from(ORACLE1)),
+ prices.clone(),
+ ));
+ assert_ok!(AcalaOracle::feed_values(
+ Origin::signed(AccountId::from(ORACLE2)),
+ prices.clone(),
+ ));
+ assert_ok!(AcalaOracle::feed_values(
+ Origin::signed(AccountId::from(ORACLE3)),
+ prices.clone(),
+ ));
+ assert_ok!(AcalaOracle::feed_values(
+ Origin::signed(AccountId::from(ORACLE4)),
+ prices.clone(),
+ ));
+ assert_ok!(AcalaOracle::feed_values(
+ Origin::signed(AccountId::from(ORACLE5)),
+ prices,
+ ));
+ Ok(())
+}
+
+pub fn alice_key() -> libsecp256k1::SecretKey {
+ libsecp256k1::SecretKey::parse(&keccak_256(b"Alice")).unwrap()
+}
+
+pub fn bob_key() -> libsecp256k1::SecretKey {
+ libsecp256k1::SecretKey::parse(&keccak_256(b"Bob")).unwrap()
+}
+
+pub fn alice() -> AccountId {
+ let address = EvmAccounts::eth_address(&alice_key());
+ let mut data = [0u8; 32];
+ data[0..4].copy_from_slice(b"evm:");
+ data[4..24].copy_from_slice(&address[..]);
+ AccountId::from(Into::<[u8; 32]>::into(data))
+}
+
+pub fn bob() -> AccountId {
+ let address = EvmAccounts::eth_address(&bob_key());
+ let mut data = [0u8; 32];
+ data[0..4].copy_from_slice(b"evm:");
+ data[4..24].copy_from_slice(&address[..]);
+ AccountId::from(Into::<[u8; 32]>::into(data))
+}
diff --git a/runtime/integration-tests/src/treasury.rs b/runtime/integration-tests/src/treasury.rs
new file mode 100644
index 000000000..e2c33acdc
--- /dev/null
+++ b/runtime/integration-tests/src/treasury.rs
@@ -0,0 +1,231 @@
+// 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::*;
+
+#[test]
+fn treasury_should_take_xcm_execution_revenue() {
+ ExtBuilder::default().build().execute_with(|| {
+ let dot_amount = 1000 * dollar(RELAY_CHAIN_CURRENCY);
+ #[cfg(feature = "with-mandala-runtime")]
+ let actual_amount = 9_999_999_760_000;
+ #[cfg(feature = "with-karura-runtime")]
+ let actual_amount = 999_999_952_000_000;
+ #[cfg(feature = "with-acala-runtime")]
+ let actual_amount = 999_999_952_000_000;
+
+ #[cfg(feature = "with-mandala-runtime")]
+ let shallow_weight = 3_000_000;
+ #[cfg(feature = "with-karura-runtime")]
+ let shallow_weight = 600_000_000;
+ #[cfg(feature = "with-acala-runtime")]
+ let shallow_weight = 600_000_000;
+ let origin = MultiLocation::parent();
+
+ // receive relay chain token
+ let asset: MultiAsset = (MultiLocation::parent(), dot_amount).into();
+ let mut msg = Xcm(vec![
+ ReserveAssetDeposited(asset.clone().into()),
+ BuyExecution {
+ fees: asset,
+ weight_limit: Limited(shallow_weight),
+ },
+ DepositAsset {
+ assets: All.into(),
+ max_assets: u32::max_value(),
+ beneficiary: X1(Junction::AccountId32 {
+ network: NetworkId::Any,
+ id: ALICE,
+ })
+ .into(),
+ },
+ ]);
+ use xcm_executor::traits::WeightBounds;
+ let debt = ::Weigher::weight(&mut msg).unwrap_or_default();
+ assert_eq!(debt, shallow_weight);
+
+ assert_eq!(Tokens::free_balance(RELAY_CHAIN_CURRENCY, &ALICE.into()), 0);
+ assert_eq!(Tokens::free_balance(RELAY_CHAIN_CURRENCY, &TreasuryAccount::get()), 0);
+
+ let weight_limit = debt;
+ assert_eq!(
+ XcmExecutor::::execute_xcm(origin, msg, weight_limit),
+ Outcome::Complete(shallow_weight)
+ );
+
+ assert_eq!(Tokens::free_balance(RELAY_CHAIN_CURRENCY, &ALICE.into()), actual_amount);
+ assert_eq!(
+ Tokens::free_balance(RELAY_CHAIN_CURRENCY, &TreasuryAccount::get()),
+ dot_amount - actual_amount
+ );
+ });
+}
+
+#[test]
+fn treasury_handles_dust_correctly() {
+ ExtBuilder::default()
+ .balances(vec![
+ (
+ AccountId::from(BOB),
+ RELAY_CHAIN_CURRENCY,
+ ExistentialDeposits::get(&RELAY_CHAIN_CURRENCY),
+ ),
+ (
+ AccountId::from(ALICE),
+ RELAY_CHAIN_CURRENCY,
+ ExistentialDeposits::get(&RELAY_CHAIN_CURRENCY),
+ ),
+ (
+ AccountId::from(BOB),
+ LIQUID_CURRENCY,
+ ExistentialDeposits::get(&LIQUID_CURRENCY),
+ ),
+ (
+ AccountId::from(ALICE),
+ LIQUID_CURRENCY,
+ ExistentialDeposits::get(&LIQUID_CURRENCY),
+ ),
+ (
+ AccountId::from(BOB),
+ USD_CURRENCY,
+ ExistentialDeposits::get(&USD_CURRENCY),
+ ),
+ (
+ AccountId::from(ALICE),
+ USD_CURRENCY,
+ ExistentialDeposits::get(&USD_CURRENCY),
+ ),
+ ])
+ .build()
+ .execute_with(|| {
+ let relay_ed = ExistentialDeposits::get(&RELAY_CHAIN_CURRENCY);
+ let liquid_ed = ExistentialDeposits::get(&LIQUID_CURRENCY);
+ let usd_ed = ExistentialDeposits::get(&USD_CURRENCY);
+
+ // Test empty treasury recieves dust tokens of relay
+ assert_eq!(
+ Currencies::free_balance(RELAY_CHAIN_CURRENCY, &TreasuryAccount::get()),
+ 0
+ );
+ assert_ok!(Currencies::transfer(
+ Origin::signed(AccountId::from(ALICE)),
+ sp_runtime::MultiAddress::Id(AccountId::from(BOB)),
+ RELAY_CHAIN_CURRENCY,
+ 1
+ ));
+ assert_eq!(
+ Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(BOB)),
+ relay_ed + 1
+ );
+
+ // ALICE account is reaped and treasury recieves dust tokens
+ assert_eq!(
+ Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(ALICE)),
+ 0
+ );
+ // Treasury can have under the existential deposit
+ assert_eq!(
+ Currencies::free_balance(RELAY_CHAIN_CURRENCY, &TreasuryAccount::get()),
+ relay_ed - 1
+ );
+
+ // treasury can send funds when under existential deposit
+ assert_ok!(Currencies::transfer(
+ Origin::signed(TreasuryAccount::get()),
+ sp_runtime::MultiAddress::Id(AccountId::from(BOB)),
+ RELAY_CHAIN_CURRENCY,
+ relay_ed - 2
+ ));
+ assert_eq!(
+ Currencies::free_balance(RELAY_CHAIN_CURRENCY, &TreasuryAccount::get()),
+ 1
+ );
+
+ assert_ok!(Currencies::transfer(
+ Origin::signed(AccountId::from(BOB)),
+ sp_runtime::MultiAddress::Id(AccountId::from(ALICE)),
+ RELAY_CHAIN_CURRENCY,
+ relay_ed
+ ));
+ assert_eq!(
+ Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(ALICE)),
+ relay_ed
+ );
+ assert_eq!(Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(BOB)), 0);
+ assert_eq!(
+ Currencies::free_balance(RELAY_CHAIN_CURRENCY, &TreasuryAccount::get()),
+ relay_ed
+ );
+ assert_ok!(Currencies::transfer(
+ Origin::signed(AccountId::from(ALICE)),
+ sp_runtime::MultiAddress::Id(TreasuryAccount::get()),
+ RELAY_CHAIN_CURRENCY,
+ relay_ed
+ ));
+
+ // Treasury is not reaped when going from over existential deposit to back under it
+ assert_eq!(
+ Currencies::free_balance(RELAY_CHAIN_CURRENCY, &TreasuryAccount::get()),
+ 2 * relay_ed
+ );
+ assert_ok!(Currencies::transfer(
+ Origin::signed(TreasuryAccount::get()),
+ sp_runtime::MultiAddress::Id(AccountId::from(ALICE)),
+ RELAY_CHAIN_CURRENCY,
+ relay_ed + 1
+ ));
+ assert_eq!(
+ Currencies::free_balance(RELAY_CHAIN_CURRENCY, &AccountId::from(ALICE)),
+ relay_ed + 1
+ );
+ assert_eq!(
+ Currencies::free_balance(RELAY_CHAIN_CURRENCY, &TreasuryAccount::get()),
+ relay_ed - 1
+ );
+
+ // Test empty treasury recieves dust tokens of Liquid Currency
+ assert_eq!(Currencies::free_balance(LIQUID_CURRENCY, &TreasuryAccount::get()), 0);
+ assert_ok!(Currencies::transfer(
+ Origin::signed(AccountId::from(ALICE)),
+ sp_runtime::MultiAddress::Id(AccountId::from(BOB)),
+ LIQUID_CURRENCY,
+ 1
+ ));
+ assert_eq!(
+ Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(BOB)),
+ liquid_ed + 1
+ );
+ assert_eq!(Currencies::free_balance(LIQUID_CURRENCY, &AccountId::from(ALICE)), 0);
+ assert_eq!(
+ Currencies::free_balance(LIQUID_CURRENCY, &TreasuryAccount::get()),
+ liquid_ed - 1
+ );
+
+ // Test empty treasury recieves dust tokens of USD Currency using Tokens pallet
+ assert_eq!(Tokens::free_balance(USD_CURRENCY, &TreasuryAccount::get()), 0);
+ assert_ok!(Tokens::transfer(
+ Origin::signed(AccountId::from(ALICE)),
+ sp_runtime::MultiAddress::Id(AccountId::from(BOB)),
+ USD_CURRENCY,
+ 1
+ ));
+ assert_eq!(Tokens::free_balance(USD_CURRENCY, &AccountId::from(BOB)), usd_ed + 1);
+ assert_eq!(Tokens::free_balance(USD_CURRENCY, &AccountId::from(ALICE)), 0);
+ assert_eq!(Tokens::free_balance(USD_CURRENCY, &TreasuryAccount::get()), usd_ed - 1);
+ });
+}
diff --git a/runtime/integration-tests/src/vesting.rs b/runtime/integration-tests/src/vesting.rs
new file mode 100644
index 000000000..e1e92086d
--- /dev/null
+++ b/runtime/integration-tests/src/vesting.rs
@@ -0,0 +1,78 @@
+// 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 orml_vesting::VestingSchedule;
+
+#[test]
+fn test_vesting_use_relaychain_block_number() {
+ ExtBuilder::default().build().execute_with(|| {
+ #[cfg(feature = "with-mandala-runtime")]
+ let signer: AccountId = TreasuryPalletId::get().into_account();
+ #[cfg(feature = "with-karura-runtime")]
+ let signer: AccountId = KaruraFoundationAccounts::get()[0].clone();
+ #[cfg(feature = "with-acala-runtime")]
+ let signer: AccountId = AcalaFoundationAccounts::get()[0].clone();
+
+ assert_ok!(Balances::set_balance(
+ Origin::root(),
+ signer.clone().into(),
+ 1_000 * dollar(ACA),
+ 0
+ ));
+
+ assert_ok!(Vesting::vested_transfer(
+ Origin::signed(signer),
+ alice().into(),
+ VestingSchedule {
+ start: 10,
+ period: 2,
+ period_count: 5,
+ per_period: 3 * dollar(NATIVE_CURRENCY),
+ }
+ ));
+
+ assert_eq!(Balances::free_balance(&alice()), 15 * dollar(NATIVE_CURRENCY));
+ assert_eq!(Balances::usable_balance(&alice()), 0);
+
+ set_relaychain_block_number(10);
+
+ assert_ok!(Vesting::claim(Origin::signed(alice())));
+ assert_eq!(Balances::usable_balance(&alice()), 0);
+
+ set_relaychain_block_number(12);
+
+ assert_ok!(Vesting::claim(Origin::signed(alice())));
+ assert_eq!(Balances::usable_balance(&alice()), 3 * dollar(NATIVE_CURRENCY));
+
+ set_relaychain_block_number(15);
+
+ assert_ok!(Vesting::claim(Origin::signed(alice())));
+ assert_eq!(Balances::usable_balance(&alice()), 6 * dollar(NATIVE_CURRENCY));
+
+ set_relaychain_block_number(20);
+
+ assert_ok!(Vesting::claim(Origin::signed(alice())));
+ assert_eq!(Balances::usable_balance(&alice()), 15 * dollar(NATIVE_CURRENCY));
+
+ set_relaychain_block_number(22);
+
+ assert_ok!(Vesting::claim(Origin::signed(alice())));
+ assert_eq!(Balances::usable_balance(&alice()), 15 * dollar(NATIVE_CURRENCY));
+ });
+}
diff --git a/runtime/integration-tests/src/weights_test.rs b/runtime/integration-tests/src/weights.rs
similarity index 100%
rename from runtime/integration-tests/src/weights_test.rs
rename to runtime/integration-tests/src/weights.rs