From 96148819ce57a9d7e345eeab6350e3079fb63dcf Mon Sep 17 00:00:00 2001 From: cdamian <17934949+cdamian@users.noreply.github.com> Date: Mon, 6 Nov 2023 10:29:18 +0100 Subject: [PATCH] integration-tests: Adapt LP kusama tests to use the generic framework --- runtime/integration-tests/Cargo.toml | 3 + .../src/generic/cases/liquidity_pools.rs | 1285 +++++++++++++++++ .../integration-tests/src/generic/config.rs | 3 + .../src/generic/envs/fudge_env.rs | 3 +- .../src/generic/envs/fudge_env/handle.rs | 78 +- .../integration-tests/src/generic/impls.rs | 62 +- runtime/integration-tests/src/generic/mod.rs | 1 + .../src/liquidity_pools/pallet/kusama/mod.rs | 4 - .../pallet/kusama/restricted_calls.rs | 189 --- .../liquidity_pools/pallet/kusama/setup.rs | 140 -- .../liquidity_pools/pallet/kusama/test_net.rs | 146 -- .../pallet/kusama/tests/asset_registry.rs | 135 -- .../kusama/tests/currency_id_convert.rs | 204 --- .../pallet/kusama/tests/mod.rs | 98 -- .../pallet/kusama/tests/transfers.rs | 621 -------- runtime/integration-tests/src/utils/env.rs | 2 + 16 files changed, 1418 insertions(+), 1556 deletions(-) create mode 100644 runtime/integration-tests/src/generic/cases/liquidity_pools.rs delete mode 100644 runtime/integration-tests/src/liquidity_pools/pallet/kusama/mod.rs delete mode 100644 runtime/integration-tests/src/liquidity_pools/pallet/kusama/restricted_calls.rs delete mode 100644 runtime/integration-tests/src/liquidity_pools/pallet/kusama/setup.rs delete mode 100644 runtime/integration-tests/src/liquidity_pools/pallet/kusama/test_net.rs delete mode 100644 runtime/integration-tests/src/liquidity_pools/pallet/kusama/tests/asset_registry.rs delete mode 100644 runtime/integration-tests/src/liquidity_pools/pallet/kusama/tests/currency_id_convert.rs delete mode 100644 runtime/integration-tests/src/liquidity_pools/pallet/kusama/tests/mod.rs delete mode 100644 runtime/integration-tests/src/liquidity_pools/pallet/kusama/tests/transfers.rs diff --git a/runtime/integration-tests/Cargo.toml b/runtime/integration-tests/Cargo.toml index b0cd202f03..939e064b17 100644 --- a/runtime/integration-tests/Cargo.toml +++ b/runtime/integration-tests/Cargo.toml @@ -26,6 +26,7 @@ pallet-aura = { git = "https://github.com/paritytech/substrate", default-feature pallet-authorship = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" } pallet-babe = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" } pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" } +pallet-beefy = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" } pallet-grandpa = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" } pallet-collective = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" } pallet-democracy = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" } @@ -44,6 +45,7 @@ fp-self-contained = { git = "https://github.com/moonbeam-foundation/frontier", b sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" } sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" } sp-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" } +sp-consensus-beefy = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" } sp-consensus-slots = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" } sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" } @@ -162,6 +164,7 @@ std = [ "orml-xtokens/std", "pallet-aura/std", "pallet-balances/std", + "pallet-beefy/std", "pallet-foreign-investments/std", "pallet-investments/std", "pallet-order-book/std", diff --git a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs new file mode 100644 index 0000000000..c8f0bcb92a --- /dev/null +++ b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs @@ -0,0 +1,1285 @@ +use cfg_primitives::{currency_decimals, parachains, AccountId, Balance}; +use cfg_types::{ + tokens::{CrossChainTransferability, CurrencyId, CustomMetadata}, + xcm::XcmMetadata, +}; +use cfg_utils::vec_to_fixed_array; +use codec::Encode; +use frame_support::{assert_noop, assert_ok, dispatch::RawOrigin, traits::OriginTrait}; +use orml_traits::{asset_registry::AssetMetadata, MultiCurrency}; +use polkadot_parachain::primitives::Id; +use runtime_common::{ + xcm::general_key, + xcm_fees::{default_per_second, ksm_per_second}, +}; +use sp_runtime::{ + traits::{AccountIdConversion, BadOrigin, ConstU32, Convert as C2}, + WeakBoundedVec, +}; +use xcm::{ + prelude::XCM_VERSION, + v3::{ + AssetId, Fungibility, Instruction::WithdrawAsset, Junction, Junction::*, Junctions, + Junctions::*, MultiAsset, MultiAssets, MultiLocation, NetworkId, WeightLimit, Xcm, + }, + VersionedMultiAsset, VersionedMultiAssets, VersionedMultiLocation, +}; +use xcm_executor::traits::Convert as C1; + +use crate::{ + generic::{ + config::Runtime, + env::{Blocks, Env}, + envs::fudge_env::{handle::FudgeHandle, FudgeEnv, FudgeSupport}, + utils::{genesis, genesis::Genesis}, + }, + utils::{accounts::Keyring, AUSD_CURRENCY_ID}, +}; + +mod utils { + use super::*; + + pub(crate) fn parachain_account(id: u32) -> AccountId { + polkadot_parachain::primitives::Sibling::from(id).into_account_truncating() + } +} + +type FudgeRelayRuntime = <::FudgeHandle as FudgeHandle>::RelayRuntime; + +use utils::*; + +mod altair { + use altair_runtime::{CurrencyIdConvert, PoolPalletIndex}; + + pub const KSM_ASSET_ID: CurrencyId = CurrencyId::ForeignAsset(1000); + + use super::*; + + mod utils { + use super::*; + + pub fn setup_xcm(env: &mut FudgeEnv) { + env.parachain_state_mut(|| { + // Set the XCM version used when sending XCM messages to sibling. + assert_ok!(pallet_xcm::Pallet::::force_xcm_version( + ::RuntimeOrigin::root(), + Box::new(MultiLocation::new( + 1, + Junctions::X1(Junction::Parachain(T::FudgeHandle::SIBLING_ID)), + )), + XCM_VERSION, + )); + }); + + env.sibling_state_mut(|| { + // Set the XCM version used when sending XCM messages to sibling. + assert_ok!(pallet_xcm::Pallet::::force_xcm_version( + ::RuntimeOrigin::root(), + Box::new(MultiLocation::new( + 1, + Junctions::X1(Junction::Parachain(T::FudgeHandle::PARA_ID)), + )), + XCM_VERSION, + )); + }); + + env.relay_state_mut(|| { + assert_ok!(polkadot_runtime_parachains::hrmp::Pallet::< + FudgeRelayRuntime, + >::force_open_hrmp_channel( + as frame_system::Config>::RuntimeOrigin::root(), + Id::from(T::FudgeHandle::PARA_ID), + Id::from(T::FudgeHandle::SIBLING_ID), + 10, + 1024, + )); + + assert_ok!(polkadot_runtime_parachains::hrmp::Pallet::< + FudgeRelayRuntime, + >::force_open_hrmp_channel( + as frame_system::Config>::RuntimeOrigin::root(), + Id::from(T::FudgeHandle::SIBLING_ID), + Id::from(T::FudgeHandle::PARA_ID), + 10, + 1024, + )); + + assert_ok!(polkadot_runtime_parachains::hrmp::Pallet::< + FudgeRelayRuntime, + >::force_process_hrmp_open( + as frame_system::Config>::RuntimeOrigin::root(), + 0, + )); + }); + + env.pass(Blocks::ByNumber(1)); + } + + pub fn register_ausd() { + let meta: AssetMetadata = AssetMetadata { + decimals: 12, + name: "Acala Dollar".into(), + symbol: "AUSD".into(), + existential_deposit: 1_000_000_000, + location: Some(VersionedMultiLocation::V3(MultiLocation::new( + 1, + X2( + Parachain(T::FudgeHandle::SIBLING_ID), + general_key(parachains::kusama::karura::AUSD_KEY), + ), + ))), + additional: CustomMetadata { + transferability: CrossChainTransferability::Xcm(Default::default()), + ..CustomMetadata::default() + }, + }; + + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + meta, + Some(AUSD_CURRENCY_ID) + )); + } + + pub fn register_air() { + let meta: AssetMetadata = AssetMetadata { + decimals: 18, + name: "Altair".into(), + symbol: "AIR".into(), + existential_deposit: 1_000_000_000_000, + location: Some(VersionedMultiLocation::V3(MultiLocation::new( + 1, + X2( + Parachain(parachains::kusama::altair::ID), + general_key(parachains::kusama::altair::AIR_KEY), + ), + ))), + additional: CustomMetadata { + transferability: CrossChainTransferability::Xcm(Default::default()), + ..CustomMetadata::default() + }, + }; + + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + meta, + Some(CurrencyId::Native) + )); + } + + pub fn register_ksm() { + let meta: AssetMetadata = AssetMetadata { + decimals: 12, + name: "Kusama".into(), + symbol: "KSM".into(), + existential_deposit: 1_000_000_000, + location: Some(VersionedMultiLocation::V3(MultiLocation::new(1, Here))), + additional: CustomMetadata { + transferability: CrossChainTransferability::Xcm(Default::default()), + ..CustomMetadata::default() + }, + }; + + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + meta, + Some(KSM_ASSET_ID) + )); + } + + pub fn air(amount: Balance) -> Balance { + amount * dollar(currency_decimals::NATIVE) + } + + pub fn ausd(amount: Balance) -> Balance { + amount * dollar(currency_decimals::AUSD) + } + + pub fn ksm(amount: Balance) -> Balance { + amount * dollar(currency_decimals::KSM) + } + + pub fn foreign(amount: Balance, decimals: u32) -> Balance { + amount * dollar(decimals) + } + + pub fn dollar(decimals: u32) -> Balance { + 10u128.saturating_pow(decimals) + } + + pub fn air_fee() -> Balance { + fee(currency_decimals::NATIVE) + } + + pub fn ausd_fee() -> Balance { + fee(currency_decimals::AUSD) + } + + pub fn fee(decimals: u32) -> Balance { + calc_fee(default_per_second(decimals)) + } + + // The fee associated with transferring KSM tokens + pub fn ksm_fee() -> Balance { + calc_fee(ksm_per_second()) + } + + pub fn calc_fee(fee_per_second: Balance) -> Balance { + // We divide the fee to align its unit and multiply by 4 as that seems to be the + // unit of time the tests take. + // NOTE: it is possible that in different machines this value may differ. We + // shall see. + fee_per_second.div_euclid(10_000) * 8 + } + + pub fn xcm_metadata(transferability: CrossChainTransferability) -> Option { + match transferability { + CrossChainTransferability::Xcm(x) | CrossChainTransferability::All(x) => Some(x), + _ => None, + } + } + } + + use utils::*; + + mod restricted_calls { + use super::*; + + fn xtokens_transfer() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + env.parachain_state_mut(|| { + assert_noop!( + orml_xtokens::Pallet::::transfer( + RawOrigin::Signed(Keyring::Alice.into()).into(), + CurrencyId::Tranche(401, [0; 16]), + 42, + Box::new( + MultiLocation::new( + 1, + X2( + Parachain(T::FudgeHandle::SIBLING_ID), + Junction::AccountId32 { + network: None, + id: Keyring::Bob.into(), + } + ) + ) + .into() + ), + WeightLimit::Limited(8_000_000_000_000.into()), + ), + orml_xtokens::Error::::NotCrossChainTransferableCurrency + ); + }); + } + + fn xtokens_transfer_multiasset() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + let tranche_currency = CurrencyId::Tranche(401, [0; 16]); + let tranche_id = + WeakBoundedVec::>::force_from(tranche_currency.encode(), None); + let tranche_location = MultiLocation { + parents: 1, + interior: X3( + Parachain(123), + PalletInstance(42), + GeneralKey { + length: tranche_id.len() as u8, + data: vec_to_fixed_array(tranche_id.to_vec()), + }, + ), + }; + let tranche_multi_asset = VersionedMultiAsset::from(MultiAsset::from(( + AssetId::Concrete(tranche_location), + Fungibility::Fungible(42), + ))); + + env.parachain_state_mut(|| { + assert_noop!( + orml_xtokens::Pallet::::transfer_multiasset( + RawOrigin::Signed(Keyring::Alice.into()).into(), + Box::new(tranche_multi_asset), + Box::new( + MultiLocation::new( + 1, + X2( + Parachain(T::FudgeHandle::SIBLING_ID), + Junction::AccountId32 { + network: None, + id: Keyring::Bob.into(), + } + ) + ) + .into() + ), + WeightLimit::Limited(8_000_000_000_000.into()), + ), + orml_xtokens::Error::::XcmExecutionFailed + ); + }); + } + + fn xtokens_transfer_multiassets() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + let tranche_currency = CurrencyId::Tranche(401, [0; 16]); + let tranche_id = + WeakBoundedVec::>::force_from(tranche_currency.encode(), None); + let tranche_location = MultiLocation { + parents: 1, + interior: X3( + Parachain(123), + PalletInstance(42), + GeneralKey { + length: tranche_id.len() as u8, + data: vec_to_fixed_array(tranche_id.to_vec()), + }, + ), + }; + let tranche_multi_asset = MultiAsset::from(( + AssetId::Concrete(tranche_location), + Fungibility::Fungible(42), + )); + + env.parachain_state_mut(|| { + assert_noop!( + orml_xtokens::Pallet::::transfer_multiassets( + RawOrigin::Signed(Keyring::Alice.into()).into(), + Box::new(VersionedMultiAssets::from(MultiAssets::from(vec![ + tranche_multi_asset + ]))), + 0, + Box::new( + MultiLocation::new( + 1, + X2( + Parachain(T::FudgeHandle::SIBLING_ID), + Junction::AccountId32 { + network: None, + id: Keyring::Bob.into(), + } + ) + ) + .into() + ), + WeightLimit::Limited(8_000_000_000_000.into()), + ), + orml_xtokens::Error::::XcmExecutionFailed + ); + }); + } + + crate::test_for_runtimes!([altair], xtokens_transfer); + crate::test_for_runtimes!([altair], xtokens_transfer_multiasset); + crate::test_for_runtimes!([altair], xtokens_transfer_multiassets); + } + + mod transfers { + use super::*; + + fn transfer_air_to_sibling(env: &mut FudgeEnv) { + let alice_initial_balance = air(10); + let bob_initial_balance = air(10); + let transfer_amount = air(5); + let air_in_sibling = CurrencyId::ForeignAsset(12); + + env.parachain_state_mut(|| { + assert_eq!( + pallet_balances::Pallet::::free_balance(&Keyring::Alice.into()), + alice_initial_balance + ); + assert_eq!( + pallet_balances::Pallet::::free_balance(¶chain_account( + T::FudgeHandle::SIBLING_ID + )), + 0 + ); + + // Register AIR as foreign asset in the sibling parachain + let meta: AssetMetadata = AssetMetadata { + decimals: 18, + name: "Altair".into(), + symbol: "AIR".into(), + existential_deposit: 1_000_000_000_000, + location: Some(VersionedMultiLocation::V3(MultiLocation::new( + 1, + X2( + Parachain(T::FudgeHandle::PARA_ID), + general_key(parachains::kusama::altair::AIR_KEY), + ), + ))), + additional: CustomMetadata { + transferability: CrossChainTransferability::Xcm(Default::default()), + ..CustomMetadata::default() + }, + }; + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + meta, + Some(CurrencyId::Native) + )); + }); + + env.sibling_state_mut(|| { + assert_eq!( + orml_tokens::Pallet::::free_balance(air_in_sibling, &Keyring::Bob.into()), + 0 + ); + + // Register AIR as foreign asset in the sibling parachain + let meta: AssetMetadata = AssetMetadata { + decimals: 18, + name: "Altair".into(), + symbol: "AIR".into(), + existential_deposit: 1_000_000_000_000, + location: Some(VersionedMultiLocation::V3(MultiLocation::new( + 1, + X2( + Parachain(T::FudgeHandle::PARA_ID), + general_key(parachains::kusama::altair::AIR_KEY), + ), + ))), + additional: CustomMetadata { + transferability: CrossChainTransferability::Xcm(Default::default()), + ..CustomMetadata::default() + }, + }; + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + meta, + Some(air_in_sibling) + )); + }); + + env.pass(Blocks::ByNumber(1)); + + env.parachain_state_mut(|| { + assert_ok!(orml_xtokens::Pallet::::transfer( + RawOrigin::Signed(Keyring::Alice.into()).into(), + CurrencyId::Native, + transfer_amount, + Box::new( + MultiLocation::new( + 1, + X2( + Parachain(T::FudgeHandle::SIBLING_ID), + Junction::AccountId32 { + network: None, + id: Keyring::Bob.into(), + } + ) + ) + .into() + ), + WeightLimit::Limited(8_000_000_000_000.into()), + )); + + // Confirm that Alice's balance is initial balance - amount transferred + assert_eq!( + pallet_balances::Pallet::::free_balance(&Keyring::Alice.into()), + alice_initial_balance - transfer_amount + ); + + // Verify that the amount transferred is now part of the sibling account here + assert_eq!( + pallet_balances::Pallet::::free_balance(¶chain_account( + T::FudgeHandle::SIBLING_ID + )), + transfer_amount + ); + }); + + env.pass(Blocks::ByNumber(1)); + + env.sibling_state_mut(|| { + let current_balance = + orml_tokens::Pallet::::free_balance(air_in_sibling, &Keyring::Bob.into()); + + // Verify that Keyring::Bob now has (amount transferred - fee) + assert_eq!(current_balance, transfer_amount - fee(18)); + + // Sanity check for the actual amount Keyring::Bob ends up with + assert_eq!(current_balance, 4992960800000000000); + }); + } + + fn test_air_transfers_to_and_from_sibling() { + let mut env = FudgeEnv::::from_storage( + Genesis::default() + .add(genesis::balances::(air(10))) + .storage(), + Default::default(), + ); + + setup_xcm(&mut env); + + // In order to be able to transfer AIR from Sibling to Altair, we need to first + // send AIR from Altair to Sibling, or else it fails since it'd be like Sibling + // had minted AIR on their side. + transfer_air_to_sibling(&mut env); + + let alice_initial_balance = air(5); + let bob_initial_balance = air(5) - air_fee(); + let transfer_amount = air(1); + + // Note: This asset was registered in `transfer_air_to_sibling` + let air_in_sibling = CurrencyId::ForeignAsset(12); + + env.parachain_state_mut(|| { + assert_eq!( + pallet_balances::Pallet::::free_balance(&Keyring::Alice.into()), + alice_initial_balance + ); + }); + + env.sibling_state_mut(|| { + assert_eq!( + pallet_balances::Pallet::::free_balance(¶chain_account( + T::FudgeHandle::PARA_ID + )), + 0 + ); + assert_eq!( + orml_tokens::Pallet::::free_balance(air_in_sibling, &Keyring::Bob.into()), + bob_initial_balance + ); + + assert_ok!(orml_xtokens::Pallet::::transfer( + RawOrigin::Signed(Keyring::Bob.into()).into(), + air_in_sibling, + transfer_amount, + Box::new( + MultiLocation::new( + 1, + X2( + Parachain(T::FudgeHandle::PARA_ID), + Junction::AccountId32 { + network: None, + id: Keyring::Alice.into(), + } + ) + ) + .into() + ), + WeightLimit::Limited(8_000_000_000_000.into()), + )); + + // Confirm that Bobs's balance is initial balance - amount transferred + assert_eq!( + orml_tokens::Pallet::::free_balance(air_in_sibling, &Keyring::Bob.into()), + bob_initial_balance - transfer_amount + ); + }); + + env.pass(Blocks::ByNumber(2)); + + env.parachain_state_mut(|| { + // Verify that Keyring::Alice now has initial balance + amount transferred - fee + assert_eq!( + pallet_balances::Pallet::::free_balance(&Keyring::Alice.into()), + alice_initial_balance + transfer_amount - air_fee(), + ); + }); + } + + fn transfer_ausd_to_altair() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + setup_xcm(&mut env); + + let alice_initial_balance = ausd(10); + let transfer_amount = ausd(7); + + env.sibling_state_mut(|| { + register_ausd::(); + + assert_ok!(orml_tokens::Pallet::::deposit( + AUSD_CURRENCY_ID, + &Keyring::Alice.into(), + alice_initial_balance + )); + + assert_eq!( + orml_tokens::Pallet::::free_balance( + AUSD_CURRENCY_ID, + ¶chain_account(T::FudgeHandle::PARA_ID) + ), + 0 + ); + }); + + env.parachain_state_mut(|| { + register_ausd::(); + + assert_eq!( + orml_tokens::Pallet::::free_balance(AUSD_CURRENCY_ID, &Keyring::Bob.into()), + 0, + ); + }); + + env.sibling_state_mut(|| { + assert_eq!( + orml_tokens::Pallet::::free_balance( + AUSD_CURRENCY_ID, + &Keyring::Alice.into() + ), + ausd(10), + ); + assert_ok!(orml_xtokens::Pallet::::transfer( + RawOrigin::Signed(Keyring::Alice.into()).into(), + AUSD_CURRENCY_ID, + transfer_amount, + Box::new( + MultiLocation::new( + 1, + X2( + Parachain(T::FudgeHandle::PARA_ID), + Junction::AccountId32 { + network: None, + id: Keyring::Bob.into(), + } + ) + ) + .into() + ), + WeightLimit::Limited(8_000_000_000_000.into()), + )); + + assert_eq!( + orml_tokens::Pallet::::free_balance( + AUSD_CURRENCY_ID, + &Keyring::Alice.into() + ), + alice_initial_balance - transfer_amount + ); + + // Verify that the amount transferred is now part of the altair parachain + // account here + assert_eq!( + orml_tokens::Pallet::::free_balance( + AUSD_CURRENCY_ID, + ¶chain_account(T::FudgeHandle::PARA_ID) + ), + transfer_amount + ); + }); + + env.pass(Blocks::ByNumber(2)); + + env.parachain_state_mut(|| { + // Verify that Keyring::Bob now has initial balance + amount transferred - fee + assert_eq!( + orml_tokens::Pallet::::free_balance(AUSD_CURRENCY_ID, &Keyring::Bob.into()), + transfer_amount - ausd_fee() + ); + }); + } + + fn transfer_ksm_from_relay_chain( + env: &mut FudgeEnv, + transfer_amount: Balance, + currency_id: CurrencyId, + meta: AssetMetadata, + ) { + env.parachain_state_mut(|| { + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + meta.clone(), + Some(currency_id), + )); + + assert_eq!( + orml_tokens::Pallet::::free_balance(currency_id, &Keyring::Bob.into()), + 0 + ); + }); + + env.relay_state_mut(|| { + assert_ok!( + pallet_balances::Pallet::>::force_set_balance( + as frame_system::Config>::RuntimeOrigin::root(), + Keyring::Alice.to_account_id().into(), + transfer_amount * 2, + ) + ); + + assert_ok!( + pallet_xcm::Pallet::>::force_xcm_version( + as frame_system::Config>::RuntimeOrigin::root(), + Box::new(MultiLocation::new( + 0, + Junctions::X1(Junction::Parachain(T::FudgeHandle::PARA_ID)), + )), + XCM_VERSION, + ) + ); + + assert_ok!( + pallet_xcm::Pallet::>::reserve_transfer_assets( + RawOrigin::Signed(Keyring::Alice.into()).into(), + Box::new(Parachain(T::FudgeHandle::PARA_ID).into()), + Box::new( + Junction::AccountId32 { + network: None, + id: Keyring::Bob.into(), + } + .into() + ), + Box::new((Here, transfer_amount).into()), + 0 + ) + ); + }); + + env.pass(Blocks::ByNumber(1)); + + env.parachain_state(|| { + assert_eq!( + orml_tokens::Pallet::::free_balance(currency_id, &Keyring::Bob.into()), + transfer_amount - fee(meta.decimals) + ); + + assert_eq!( + orml_tokens::Pallet::::free_balance(currency_id, &Keyring::Bob.into()), + transfer_amount - fee(meta.decimals) + ); + }); + } + + fn transfer_ksm_to_and_from_relay_chain() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + let transfer_amount: Balance = ksm(2); + let currency_id = CurrencyId::ForeignAsset(3001); + let meta: AssetMetadata = AssetMetadata { + decimals: 12, + name: "Kusama".into(), + symbol: "KSM".into(), + existential_deposit: 1_000_000_000, + location: Some(VersionedMultiLocation::V3(MultiLocation::new(1, Here))), + additional: CustomMetadata { + transferability: CrossChainTransferability::Xcm(Default::default()), + ..CustomMetadata::default() + }, + }; + + // First we need some KSM on Altair + transfer_ksm_from_relay_chain(&mut env, transfer_amount, currency_id, meta.clone()); + + let currency_id = CurrencyId::ForeignAsset(3001); + + env.parachain_state_mut(|| { + assert_eq!( + orml_tokens::Pallet::::free_balance(currency_id, &Keyring::Bob.into()), + transfer_amount - fee(meta.decimals) + ); + + assert_ok!(pallet_xcm::Pallet::::force_xcm_version( + ::RuntimeOrigin::root(), + Box::new(MultiLocation::new(1, Junctions::Here)), + XCM_VERSION, + )); + + assert_ok!(orml_xtokens::Pallet::::transfer( + RawOrigin::Signed(Keyring::Bob.into()).into(), + currency_id, + ksm(1), + Box::new( + MultiLocation::new( + 1, + X1(Junction::AccountId32 { + id: Keyring::Bob.into(), + network: None, + }) + ) + .into() + ), + WeightLimit::Limited(4_000_000_000.into()) + )); + }); + + env.pass(Blocks::ByNumber(1)); + + env.relay_state_mut(|| { + assert_eq!( + pallet_balances::Pallet::>::free_balance( + &Keyring::Bob.into() + ), + 999907996044 + ); + }); + } + + fn transfer_foreign_sibling_to_altair() { + let mut env = FudgeEnv::::from_storage( + Genesis::default() + .add(genesis::balances::(air(10))) + .storage(), + Default::default(), + ); + + setup_xcm(&mut env); + + let alice_initial_balance = air(10); + let sibling_asset_id = CurrencyId::ForeignAsset(1); + let asset_location = MultiLocation::new( + 1, + X2(Parachain(T::FudgeHandle::SIBLING_ID), general_key(&[0, 1])), + ); + let meta: AssetMetadata = AssetMetadata { + decimals: 18, + name: "Sibling Native Token".into(), + symbol: "SBLNG".into(), + existential_deposit: 1_000_000_000_000, + location: Some(VersionedMultiLocation::V3(asset_location)), + additional: CustomMetadata { + transferability: CrossChainTransferability::Xcm(XcmMetadata { + // We specify a custom fee_per_second and verify below that this value is + // used when XCM transfer fees are charged for this token. + fee_per_second: Some(8420000000000000000), + }), + ..CustomMetadata::default() + }, + }; + let transfer_amount = foreign(1, meta.decimals); + + env.sibling_state_mut(|| { + assert_eq!( + orml_tokens::Pallet::::free_balance(sibling_asset_id, &Keyring::Bob.into()), + 0 + ); + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + meta.clone(), + Some(CurrencyId::Native), + )); + }); + + env.parachain_state_mut(|| { + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + meta.clone(), + Some(sibling_asset_id) + )); + }); + + env.sibling_state_mut(|| { + assert_ok!(pallet_balances::Pallet::::force_set_balance( + ::RuntimeOrigin::root(), + Keyring::Alice.to_account_id().into(), + transfer_amount * 2, + )); + + assert_ok!(orml_xtokens::Pallet::::transfer( + RawOrigin::Signed(Keyring::Alice.into()).into(), + CurrencyId::Native, + transfer_amount, + Box::new( + MultiLocation::new( + 1, + X2( + Parachain(T::FudgeHandle::PARA_ID), + Junction::AccountId32 { + network: None, + id: Keyring::Bob.into(), + } + ) + ) + .into() + ), + WeightLimit::Limited(8_000_000_000_000.into()), + )); + + // Confirm that Alice's balance is initial balance - amount transferred + assert_eq!( + pallet_balances::Pallet::::free_balance(&Keyring::Alice.into()), + transfer_amount + ); + }); + + env.pass(Blocks::ByNumber(2)); + + env.parachain_state_mut(|| { + let bob_balance = + orml_tokens::Pallet::::free_balance(sibling_asset_id, &Keyring::Bob.into()); + + // Verify that Keyring::Bob now has initial balance + amount transferred - fee + assert_eq!( + bob_balance, + transfer_amount + - calc_fee( + xcm_metadata(meta.additional.transferability) + .unwrap() + .fee_per_second + .unwrap() + ) + ); + // Sanity check to ensure the calculated is what is expected + assert_eq!(bob_balance, 993264000000000000); + }); + } + + fn transfer_wormhole_usdc_karura_to_altair() { + let mut env = FudgeEnv::::from_storage( + Default::default(), + Genesis::default() + .add(genesis::balances::(air(10))) + .storage(), + ); + + setup_xcm(&mut env); + + let usdc_asset_id = CurrencyId::ForeignAsset(39); + let asset_location = MultiLocation::new( + 1, + X2( + Parachain(T::FudgeHandle::SIBLING_ID), + general_key("0x02f3a00dd12f644daec907013b16eb6d14bf1c4cb4".as_bytes()), + ), + ); + let meta: AssetMetadata = AssetMetadata { + decimals: 6, + name: "Wormhole USDC".into(), + symbol: "WUSDC".into(), + existential_deposit: 1, + location: Some(VersionedMultiLocation::V3(asset_location)), + additional: CustomMetadata { + transferability: CrossChainTransferability::Xcm(Default::default()), + ..CustomMetadata::default() + }, + }; + let transfer_amount = foreign(12, meta.decimals); + let alice_initial_balance = transfer_amount * 100; + + env.sibling_state_mut(|| { + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + meta.clone(), + Some(usdc_asset_id) + )); + assert_ok!(orml_tokens::Pallet::::deposit( + usdc_asset_id, + &Keyring::Alice.into(), + alice_initial_balance + )); + assert_eq!( + orml_tokens::Pallet::::free_balance(usdc_asset_id, &Keyring::Alice.into()), + alice_initial_balance + ); + assert_eq!( + pallet_balances::Pallet::::free_balance(&Keyring::Alice.into()), + air(10) + ); + }); + + env.parachain_state_mut(|| { + // First, register the asset in centrifuge + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + meta.clone(), + Some(usdc_asset_id) + )); + }); + + env.sibling_state_mut(|| { + assert_ok!(orml_xtokens::Pallet::::transfer( + RawOrigin::Signed(Keyring::Alice.into()).into(), + usdc_asset_id, + transfer_amount, + Box::new( + MultiLocation::new( + 1, + X2( + Parachain(T::FudgeHandle::PARA_ID), + Junction::AccountId32 { + network: None, + id: Keyring::Bob.into(), + } + ) + ) + .into() + ), + WeightLimit::Limited(8_000_000_000.into()), + )); + + // Confirm that Alice's balance is initial balance - amount transferred + assert_eq!( + orml_tokens::Pallet::::free_balance(usdc_asset_id, &Keyring::Alice.into()), + alice_initial_balance - transfer_amount + ); + }); + + env.pass(Blocks::ByNumber(2)); + + env.parachain_state_mut(|| { + let bob_balance = + orml_tokens::Pallet::::free_balance(usdc_asset_id, &Keyring::Bob.into()); + + // Sanity check to ensure the calculated is what is expected + assert_eq!(bob_balance, 11992961); + }); + } + + crate::test_for_runtimes!([altair], test_air_transfers_to_and_from_sibling); + crate::test_for_runtimes!([altair], transfer_ausd_to_altair); + crate::test_for_runtimes!([altair], transfer_ksm_to_and_from_relay_chain); + crate::test_for_runtimes!([altair], transfer_foreign_sibling_to_altair); + crate::test_for_runtimes!([altair], transfer_wormhole_usdc_karura_to_altair); + } + + mod asset_registry { + use super::*; + + fn register_air_works() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + env.parachain_state_mut(|| { + let meta: AssetMetadata = AssetMetadata { + decimals: 18, + name: "Altair".into(), + symbol: "AIR".into(), + existential_deposit: 1_000_000_000_000, + location: Some(VersionedMultiLocation::V3(MultiLocation::new( + 0, + X1(general_key(parachains::kusama::altair::AIR_KEY)), + ))), + additional: CustomMetadata { + transferability: CrossChainTransferability::Xcm(Default::default()), + ..CustomMetadata::default() + }, + }; + + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + meta, + Some(CurrencyId::Native) + )); + }); + } + + fn register_foreign_asset_works() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + env.parachain_state_mut(|| { + let meta: AssetMetadata = AssetMetadata { + decimals: 12, + name: "Acala Dollar".into(), + symbol: "AUSD".into(), + existential_deposit: 1_000_000_000_000, + location: Some(VersionedMultiLocation::V3(MultiLocation::new( + 1, + X2( + Parachain(T::FudgeHandle::SIBLING_ID), + general_key(parachains::kusama::karura::AUSD_KEY), + ), + ))), + additional: CustomMetadata { + transferability: CrossChainTransferability::Xcm(Default::default()), + ..CustomMetadata::default() + }, + }; + + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + meta, + Some(CurrencyId::ForeignAsset(42)) + )); + }); + } + + // Verify that registering tranche tokens is not allowed through extrinsics + fn register_tranche_asset_blocked() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + env.parachain_state_mut(|| { + let meta: AssetMetadata = AssetMetadata { + decimals: 12, + name: "Tranche Token 1".into(), + symbol: "TRNCH".into(), + existential_deposit: 1_000_000_000_000, + location: Some(VersionedMultiLocation::V3(MultiLocation::new( + 1, + X2(Parachain(2000), general_key(&[42])), + ))), + additional: CustomMetadata { + transferability: CrossChainTransferability::Xcm(Default::default()), + ..CustomMetadata::default() + }, + }; + + // It fails with `BadOrigin` even when submitted with `Origin::root` since we + // only allow for tranche tokens to be registered through the pools pallet. + let asset_id = CurrencyId::Tranche(42, [42u8; 16]); + assert_noop!( + orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + meta, + Some(asset_id) + ), + BadOrigin + ); + }); + } + + crate::test_for_runtimes!([altair], register_air_works); + crate::test_for_runtimes!([altair], register_foreign_asset_works); + crate::test_for_runtimes!([altair], register_tranche_asset_blocked); + } + + mod currency_id_convert { + use super::*; + + fn convert_air() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + assert_eq!(parachains::kusama::altair::AIR_KEY.to_vec(), vec![0, 1]); + + env.parachain_state_mut(|| { + // The way AIR is represented relative within the Altair runtime + let air_location_inner: MultiLocation = + MultiLocation::new(0, X1(general_key(parachains::kusama::altair::AIR_KEY))); + + // register air + register_air::(); + + assert_eq!( + >::convert(air_location_inner), + Ok(CurrencyId::Native), + ); + + // The canonical way AIR is represented out in the wild + let air_location_canonical: MultiLocation = MultiLocation::new( + 1, + X2( + Parachain(T::FudgeHandle::PARA_ID), + general_key(parachains::kusama::altair::AIR_KEY), + ), + ); + + assert_eq!( + >::convert(CurrencyId::Native), + Some(air_location_canonical) + ) + }); + } + + /// Verify that Tranche tokens are not handled by the CurrencyIdConvert + /// since we don't allow Tranche tokens to be transferable through XCM. + fn convert_tranche() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + let tranche_currency = CurrencyId::Tranche(401, [0; 16]); + let tranche_id = + WeakBoundedVec::>::force_from(tranche_currency.encode(), None); + let tranche_multilocation = MultiLocation { + parents: 1, + interior: X3( + Parachain(T::FudgeHandle::PARA_ID), + PalletInstance(PoolPalletIndex::get()), + GeneralKey { + length: tranche_id.len() as u8, + data: vec_to_fixed_array(tranche_id.to_vec()), + }, + ), + }; + + env.parachain_state_mut(|| { + assert_eq!( + >::convert(tranche_multilocation), + Err(tranche_multilocation), + ); + }); + + env.parachain_state_mut(|| { + assert_eq!( + >::convert(tranche_currency), + None + ) + }); + } + + fn convert_ausd() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + env.parachain_state_mut(|| { + assert_eq!(parachains::kusama::karura::AUSD_KEY, &[0, 129]); + + let ausd_location: MultiLocation = MultiLocation::new( + 1, + X2( + Parachain(T::FudgeHandle::SIBLING_ID), + general_key(parachains::kusama::karura::AUSD_KEY), + ), + ); + + register_ausd::(); + + assert_eq!( + >::convert(ausd_location.clone()), + Ok(AUSD_CURRENCY_ID), + ); + + assert_eq!( + >::convert(AUSD_CURRENCY_ID), + Some(ausd_location) + ) + }); + } + + fn convert_ksm() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + let ksm_location: MultiLocation = MultiLocation::parent().into(); + + env.parachain_state_mut(|| { + register_ksm::(); + + assert_eq!( + >::convert(ksm_location), + Ok(KSM_ASSET_ID), + ); + + assert_eq!( + >::convert(KSM_ASSET_ID), + Some(ksm_location) + ) + }); + } + + fn convert_unkown_multilocation() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + let unknown_location: MultiLocation = MultiLocation::new( + 1, + X2(Parachain(T::FudgeHandle::PARA_ID), general_key(&[42])), + ); + + env.parachain_state_mut(|| { + assert!(>::convert(unknown_location).is_err()); + }); + } + + fn convert_unsupported_currency() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + env.parachain_state_mut(|| { + assert_eq!( + >::convert(CurrencyId::Tranche( + 0, + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] + )), + None + ) + }); + } + + crate::test_for_runtimes!([altair], convert_air); + crate::test_for_runtimes!([altair], convert_tranche); + crate::test_for_runtimes!([altair], convert_ausd); + crate::test_for_runtimes!([altair], convert_ksm); + crate::test_for_runtimes!([altair], convert_unkown_multilocation); + crate::test_for_runtimes!([altair], convert_unsupported_currency); + } +} diff --git a/runtime/integration-tests/src/generic/config.rs b/runtime/integration-tests/src/generic/config.rs index a25c5184ff..f52a6cbe0e 100644 --- a/runtime/integration-tests/src/generic/config.rs +++ b/runtime/integration-tests/src/generic/config.rs @@ -91,7 +91,10 @@ pub trait Runtime: Balance = Balance, NativeFungible = pallet_balances::Pallet, > + cumulus_pallet_parachain_system::Config + + parachain_info::Config + orml_oracle::Config + + orml_xtokens::Config + + pallet_xcm::Config { /// Just the RuntimeCall type, but redefined with extra bounds. /// You can add `From` bounds in order to convert pallet calls to diff --git a/runtime/integration-tests/src/generic/envs/fudge_env.rs b/runtime/integration-tests/src/generic/envs/fudge_env.rs index 03660d3459..867efff3f6 100644 --- a/runtime/integration-tests/src/generic/envs/fudge_env.rs +++ b/runtime/integration-tests/src/generic/envs/fudge_env.rs @@ -35,7 +35,8 @@ impl Env for FudgeEnv { let mut handle = T::FudgeHandle::new(Storage::default(), parachain_storage, sibling_storage); - handle.evolve(); + // TODO(cdamian): Confirm this doesn't affect tests. + // handle.evolve(); Self { handle, diff --git a/runtime/integration-tests/src/generic/envs/fudge_env/handle.rs b/runtime/integration-tests/src/generic/envs/fudge_env/handle.rs index 7865e808ce..305223ffaf 100644 --- a/runtime/integration-tests/src/generic/envs/fudge_env/handle.rs +++ b/runtime/integration-tests/src/generic/envs/fudge_env/handle.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use cfg_primitives::{AuraId, BlockNumber}; +use cfg_primitives::{AuraId, Balance, BlockNumber}; use cumulus_primitives_core::CollectCollationInfo; use frame_support::{traits::GenesisBuild, Parameter}; use fudge::{ @@ -18,6 +18,7 @@ use polkadot_parachain::primitives::Id as ParaId; use polkadot_primitives::{ runtime_api::ParachainHost, AssignmentId, AuthorityDiscoveryId, ValidatorId, }; +use polkadot_runtime_parachains::configuration::HostConfiguration; use sc_block_builder::BlockBuilderApi; use sc_client_api::Backend; use sc_service::{TFullBackend, TFullClient}; @@ -27,7 +28,7 @@ use sp_consensus_babe::BabeApi; use sp_consensus_slots::SlotDuration; use sp_core::{crypto::AccountId32, ByteArray, H256}; use sp_runtime::{ - traits::{BlakeTwo256, MaybeSerializeDeserialize, Member, OpaqueKeys}, + traits::{AccountIdLookup, BlakeTwo256, MaybeSerializeDeserialize, Member, OpaqueKeys}, Storage, }; use sp_transaction_pool::runtime_api::TaggedTransactionQueue; @@ -80,10 +81,17 @@ pub type RelayClient = TFullClient = TFullClient; pub trait FudgeHandle { - type RelayRuntime: frame_system::Config - + polkadot_runtime_parachains::paras::Config + type RelayRuntime: frame_system::Config< + BlockNumber = BlockNumber, + AccountId = AccountId32, + Lookup = AccountIdLookup, + > + polkadot_runtime_parachains::paras::Config + polkadot_runtime_parachains::session_info::Config - + polkadot_runtime_parachains::initializer::Config; + + polkadot_runtime_parachains::initializer::Config + + polkadot_runtime_parachains::hrmp::Config + + pallet_session::Config + + pallet_xcm::Config + + pallet_balances::Config; type RelayConstructApi: ConstructRuntimeApi< RelayBlock, @@ -116,6 +124,9 @@ pub trait FudgeHandle { const RELAY_CODE: Option<&'static [u8]>; const PARACHAIN_CODE: Option<&'static [u8]>; + const PARA_ID: u32; + const SIBLING_ID: u32; + fn relay(&self) -> &RelaychainBuilder; fn relay_mut(&mut self) -> &mut RelaychainBuilder; @@ -139,6 +150,7 @@ pub trait FudgeHandle { fn new_relay_builder( storage: Storage, + session_keys: ::Keys, ) -> RelaychainBuilder { sp_tracing::enter_span!(sp_tracing::Level::INFO, "Relay - StartUp"); @@ -147,11 +159,30 @@ pub trait FudgeHandle { StateProvider::, RelayBlock>::empty_default(Some(code)) .expect("ESSENTIAL: State provider can be created."); + let mut configuration = polkadot_runtime_parachains::configuration::GenesisConfig::< + Self::RelayRuntime, + >::default(); + + let mut host_config = HostConfiguration::::default(); + host_config.max_downward_message_size = 1024; + host_config.hrmp_channel_max_capacity = 100; + host_config.hrmp_channel_max_message_size = 1024; + host_config.hrmp_channel_max_total_size = 1024; + host_config.hrmp_max_parachain_outbound_channels = 10; + host_config.hrmp_max_parachain_inbound_channels = 10; + host_config.hrmp_max_message_num_per_candidate = 100; + host_config.max_upward_queue_count = 10; + host_config.max_upward_queue_size = 1024; + host_config.max_upward_message_size = 1024; + host_config.max_upward_message_num_per_candidate = 100; + + configuration.config = host_config; + state .insert_storage( - polkadot_runtime_parachains::configuration::GenesisConfig::::default() - .build_storage() - .expect("ESSENTIAL: GenesisBuild must not fail at this stage."), + configuration + .build_storage() + .expect("ESSENTIAL: GenesisBuild must not fail at this stage."), ) .expect("ESSENTIAL: Storage can be inserted"); @@ -164,6 +195,19 @@ pub trait FudgeHandle { .expect("ESSENTIAL: GenesisBuild must not fail at this stage."), ) .expect("ESSENTIAL: Storage can be inserted"); + state + .insert_storage( + pallet_session::GenesisConfig:: { + keys: vec![( + AccountId32::from_slice([0u8; 32].as_slice()).unwrap(), + AccountId32::from_slice([0u8; 32].as_slice()).unwrap(), + session_keys, + )], + } + .build_storage() + .unwrap(), + ) + .unwrap(); state .insert_storage(storage) @@ -204,9 +248,7 @@ pub trait FudgeHandle { let dp: DigestCreator = Box::new(move |parent: Header, inherents| async move { let babe = FudgeBabeDigest::::new(); - let mut digest = babe.build_digest(parent.clone(), &inherents).await?; - - babe.append_digest(parent, &mut digest, &inherents).await?; + let digest = babe.build_digest(parent.clone(), &inherents).await?; Ok(digest) }); @@ -245,6 +287,16 @@ pub trait FudgeHandle { .expect("ESSENTIAL: GenesisBuild must not fail at this stage."), ) .expect("ESSENTIAL: Storage can be inserted"); + state + .insert_storage( + >::build_storage( + ¶chain_info::GenesisConfig { + parachain_id: para_id, + }, + ) + .expect("ESSENTIAL: Parachain Info GenesisBuild must not fail at this stage."), + ) + .expect("ESSENTIAL: Storage can be inserted"); state .insert_storage(storage) @@ -288,9 +340,7 @@ pub trait FudgeHandle { >::new(&*client) .expect("ESSENTIAL: Aura digest can be created."); - let mut digest = aura.build_digest(parent.clone(), &inherents).await?; - - // aura.append_digest(parent, &mut digest, &inherents).await?; + let digest = aura.build_digest(parent.clone(), &inherents).await?; Ok(digest) } diff --git a/runtime/integration-tests/src/generic/impls.rs b/runtime/integration-tests/src/generic/impls.rs index 41fb70075e..933b1a952e 100644 --- a/runtime/integration-tests/src/generic/impls.rs +++ b/runtime/integration-tests/src/generic/impls.rs @@ -1,3 +1,6 @@ +use polkadot_primitives::{AssignmentId, AuthorityDiscoveryId, ValidatorId}; +use sp_core::ByteArray; + /// Implements the `Runtime` trait for a runtime macro_rules! impl_runtime { ($runtime_path:ident, $kind:ident) => { @@ -26,6 +29,7 @@ macro_rules! impl_fudge_support { ( $fudge_companion_type:ident, $relay_path:ident, + $relay_session_keys:expr, $parachain_path:ident, $parachain_id:literal, $sibling_id:literal @@ -72,21 +76,23 @@ macro_rules! impl_fudge_support { type RelayRuntime = $relay_path::Runtime; const PARACHAIN_CODE: Option<&'static [u8]> = $parachain_path::WASM_BINARY; + const PARA_ID: u32 = $parachain_id; const RELAY_CODE: Option<&'static [u8]> = $relay_path::WASM_BINARY; + const SIBLING_ID: u32 = $sibling_id; fn new( relay_storage: Storage, parachain_storage: Storage, sibling_storage: Storage, ) -> Self { - let relay = Self::new_relay_builder(relay_storage); + let relay = Self::new_relay_builder(relay_storage, $relay_session_keys); let parachain = Self::new_parachain_builder( - ParaId::from($parachain_id), + ParaId::from(Self::PARA_ID), &relay, parachain_storage, ); let sibling = Self::new_parachain_builder( - ParaId::from($sibling_id), + ParaId::from(Self::SIBLING_ID), &relay, sibling_storage, ); @@ -160,15 +166,63 @@ macro_rules! impl_fudge_support { impl_fudge_support!( FudgeDevelopment, rococo_runtime, + default_rococo_session_keys(), development_runtime, 2000, 2001 ); -impl_fudge_support!(FudgeAltair, kusama_runtime, altair_runtime, 2088, 2089); + +impl_fudge_support!( + FudgeAltair, + kusama_runtime, + default_kusama_session_keys(), + altair_runtime, + 2088, + 2089 +); + impl_fudge_support!( FudgeCentrifuge, polkadot_runtime, + default_polkadot_session_keys(), centrifuge_runtime, 2031, 2032 ); + +pub fn default_rococo_session_keys() -> rococo_runtime::SessionKeys { + rococo_runtime::SessionKeys { + grandpa: pallet_grandpa::AuthorityId::from_slice([0u8; 32].as_slice()).unwrap(), + babe: pallet_babe::AuthorityId::from_slice([0u8; 32].as_slice()).unwrap(), + im_online: pallet_im_online::sr25519::AuthorityId::from_slice([0u8; 32].as_slice()) + .unwrap(), + para_validator: ValidatorId::from_slice([0u8; 32].as_slice()).unwrap(), + para_assignment: AssignmentId::from_slice([0u8; 32].as_slice()).unwrap(), + authority_discovery: AuthorityDiscoveryId::from_slice([0u8; 32].as_slice()).unwrap(), + beefy: sp_consensus_beefy::crypto::AuthorityId::from_slice([0u8; 33].as_slice()).unwrap(), + } +} + +pub fn default_kusama_session_keys() -> kusama_runtime::SessionKeys { + kusama_runtime::SessionKeys { + grandpa: pallet_grandpa::AuthorityId::from_slice([0u8; 32].as_slice()).unwrap(), + babe: pallet_babe::AuthorityId::from_slice([0u8; 32].as_slice()).unwrap(), + im_online: pallet_im_online::sr25519::AuthorityId::from_slice([0u8; 32].as_slice()) + .unwrap(), + para_validator: ValidatorId::from_slice([0u8; 32].as_slice()).unwrap(), + para_assignment: AssignmentId::from_slice([0u8; 32].as_slice()).unwrap(), + authority_discovery: AuthorityDiscoveryId::from_slice([0u8; 32].as_slice()).unwrap(), + } +} + +pub fn default_polkadot_session_keys() -> polkadot_runtime::SessionKeys { + polkadot_runtime::SessionKeys { + grandpa: pallet_grandpa::AuthorityId::from_slice([0u8; 32].as_slice()).unwrap(), + babe: pallet_babe::AuthorityId::from_slice([0u8; 32].as_slice()).unwrap(), + im_online: pallet_im_online::sr25519::AuthorityId::from_slice([0u8; 32].as_slice()) + .unwrap(), + para_validator: ValidatorId::from_slice([0u8; 32].as_slice()).unwrap(), + para_assignment: AssignmentId::from_slice([0u8; 32].as_slice()).unwrap(), + authority_discovery: AuthorityDiscoveryId::from_slice([0u8; 32].as_slice()).unwrap(), + } +} diff --git a/runtime/integration-tests/src/generic/mod.rs b/runtime/integration-tests/src/generic/mod.rs index ae6944f97b..4685a67ab9 100644 --- a/runtime/integration-tests/src/generic/mod.rs +++ b/runtime/integration-tests/src/generic/mod.rs @@ -15,6 +15,7 @@ pub mod utils; // Test cases mod cases { mod example; + mod liquidity_pools; mod loans; } diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/kusama/mod.rs b/runtime/integration-tests/src/liquidity_pools/pallet/kusama/mod.rs deleted file mode 100644 index 30b8ca39c6..0000000000 --- a/runtime/integration-tests/src/liquidity_pools/pallet/kusama/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -mod restricted_calls; -mod setup; -mod test_net; -mod tests; diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/kusama/restricted_calls.rs b/runtime/integration-tests/src/liquidity_pools/pallet/kusama/restricted_calls.rs deleted file mode 100644 index 287003b7ea..0000000000 --- a/runtime/integration-tests/src/liquidity_pools/pallet/kusama/restricted_calls.rs +++ /dev/null @@ -1,189 +0,0 @@ -// This file is part of Altair chain project. -// -// Altair 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 (see http://www.gnu.org/licenses). -// Altair 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. - -// Copyright 2021 Altair GmbH (altair.io). -// This file is part of Altair chain project. -// -// Altair 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 (see http://www.gnu.org/licenses). -// Altair 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. - -use altair_runtime::{Balances, PolkadotXcm, RuntimeCall, RuntimeOrigin, XTokens}; -use cfg_primitives::{constants::currency_decimals, parachains, Balance}; -use cfg_types::{ - tokens::{CurrencyId, CustomMetadata}, - xcm::XcmMetadata, -}; -use frame_support::{assert_err, assert_noop, assert_ok, dispatch::Dispatchable}; -use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; -use runtime_common::xcm_fees::{default_per_second, ksm_per_second}; -use sp_runtime::{DispatchError, DispatchError::BadOrigin}; -use xcm::{ - latest::{ - AssetId, Fungibility, Junction, Junction::*, Junctions::*, MultiAsset, MultiLocation, - NetworkId, WeightLimit, - }, - v2::{Instruction::WithdrawAsset, Xcm}, - VersionedMultiLocation, -}; -use xcm_simulator::TestExt; - -use crate::liquidity_pools::pallet::kusama::{ - setup::{air, foreign, sibling_account, ALICE, BOB, PARA_ID_SIBLING}, - test_net::{Altair, KusamaNet, Sibling, TestNet}, -}; - -/// Verify that calls that would allow for Tranche token to be transferred -/// through XCM fail because the underlying CurrencyIdConvert doesn't handle -/// Tranche tokens. -pub mod blocked { - use cfg_utils::vec_to_fixed_array; - use sp_runtime::{traits::ConstU32, WeakBoundedVec}; - use xcm::{latest::MultiAssets, VersionedMultiAsset, VersionedMultiAssets}; - - use super::*; - - #[test] - fn xtokens_transfer() { - // For now, Tranche tokens are not supported in the XCM config so - // we just safe-guard that trying to transfer a tranche token fails. - Altair::execute_with(|| { - assert_noop!( - XTokens::transfer( - RuntimeOrigin::signed(ALICE.into()), - CurrencyId::Tranche(401, [0; 16]), - 42, - Box::new( - MultiLocation::new( - 1, - X2( - Parachain(PARA_ID_SIBLING), - Junction::AccountId32 { - network: None, - id: BOB, - } - ) - ) - .into() - ), - WeightLimit::Limited(8_000_000_000_000.into()), - ), - orml_xtokens::Error::::NotCrossChainTransferableCurrency - ); - }); - } - - // Verify that trying to transfer Tranche tokens using their MultiLocation - // representation also fails. - #[test] - fn xtokens_transfer_multiasset() { - use codec::Encode; - - let tranche_currency = CurrencyId::Tranche(401, [0; 16]); - let tranche_id = - WeakBoundedVec::>::force_from(tranche_currency.encode(), None); - let tranche_location = MultiLocation { - parents: 1, - interior: X3( - Parachain(123), - PalletInstance(42), - GeneralKey { - length: tranche_id.len() as u8, - data: vec_to_fixed_array(tranche_id.to_vec()), - }, - ), - }; - let tranche_multi_asset = VersionedMultiAsset::from(MultiAsset::from(( - AssetId::Concrete(tranche_location), - Fungibility::Fungible(42), - ))); - - Altair::execute_with(|| { - assert_noop!( - XTokens::transfer_multiasset( - RuntimeOrigin::signed(ALICE.into()), - Box::new(tranche_multi_asset), - Box::new( - MultiLocation::new( - 1, - X2( - Parachain(PARA_ID_SIBLING), - Junction::AccountId32 { - network: None, - id: BOB, - } - ) - ) - .into() - ), - WeightLimit::Limited(8_000_000_000_000.into()), - ), - orml_xtokens::Error::::XcmExecutionFailed - ); - }); - } - - #[test] - fn xtokens_transfer_multiassets() { - use codec::Encode; - - let tranche_currency = CurrencyId::Tranche(401, [0; 16]); - let tranche_id = - WeakBoundedVec::>::force_from(tranche_currency.encode(), None); - let tranche_location = MultiLocation { - parents: 1, - interior: X3( - Parachain(123), - PalletInstance(42), - GeneralKey { - length: tranche_id.len() as u8, - data: vec_to_fixed_array(tranche_id.to_vec()), - }, - ), - }; - let tranche_multi_asset = MultiAsset::from(( - AssetId::Concrete(tranche_location), - Fungibility::Fungible(42), - )); - - Altair::execute_with(|| { - assert_noop!( - XTokens::transfer_multiassets( - RuntimeOrigin::signed(ALICE.into()), - Box::new(VersionedMultiAssets::from(MultiAssets::from(vec![ - tranche_multi_asset - ]))), - 0, - Box::new( - MultiLocation::new( - 1, - X2( - Parachain(PARA_ID_SIBLING), - Junction::AccountId32 { - network: None, - id: BOB, - } - ) - ) - .into() - ), - WeightLimit::Limited(8_000_000_000_000.into()), - ), - orml_xtokens::Error::::XcmExecutionFailed - ); - }); - } -} diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/kusama/setup.rs b/runtime/integration-tests/src/liquidity_pools/pallet/kusama/setup.rs deleted file mode 100644 index c734d8fbec..0000000000 --- a/runtime/integration-tests/src/liquidity_pools/pallet/kusama/setup.rs +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2021 Centrifuge Foundation (centrifuge.io). -// -// This file is part of the Centrifuge chain project. -// Centrifuge 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 (see http://www.gnu.org/licenses). -// Centrifuge 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. - -pub use altair_runtime::{Runtime, RuntimeOrigin, System}; -use cfg_primitives::{constants::currency_decimals, parachains, AccountId, Balance}; -use cfg_types::tokens::{CurrencyId, CustomMetadata}; -use frame_support::traits::GenesisBuild; -use orml_traits::asset_registry::AssetMetadata; - -/// Accounts -pub const ALICE: [u8; 32] = [4u8; 32]; -pub const BOB: [u8; 32] = [5u8; 32]; - -/// A PARA ID used for a sibling parachain. -/// It must be one that doesn't collide with any other in use. -pub const PARA_ID_SIBLING: u32 = 3000; - -/// The test asset id attributed to KSM -pub const KSM_ASSET_ID: CurrencyId = CurrencyId::ForeignAsset(1000); - -pub struct ExtBuilder { - balances: Vec<(AccountId, CurrencyId, Balance)>, - parachain_id: u32, -} - -impl Default for ExtBuilder { - fn default() -> Self { - Self { - balances: vec![], - parachain_id: parachains::kusama::altair::ID, - } - } -} - -impl ExtBuilder { - pub fn balances(mut self, balances: Vec<(AccountId, CurrencyId, Balance)>) -> Self { - self.balances = balances; - self - } - - pub fn parachain_id(mut self, parachain_id: u32) -> Self { - self.parachain_id = parachain_id; - self - } - - pub fn build(self) -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap(); - let native_currency_id = altair_runtime::NativeToken::get(); - 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)) - .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(); - - >::assimilate_storage( - ¶chain_info::GenesisConfig { - parachain_id: self.parachain_id.into(), - }, - &mut t, - ) - .unwrap(); - - >::assimilate_storage( - &pallet_xcm::GenesisConfig { - safe_xcm_version: Some(2), - }, - &mut t, - ) - .unwrap(); - - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext - } -} - -pub fn air(amount: Balance) -> Balance { - amount * dollar(currency_decimals::NATIVE) -} - -pub fn ausd(amount: Balance) -> Balance { - amount * dollar(currency_decimals::AUSD) -} - -pub fn ksm(amount: Balance) -> Balance { - amount * dollar(currency_decimals::KSM) -} - -pub fn foreign(amount: Balance, decimals: u32) -> Balance { - amount * dollar(decimals) -} - -pub fn dollar(decimals: u32) -> Balance { - 10u128.saturating_pow(decimals) -} - -pub fn sibling_account() -> AccountId { - parachain_account(PARA_ID_SIBLING) -} - -pub fn karura_account() -> AccountId { - parachain_account(parachains::kusama::karura::ID) -} - -pub fn altair_account() -> AccountId { - parachain_account(parachains::kusama::altair::ID) -} - -fn parachain_account(id: u32) -> AccountId { - use sp_runtime::traits::AccountIdConversion; - - polkadot_parachain::primitives::Sibling::from(id).into_account_truncating() -} diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/kusama/test_net.rs b/runtime/integration-tests/src/liquidity_pools/pallet/kusama/test_net.rs deleted file mode 100644 index 445105496f..0000000000 --- a/runtime/integration-tests/src/liquidity_pools/pallet/kusama/test_net.rs +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2021 Centrifuge GmbH (centrifuge.io). -// This file is part of Centrifuge chain project. - -// Centrifuge 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 (see http://www.gnu.org/licenses). - -// Centrifuge 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. - -//! Relay chain and parachains emulation. - -use altair_runtime::CurrencyId; -use cfg_primitives::{parachains, AccountId}; -use cumulus_primitives_core::ParaId; -use frame_support::{traits::GenesisBuild, weights::Weight}; -use polkadot_primitives::{BlockNumber, MAX_CODE_SIZE, MAX_POV_SIZE}; -use polkadot_runtime_parachains::configuration::HostConfiguration; -use sp_runtime::traits::AccountIdConversion; -use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt}; - -use super::setup::{air, ksm, ExtBuilder, ALICE, BOB, PARA_ID_SIBLING}; - -decl_test_relay_chain! { - pub struct KusamaNet { - Runtime = kusama_runtime::Runtime, - RuntimeCall = kusama_runtime::RuntimeCall, - RuntimeEvent = kusama_runtime::RuntimeEvent, - XcmConfig = kusama_runtime::xcm_config::XcmConfig, - MessageQueue = kusama_runtime::MessageQueue, - System = kusama_runtime::System, - new_ext = relay_ext(), - } -} - -decl_test_parachain! { - pub struct Altair { - Runtime = altair_runtime::Runtime, - XcmpMessageHandler = altair_runtime::XcmpQueue, - DmpMessageHandler = altair_runtime::DmpQueue, - new_ext = para_ext(parachains::kusama::altair::ID), - } -} - -decl_test_parachain! { - pub struct Sibling { - Runtime = altair_runtime::Runtime, - XcmpMessageHandler = altair_runtime::XcmpQueue, - DmpMessageHandler = altair_runtime::DmpQueue, - new_ext = para_ext(PARA_ID_SIBLING), - } -} - -decl_test_parachain! { - pub struct Karura { - Runtime = altair_runtime::Runtime, - XcmpMessageHandler = altair_runtime::XcmpQueue, - DmpMessageHandler = altair_runtime::DmpQueue, - new_ext = para_ext(parachains::kusama::karura::ID), - } -} - -decl_test_network! { - pub struct TestNet { - relay_chain = KusamaNet, - parachains = vec![ - // N.B: Ideally, we could use the defined para id constants but doing so - // fails with: "error: arbitrary expressions aren't allowed in patterns" - - // Be sure to use `parachains::kusama::altair::ID` - (2088, Altair), - // Be sure to use `PARA_ID_SIBLING` - (3000, Sibling), - // Be sure to use `parachains::kusama::karura::ID` - (2000, Karura), - ], - } -} - -pub fn relay_ext() -> sp_io::TestExternalities { - use kusama_runtime::{Runtime, System}; - - let mut t = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap(); - - pallet_balances::GenesisConfig:: { - balances: vec![ - (AccountId::from(ALICE), air(2002)), - ( - ParaId::from(parachains::kusama::altair::ID).into_account_truncating(), - air(7), - ), - ( - ParaId::from(PARA_ID_SIBLING).into_account_truncating(), - air(7), - ), - ], - } - .assimilate_storage(&mut t) - .unwrap(); - - polkadot_runtime_parachains::configuration::GenesisConfig:: { - config: default_parachains_host_configuration(), - } - .assimilate_storage(&mut t) - .unwrap(); - - >::assimilate_storage( - &pallet_xcm::GenesisConfig { - safe_xcm_version: Some(2), - }, - &mut t, - ) - .unwrap(); - - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext -} - -pub fn para_ext(parachain_id: u32) -> sp_io::TestExternalities { - ExtBuilder::default() - .balances(vec![ - (AccountId::from(ALICE), CurrencyId::Native, air(10)), - (AccountId::from(BOB), CurrencyId::Native, air(10)), - ]) - .parachain_id(parachain_id) - .build() -} - -fn default_parachains_host_configuration() -> HostConfiguration { - HostConfiguration { - hrmp_channel_max_capacity: u32::MAX, - hrmp_channel_max_total_size: u32::MAX, - hrmp_max_parachain_inbound_channels: 10, - hrmp_max_parachain_outbound_channels: 10, - hrmp_channel_max_message_size: u32::MAX, - // Changed to avoid aritmetic errors within hrmp_close - max_downward_message_size: 100_000u32, - ..Default::default() - } -} diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/kusama/tests/asset_registry.rs b/runtime/integration-tests/src/liquidity_pools/pallet/kusama/tests/asset_registry.rs deleted file mode 100644 index 04b016617f..0000000000 --- a/runtime/integration-tests/src/liquidity_pools/pallet/kusama/tests/asset_registry.rs +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2021 Centrifuge GmbH (centrifuge.io). -// This file is part of Centrifuge chain project. -// -// Centrifuge 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 (see http://www.gnu.org/licenses). -// Centrifuge 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. - -// Copyright 2021 Centrifuge GmbH (centrifuge.io). -// This file is part of Centrifuge chain project. -// -// Centrifuge 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 (see http://www.gnu.org/licenses). -// Centrifuge 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. - -use altair_runtime::{Balances, OrmlAssetRegistry, OrmlTokens, RuntimeOrigin, XTokens}; -use cfg_primitives::{constants::currency_decimals, parachains, Balance}; -use cfg_types::{ - tokens::{CrossChainTransferability, CurrencyId, CustomMetadata}, - xcm::XcmMetadata, -}; -use frame_support::{assert_noop, assert_ok}; -use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; -use runtime_common::{ - xcm::general_key, - xcm_fees::{default_per_second, ksm_per_second}, -}; -use sp_runtime::traits::BadOrigin; -use xcm::{ - latest::{Junction, Junction::*, Junctions::*, MultiLocation, NetworkId}, - prelude::{Parachain, X2}, - VersionedMultiLocation, -}; -use xcm_simulator::TestExt; - -use crate::liquidity_pools::pallet::kusama::{ - setup::{ - air, altair_account, ausd, foreign, karura_account, ksm, sibling_account, ALICE, BOB, - PARA_ID_SIBLING, - }, - test_net::{Altair, Karura, KusamaNet, Sibling, TestNet}, -}; - -#[test] -fn register_air_works() { - Altair::execute_with(|| { - let meta: AssetMetadata = AssetMetadata { - decimals: 18, - name: "Altair".into(), - symbol: "AIR".into(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedMultiLocation::V3(MultiLocation::new( - 0, - X1(general_key(parachains::kusama::altair::AIR_KEY)), - ))), - additional: CustomMetadata { - transferability: CrossChainTransferability::Xcm(Default::default()), - ..CustomMetadata::default() - }, - }; - - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - meta, - Some(CurrencyId::Native) - )); - }); -} - -#[test] -fn register_foreign_asset_works() { - Altair::execute_with(|| { - let meta: AssetMetadata = AssetMetadata { - decimals: 12, - name: "Acala Dollar".into(), - symbol: "AUSD".into(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedMultiLocation::V3(MultiLocation::new( - 1, - X2( - Parachain(parachains::kusama::karura::ID), - general_key(parachains::kusama::karura::AUSD_KEY), - ), - ))), - additional: CustomMetadata { - transferability: CrossChainTransferability::Xcm(Default::default()), - ..CustomMetadata::default() - }, - }; - - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - meta, - Some(CurrencyId::ForeignAsset(42)) - )); - }); -} - -#[test] -// Verify that registering tranche tokens is not allowed through extrinsics -fn register_tranche_asset_blocked() { - Altair::execute_with(|| { - let meta: AssetMetadata = AssetMetadata { - decimals: 12, - name: "Tranche Token 1".into(), - symbol: "TRNCH".into(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedMultiLocation::V3(MultiLocation::new( - 1, - X2(Parachain(2000), general_key(&[42])), - ))), - additional: CustomMetadata { - transferability: CrossChainTransferability::Xcm(Default::default()), - ..CustomMetadata::default() - }, - }; - - // It fails with `BadOrigin` even when submitted with `Origin::root` since we - // only allow for tranche tokens to be registered through the pools pallet. - let asset_id = CurrencyId::Tranche(42, [42u8; 16]); - assert_noop!( - OrmlAssetRegistry::register_asset(RuntimeOrigin::root(), meta, Some(asset_id)), - BadOrigin - ); - }); -} diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/kusama/tests/currency_id_convert.rs b/runtime/integration-tests/src/liquidity_pools/pallet/kusama/tests/currency_id_convert.rs deleted file mode 100644 index 0253849a8b..0000000000 --- a/runtime/integration-tests/src/liquidity_pools/pallet/kusama/tests/currency_id_convert.rs +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright 2021 Centrifuge GmbH (centrifuge.io). -// This file is part of Centrifuge chain project. -// -// Centrifuge 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 (see http://www.gnu.org/licenses). -// Centrifuge 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. - -// Copyright 2021 Centrifuge GmbH (centrifuge.io). -// This file is part of Centrifuge chain project. -// -// Centrifuge 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 (see http://www.gnu.org/licenses). -// Centrifuge 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. - -use altair_runtime::{ - Balances, CurrencyIdConvert, OrmlAssetRegistry, OrmlTokens, PoolPalletIndex, RuntimeOrigin, - XTokens, -}; -use cfg_primitives::{constants::currency_decimals, parachains, Balance}; -use cfg_types::{ - tokens::{CurrencyId, CustomMetadata}, - xcm::XcmMetadata, -}; -use cfg_utils::vec_to_fixed_array; -use codec::Encode; -use frame_support::{assert_ok, traits::Len}; -use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; -use runtime_common::{ - xcm::general_key, - xcm_fees::{default_per_second, ksm_per_second}, -}; -use sp_runtime::{ - traits::{ConstU32, Convert as C2}, - WeakBoundedVec, -}; -use xcm::{ - latest::{Error::BadOrigin, Junction, Junction::*, Junctions::*, MultiLocation, NetworkId}, - VersionedMultiLocation, -}; -use xcm_executor::traits::Convert as C1; -use xcm_simulator::TestExt; - -use crate::{ - liquidity_pools::pallet::kusama::{ - setup::{ - air, altair_account, ausd, foreign, karura_account, ksm, sibling_account, ALICE, BOB, - KSM_ASSET_ID, PARA_ID_SIBLING, - }, - test_net::{Altair, Karura, KusamaNet, Sibling, TestNet}, - tests::{register_air, register_ausd, register_ksm}, - }, - utils::AUSD_CURRENCY_ID, -}; - -#[test] -fn convert_air() { - assert_eq!(parachains::kusama::altair::AIR_KEY.to_vec(), vec![0, 1]); - - Altair::execute_with(|| { - // The way AIR is represented relative within the Altair runtime - let air_location_inner: MultiLocation = - MultiLocation::new(0, X1(general_key(parachains::kusama::altair::AIR_KEY))); - - // register air - register_air(); - - assert_eq!( - >::convert(air_location_inner), - Ok(CurrencyId::Native), - ); - - // The canonical way AIR is represented out in the wild - let air_location_canonical: MultiLocation = MultiLocation::new( - 1, - X2( - Parachain(parachains::kusama::altair::ID), - general_key(parachains::kusama::altair::AIR_KEY), - ), - ); - - assert_eq!( - >::convert(CurrencyId::Native), - Some(air_location_canonical) - ) - }); -} - -/// Verify that Tranche tokens are not handled by the CurrencyIdConvert -/// since we don't allow Tranche tokens to be transferable through XCM. -#[test] -fn convert_tranche() { - let tranche_currency = CurrencyId::Tranche(401, [0; 16]); - let tranche_id = - WeakBoundedVec::>::force_from(tranche_currency.encode(), None); - let tranche_multilocation = MultiLocation { - parents: 1, - interior: X3( - Parachain(parachains::kusama::altair::ID), - PalletInstance(PoolPalletIndex::get()), - GeneralKey { - length: tranche_id.len() as u8, - data: vec_to_fixed_array(tranche_id.to_vec()), - }, - ), - }; - - Altair::execute_with(|| { - assert_eq!( - >::convert(tranche_multilocation), - Err(tranche_multilocation), - ); - }); - - Altair::execute_with(|| { - assert_eq!( - >::convert(tranche_currency), - None - ) - }); -} - -#[test] -fn convert_ausd() { - Altair::execute_with(|| { - assert_eq!(parachains::kusama::karura::AUSD_KEY, &[0, 129]); - - let ausd_location: MultiLocation = MultiLocation::new( - 1, - X2( - Parachain(parachains::kusama::karura::ID), - general_key(parachains::kusama::karura::AUSD_KEY), - ), - ); - - register_ausd(); - - assert_eq!( - >::convert(ausd_location.clone()), - Ok(AUSD_CURRENCY_ID), - ); - - assert_eq!( - >::convert(AUSD_CURRENCY_ID), - Some(ausd_location) - ) - }); -} - -#[test] -fn convert_ksm() { - let ksm_location: MultiLocation = MultiLocation::parent().into(); - - Altair::execute_with(|| { - register_ksm(); - - assert_eq!( - >::convert(ksm_location), - Ok(KSM_ASSET_ID), - ); - - assert_eq!( - >::convert(KSM_ASSET_ID), - Some(ksm_location) - ) - }); -} - -#[test] -fn convert_unkown_multilocation() { - let unknown_location: MultiLocation = MultiLocation::new( - 1, - X2( - Parachain(parachains::kusama::altair::ID), - general_key(&[42]), - ), - ); - - Altair::execute_with(|| { - assert!(>::convert(unknown_location).is_err()); - }); -} - -#[test] -fn convert_unsupported_currency() { - Altair::execute_with(|| { - assert_eq!( - >::convert(CurrencyId::Tranche( - 0, - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] - )), - None - ) - }); -} diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/kusama/tests/mod.rs b/runtime/integration-tests/src/liquidity_pools/pallet/kusama/tests/mod.rs deleted file mode 100644 index 806d045ae0..0000000000 --- a/runtime/integration-tests/src/liquidity_pools/pallet/kusama/tests/mod.rs +++ /dev/null @@ -1,98 +0,0 @@ -use centrifuge_runtime::{OrmlAssetRegistry, RuntimeOrigin}; -use cfg_primitives::{parachains, Balance}; -use cfg_types::{ - tokens::{CrossChainTransferability, CurrencyId, CustomMetadata}, - xcm::XcmMetadata, -}; -use frame_support::assert_ok; -use orml_traits::asset_registry::AssetMetadata; -use runtime_common::{xcm::general_key, xcm_fees::ksm_per_second}; -use xcm::{ - latest::MultiLocation, - prelude::{Here, Parachain, X2}, - VersionedMultiLocation, -}; - -use crate::{liquidity_pools::pallet::kusama::setup::KSM_ASSET_ID, utils::AUSD_CURRENCY_ID}; - -mod asset_registry; -mod currency_id_convert; -mod transfers; - -/// Register AIR in the asset registry. -/// It should be executed within an externalities environment. -fn register_air() { - let meta: AssetMetadata = AssetMetadata { - decimals: 18, - name: "Altair".into(), - symbol: "AIR".into(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedMultiLocation::V3(MultiLocation::new( - 1, - X2( - Parachain(parachains::kusama::altair::ID), - general_key(parachains::kusama::altair::AIR_KEY), - ), - ))), - additional: CustomMetadata { - transferability: CrossChainTransferability::Xcm(Default::default()), - ..CustomMetadata::default() - }, - }; - - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - meta, - Some(CurrencyId::Native) - )); -} - -/// Register AUSD in the asset registry. -/// It should be executed within an externalities environment. -fn register_ausd() { - let meta: AssetMetadata = AssetMetadata { - decimals: 12, - name: "Acala Dollar".into(), - symbol: "AUSD".into(), - existential_deposit: 1_000_000_000, - location: Some(VersionedMultiLocation::V3(MultiLocation::new( - 1, - X2( - Parachain(parachains::kusama::karura::ID), - general_key(parachains::kusama::karura::AUSD_KEY), - ), - ))), - additional: CustomMetadata { - transferability: CrossChainTransferability::Xcm(Default::default()), - ..CustomMetadata::default() - }, - }; - - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - meta, - Some(AUSD_CURRENCY_ID) - )); -} - -/// Register KSM in the asset registry. -/// It should be executed within an externalities environment. -fn register_ksm() { - let meta: AssetMetadata = AssetMetadata { - decimals: 12, - name: "Kusama".into(), - symbol: "KSM".into(), - existential_deposit: 1_000_000_000, - location: Some(VersionedMultiLocation::V3(MultiLocation::new(1, Here))), - additional: CustomMetadata { - transferability: CrossChainTransferability::Xcm(Default::default()), - ..CustomMetadata::default() - }, - }; - - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - meta, - Some(KSM_ASSET_ID) - )); -} diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/kusama/tests/transfers.rs b/runtime/integration-tests/src/liquidity_pools/pallet/kusama/tests/transfers.rs deleted file mode 100644 index 6ff029a58a..0000000000 --- a/runtime/integration-tests/src/liquidity_pools/pallet/kusama/tests/transfers.rs +++ /dev/null @@ -1,621 +0,0 @@ -// Copyright 2021 Centrifuge GmbH (centrifuge.io). -// This file is part of Centrifuge chain project. -// -// Centrifuge 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 (see http://www.gnu.org/licenses). -// Centrifuge 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. - -// Copyright 2021 Centrifuge GmbH (centrifuge.io). -// This file is part of Centrifuge chain project. -// -// Centrifuge 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 (see http://www.gnu.org/licenses). -// Centrifuge 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. - -use altair_runtime::{Balances, OrmlAssetRegistry, OrmlTokens, RuntimeOrigin, XTokens}; -use cfg_primitives::{constants::currency_decimals, parachains, Balance}; -use cfg_types::{ - tokens::{CrossChainTransferability, CurrencyId, CustomMetadata}, - xcm::XcmMetadata, -}; -use frame_support::assert_ok; -use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; -use runtime_common::{ - xcm::general_key, - xcm_fees::{default_per_second, ksm_per_second}, -}; -use sp_runtime::DispatchError::BadOrigin; -use xcm::{ - latest::{Junction, Junction::*, Junctions::*, MultiLocation, NetworkId, WeightLimit}, - VersionedMultiLocation, -}; -use xcm_simulator::TestExt; - -use crate::{ - liquidity_pools::pallet::{ - kusama::{ - setup::{ - air, altair_account, ausd, foreign, karura_account, ksm, sibling_account, ALICE, - BOB, PARA_ID_SIBLING, - }, - test_net::{Altair, Karura, KusamaNet, Sibling, TestNet}, - tests::register_ausd, - }, - xcm_metadata, - }, - utils::AUSD_CURRENCY_ID, -}; - -/* - -NOTE: We hardcode the expected balances after an XCM operation given that the weights involved in -XCM execution often change slightly with each Polkadot update. We could simply test that the final -balance after some XCM operation is `initialBalance - amount - fee`, which would mean we would -never have to touch the tests again. However, by hard-coding these values we are forced to catch -an unexpectedly big change that would have a big impact on the weights and fees and thus balances, -which would go unnoticed and untreated otherwise. - - */ - -#[test] -fn transfer_air_to_sibling() { - TestNet::reset(); - - let alice_initial_balance = air(10); - let bob_initial_balance = air(10); - let transfer_amount = air(1); - let transfer_amount = air(5); - let air_in_sibling = CurrencyId::ForeignAsset(12); - - Altair::execute_with(|| { - assert_eq!(Balances::free_balance(&ALICE.into()), alice_initial_balance); - assert_eq!(Balances::free_balance(&sibling_account()), 0); - - // Register AIR as foreign asset in the sibling parachain - let meta: AssetMetadata = AssetMetadata { - decimals: 18, - name: "Altair".into(), - symbol: "AIR".into(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedMultiLocation::V3(MultiLocation::new( - 1, - X2( - Parachain(parachains::kusama::altair::ID), - general_key(parachains::kusama::altair::AIR_KEY), - ), - ))), - additional: CustomMetadata { - transferability: CrossChainTransferability::Xcm(Default::default()), - ..CustomMetadata::default() - }, - }; - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - meta, - Some(CurrencyId::Native) - )); - }); - - Sibling::execute_with(|| { - assert_eq!(OrmlTokens::free_balance(air_in_sibling, &BOB.into()), 0); - - // Register AIR as foreign asset in the sibling parachain - let meta: AssetMetadata = AssetMetadata { - decimals: 18, - name: "Altair".into(), - symbol: "AIR".into(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedMultiLocation::V3(MultiLocation::new( - 1, - X2( - Parachain(parachains::kusama::altair::ID), - general_key(parachains::kusama::altair::AIR_KEY), - ), - ))), - additional: CustomMetadata { - transferability: CrossChainTransferability::Xcm(Default::default()), - ..CustomMetadata::default() - }, - }; - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - meta, - Some(air_in_sibling) - )); - }); - - Altair::execute_with(|| { - assert_ok!(XTokens::transfer( - RuntimeOrigin::signed(ALICE.into()), - CurrencyId::Native, - transfer_amount, - Box::new( - MultiLocation::new( - 1, - X2( - Parachain(PARA_ID_SIBLING), - Junction::AccountId32 { - network: None, - id: BOB, - } - ) - ) - .into() - ), - WeightLimit::Limited(8_000_000_000_000.into()), - )); - - // Confirm that Alice's balance is initial balance - amount transferred - assert_eq!( - Balances::free_balance(&ALICE.into()), - alice_initial_balance - transfer_amount - ); - - // Verify that the amount transferred is now part of the sibling account here - assert_eq!(Balances::free_balance(&sibling_account()), transfer_amount); - }); - - Sibling::execute_with(|| { - let current_balance = OrmlTokens::free_balance(air_in_sibling, &BOB.into()); - - // Verify that BOB now has (amount transferred - fee) - assert_eq!(current_balance, transfer_amount - fee(18)); - - // Sanity check for the actual amount BOB ends up with - assert_eq!(current_balance, 4991987200000000000); - }); -} - -#[test] -fn transfer_air_sibling_to_altair() { - TestNet::reset(); - - // In order to be able to transfer AIR from Sibling to Altair, we need to first - // send AIR from Altair to Sibling, or else it fails since it'd be like Sibling - // had minted AIR on their side. - transfer_air_to_sibling(); - - let alice_initial_balance = air(5); - let bob_initial_balance = air(5) - air_fee(); - let transfer_amount = air(1); - // Note: This asset was registered in `transfer_air_to_sibling` - let air_in_sibling = CurrencyId::ForeignAsset(12); - - Altair::execute_with(|| { - assert_eq!(Balances::free_balance(&ALICE.into()), alice_initial_balance); - }); - - Sibling::execute_with(|| { - assert_eq!(Balances::free_balance(&altair_account()), 0); - assert_eq!( - OrmlTokens::free_balance(air_in_sibling, &BOB.into()), - bob_initial_balance - ); - }); - - Sibling::execute_with(|| { - assert_ok!(XTokens::transfer( - RuntimeOrigin::signed(BOB.into()), - air_in_sibling, - transfer_amount, - Box::new( - MultiLocation::new( - 1, - X2( - Parachain(parachains::kusama::altair::ID), - Junction::AccountId32 { - network: None, - id: ALICE, - } - ) - ) - .into() - ), - WeightLimit::Limited(8_000_000_000_000.into()), - )); - - // Confirm that Bobs's balance is initial balance - amount transferred - assert_eq!( - OrmlTokens::free_balance(air_in_sibling, &BOB.into()), - bob_initial_balance - transfer_amount - ); - }); - - Altair::execute_with(|| { - // Verify that ALICE now has initial balance + amount transferred - fee - assert_eq!( - Balances::free_balance(&ALICE.into()), - alice_initial_balance + transfer_amount - air_fee(), - ); - }); -} - -#[test] -fn transfer_ausd_to_altair() { - TestNet::reset(); - - let alice_initial_balance = ausd(10); - let transfer_amount = ausd(7); - - Karura::execute_with(|| { - register_ausd(); - - assert_ok!(OrmlTokens::deposit( - AUSD_CURRENCY_ID, - &ALICE.into(), - alice_initial_balance - )); - - assert_eq!( - OrmlTokens::free_balance(AUSD_CURRENCY_ID, &altair_account()), - 0 - ); - }); - - Altair::execute_with(|| { - register_ausd(); - - assert_eq!(OrmlTokens::free_balance(AUSD_CURRENCY_ID, &BOB.into()), 0,); - }); - - Karura::execute_with(|| { - assert_eq!( - OrmlTokens::free_balance(AUSD_CURRENCY_ID, &ALICE.into()), - ausd(10), - ); - assert_ok!(XTokens::transfer( - RuntimeOrigin::signed(ALICE.into()), - AUSD_CURRENCY_ID, - transfer_amount, - Box::new( - MultiLocation::new( - 1, - X2( - Parachain(parachains::kusama::altair::ID), - Junction::AccountId32 { - network: None, - id: BOB, - } - ) - ) - .into() - ), - WeightLimit::Limited(8_000_000_000_000.into()), - )); - - assert_eq!( - OrmlTokens::free_balance(AUSD_CURRENCY_ID, &ALICE.into()), - alice_initial_balance - transfer_amount - ); - - // Verify that the amount transferred is now part of the altair parachain - // account here - assert_eq!( - OrmlTokens::free_balance(AUSD_CURRENCY_ID, &altair_account()), - transfer_amount - ); - }); - - Altair::execute_with(|| { - // Verify that BOB now has initial balance + amount transferred - fee - assert_eq!( - OrmlTokens::free_balance(AUSD_CURRENCY_ID, &BOB.into()), - transfer_amount - ausd_fee() - ); - }); -} - -#[test] -fn transfer_ksm_from_relay_chain() { - let transfer_amount: Balance = ksm(2); - let currency_id = CurrencyId::ForeignAsset(3001); - let meta: AssetMetadata = AssetMetadata { - decimals: 12, - name: "Kusama".into(), - symbol: "KSM".into(), - existential_deposit: 1_000_000_000, - location: Some(VersionedMultiLocation::V3(MultiLocation::new(1, Here))), - additional: CustomMetadata { - transferability: CrossChainTransferability::Xcm(Default::default()), - ..CustomMetadata::default() - }, - }; - - Altair::execute_with(|| { - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - meta.clone(), - Some(currency_id), - )); - - assert_eq!(OrmlTokens::free_balance(currency_id, &BOB.into()), 0); - }); - - KusamaNet::execute_with(|| { - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - AssetMetadata { - location: Some(VersionedMultiLocation::V3(MultiLocation::new(0, Here))), - ..meta.clone() - }, - Some(CurrencyId::Native), - )); - - assert_ok!(kusama_runtime::XcmPallet::reserve_transfer_assets( - kusama_runtime::RuntimeOrigin::signed(ALICE.into()), - Box::new(Parachain(parachains::kusama::altair::ID).into()), - Box::new( - Junction::AccountId32 { - network: None, - id: BOB, - } - .into() - ), - Box::new((Here, transfer_amount).into()), - 0 - )); - }); - - Altair::execute_with(|| { - assert_eq!( - OrmlTokens::free_balance(currency_id, &BOB.into()), - transfer_amount - fee(meta.decimals) - ); - }); -} - -#[test] -fn transfer_ksm_to_relay_chain() { - // First we need some KSM on Altair - transfer_ksm_from_relay_chain(); - - let currency_id = CurrencyId::ForeignAsset(3001); - Altair::execute_with(|| { - assert_eq!( - OrmlTokens::free_balance(currency_id, &BOB.into()), - 1991987200000 - ); - - assert_ok!(XTokens::transfer( - RuntimeOrigin::signed(BOB.into()), - currency_id, - ksm(1), - Box::new( - MultiLocation::new( - 1, - X1(Junction::AccountId32 { - id: BOB, - network: None, - }) - ) - .into() - ), - WeightLimit::Limited(4_000_000_000.into()) - )); - }); - - KusamaNet::execute_with(|| { - assert_eq!( - kusama_runtime::Balances::free_balance(&BOB.into()), - 999909712564 - ); - }); -} - -#[test] -fn transfer_foreign_sibling_to_altair() { - TestNet::reset(); - - let alice_initial_balance = air(10); - let sibling_asset_id = CurrencyId::ForeignAsset(1); - let asset_location = - MultiLocation::new(1, X2(Parachain(PARA_ID_SIBLING), general_key(&[0, 1]))); - let meta: AssetMetadata = AssetMetadata { - decimals: 18, - name: "Sibling Native Token".into(), - symbol: "SBLNG".into(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedMultiLocation::V3(asset_location)), - additional: CustomMetadata { - transferability: CrossChainTransferability::Xcm(XcmMetadata { - // We specify a custom fee_per_second and verify below that this value is - // used when XCM transfer fees are charged for this token. - fee_per_second: Some(8420000000000000000), - }), - ..CustomMetadata::default() - }, - }; - let transfer_amount = foreign(1, meta.decimals); - - Sibling::execute_with(|| { - assert_eq!(OrmlTokens::free_balance(sibling_asset_id, &BOB.into()), 0); - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - meta.clone(), - Some(CurrencyId::Native), - )); - }); - - Altair::execute_with(|| { - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - meta.clone(), - Some(sibling_asset_id) - )); - }); - - Sibling::execute_with(|| { - assert_ok!(XTokens::transfer( - RuntimeOrigin::signed(ALICE.into()), - CurrencyId::Native, - transfer_amount, - Box::new( - MultiLocation::new( - 1, - X2( - Parachain(parachains::kusama::altair::ID), - Junction::AccountId32 { - network: None, - id: BOB, - } - ) - ) - .into() - ), - WeightLimit::Limited(8_000_000_000_000.into()), - )); - - // Confirm that Alice's balance is initial balance - amount transferred - assert_eq!( - Balances::free_balance(&ALICE.into()), - alice_initial_balance - transfer_amount - ); - }); - - Altair::execute_with(|| { - let bob_balance = OrmlTokens::free_balance(sibling_asset_id, &BOB.into()); - - // Verify that BOB now has initial balance + amount transferred - fee - assert_eq!( - bob_balance, - transfer_amount - - calc_fee( - xcm_metadata(meta.additional.transferability) - .unwrap() - .fee_per_second - .unwrap() - ) - ); - // Sanity check to ensure the calculated is what is expected - assert_eq!(bob_balance, 993264000000000000); - }); -} - -#[test] -fn transfer_wormhole_usdc_karura_to_altair() { - TestNet::reset(); - - let usdc_asset_id = CurrencyId::ForeignAsset(39); - let asset_location = MultiLocation::new( - 1, - X2( - Parachain(parachains::kusama::karura::ID), - general_key("0x02f3a00dd12f644daec907013b16eb6d14bf1c4cb4".as_bytes()), - ), - ); - let meta: AssetMetadata = AssetMetadata { - decimals: 6, - name: "Wormhole USDC".into(), - symbol: "WUSDC".into(), - existential_deposit: 1, - location: Some(VersionedMultiLocation::V3(asset_location)), - additional: CustomMetadata { - transferability: CrossChainTransferability::Xcm(Default::default()), - ..CustomMetadata::default() - }, - }; - let transfer_amount = foreign(12, meta.decimals); - let alice_initial_balance = transfer_amount * 100; - - Karura::execute_with(|| { - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - meta.clone(), - Some(usdc_asset_id) - )); - assert_ok!(OrmlTokens::deposit( - usdc_asset_id, - &ALICE.into(), - alice_initial_balance - )); - assert_eq!( - OrmlTokens::free_balance(usdc_asset_id, &ALICE.into()), - alice_initial_balance - ); - assert_eq!(Balances::free_balance(&ALICE.into()), air(10)); - }); - - Altair::execute_with(|| { - // First, register the asset in centrifuge - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - meta.clone(), - Some(usdc_asset_id) - )); - }); - - Karura::execute_with(|| { - assert_ok!(XTokens::transfer( - RuntimeOrigin::signed(ALICE.into()), - usdc_asset_id, - transfer_amount, - Box::new( - MultiLocation::new( - 1, - X2( - Parachain(parachains::kusama::altair::ID), - Junction::AccountId32 { - network: None, - id: BOB, - } - ) - ) - .into() - ), - WeightLimit::Limited(8_000_000_000.into()), - )); - - // Confirm that Alice's balance is initial balance - amount transferred - assert_eq!( - OrmlTokens::free_balance(usdc_asset_id, &ALICE.into()), - alice_initial_balance - transfer_amount - ); - }); - - Altair::execute_with(|| { - let bob_balance = OrmlTokens::free_balance(usdc_asset_id, &BOB.into()); - - // Sanity check to ensure the calculated is what is expected - assert_eq!(bob_balance, 11991988); - }); -} - -#[test] -fn test_total_fee() { - assert_eq!(air_fee(), 8012800000000000); -} - -fn air_fee() -> Balance { - fee(currency_decimals::NATIVE) -} - -fn ausd_fee() -> Balance { - fee(currency_decimals::AUSD) -} - -fn fee(decimals: u32) -> Balance { - calc_fee(default_per_second(decimals)) -} - -// The fee associated with transferring KSM tokens -fn ksm_fee() -> Balance { - calc_fee(ksm_per_second()) -} - -fn calc_fee(fee_per_second: Balance) -> Balance { - // We divide the fee to align its unit and multiply by 4 as that seems to be the - // unit of time the tests take. - // NOTE: it is possible that in different machines this value may differ. We - // shall see. - fee_per_second.div_euclid(10_000) * 8 -} diff --git a/runtime/integration-tests/src/utils/env.rs b/runtime/integration-tests/src/utils/env.rs index ce93f1a58d..738011bf65 100644 --- a/runtime/integration-tests/src/utils/env.rs +++ b/runtime/integration-tests/src/utils/env.rs @@ -775,6 +775,8 @@ fn test_env( // Build relay-chain builder let relay = { sp_tracing::enter_span!(sp_tracing::Level::INFO, "Relay - StartUp"); + + //TODO(cdamian): Use RelayBlock let mut state = StateProvider::, centrifuge::Block>::empty_default( Some(RelayCode.expect("Wasm is build. Qed.")),